diff --git a/DEPS b/DEPS
index b9d3372..a88bb82 100644
--- a/DEPS
+++ b/DEPS
@@ -129,11 +129,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '5155e09d146665be078494247092fa990d5ae4a7',
+  'skia_revision': '5b39dc81534a2c30d5788de9b8a6501b23e96fdf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'fd3e5e3a30df06b3f5ef428dab42c3d625ef2c0b',
+  'v8_revision': '35b9bf5cf697b1c0fe4313c1313782d626d2afaa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -141,7 +141,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3b2c6bfd43536cf9ceca5d1303aa9435e67a432b',
+  'angle_revision': 'e3c7134c2717443e925adf37ed6de21eb0187cf2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -264,7 +264,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '59a49bc5cdff252c6e56e2176255398ace226a90',
+  'shaderc_revision': '60caf55788c69dbaebe78c03031d8d1d605988cd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -805,7 +805,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e72d09e780cedba24bdb63637f9be30a0ba6af7e',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5a01970efa3a0c5726a303d9cd901ae0d6a144b2',
       'condition': 'checkout_linux',
   },
 
@@ -1183,7 +1183,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '084712c40e18337cd48e6f5866baf43121e1e2c6',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '3d46e0d12b172526482d343a6d1a25a9a061af35',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1354,7 +1354,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3f6583d3fee4ab71866ade794504a20eb6f63f88',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '011d3a125e15e38111b2e21e5b089578c8514466',
+    Var('webrtc_git') + '/src.git' + '@' + 'e0ab81c8c6e570081c2e1fda2e2c0b84f92c7d77',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1395,7 +1395,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@db8bc8a9d46ca921d84554b29a952e8305e08390',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8d6e1e0bfd92a236493718d477376d2ef3fa6c48',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/docs/commandline-flags.md b/android_webview/docs/commandline-flags.md
index 4b59123..94d0e67 100644
--- a/android_webview/docs/commandline-flags.md
+++ b/android_webview/docs/commandline-flags.md
@@ -12,29 +12,38 @@
 to the file with:
 
 ```sh
-$ # Overwrites all flags (and prints the new flag state):
-$ build/android/adb_system_webview_command_line \
+# Overwrite flags (supports multiple)
+build/android/adb_system_webview_command_line \
     --show-composited-layer-borders \
-    --log-net-log=foo.json # Supports multiple flags
-$ # Simply prints the existing flag state:
-$ build/android/adb_system_webview_command_line
-$ # Passing empty string clears all flags:
-$ build/android/adb_system_webview_command_line ""
+    --log-net-log=foo.json
+# Clear flags
+build/android/adb_system_webview_command_line ""
+# Print flags
+build/android/adb_system_webview_command_line
+```
+
+Or, for a locally compiled APK:
+
+```sh
+autoninja -C out/Default system_webview_apk
+# Overwrite flags (supports multiple)
+out/Default/bin/system_webview_apk argv --args='--show-composited-layer-borders --log-net-log=foo.json'
+# Clear flags
+out/Default/bin/system_webview_apk argv --args=''
+# Print flags
+out/Default/bin/system_webview_apk argv
 ```
 
 Or, you can use the `adb` in your `$PATH` like so:
 
 ```sh
-$ FLAG_FILE=/data/local/tmp/webview-command-line
-$ adb shell "echo '_ --show-composited-layer-borders' > ${FLAG_FILE}"
-$ # The first token is ignored. We use '_' as a convenient placeholder, but any
-$ # token is acceptable.
+FLAG_FILE=/data/local/tmp/webview-command-line
+# Overwrite flags
+adb shell "echo '_ --show-composited-layer-borders' > ${FLAG_FILE}"
+# The first token is ignored. We use '_' as a convenient placeholder, but any
+# token is acceptable.
 ```
 
-*** note
-**Note:** either set of commands will overwrite existing flags.
-***
-
 ### Applying Features with flags
 
 WebView supports the same `--enable-features=feature1,feature2` and
diff --git a/android_webview/docs/net-debugging.md b/android_webview/docs/net-debugging.md
index 2de1b88..b0f906f 100644
--- a/android_webview/docs/net-debugging.md
+++ b/android_webview/docs/net-debugging.md
@@ -16,6 +16,30 @@
 production builds of Android.
 ***
 
+```shell
+# Optional: set any flags of your choosing before running the script
+$ build/android/adb_system_webview_command_line --enable-features=NetworkService,NetworkServiceInProcess
+Wrote command line file. Current flags (in webview-command-line):
+  005d1ac915b0c7d6 (bullhead-userdebug 6.0 MDB08M 2353240 dev-keys): --enable-features=NetworkService,NetworkServiceInProcess
+
+# Replace "<app package name>" with your app's package name (ex. the
+# WebView Shell is "org.chromium.webview_shell")
+$ android_webview/tools/record_netlog.py --package="<app package name>"
+Running with flags ['--enable-features=NetworkService,NetworkServiceInProcess', '--log-net-log=netlog.json']
+Netlog will start recording as soon as app starts up. Press ctrl-C to stop recording.
+^C
+Pulling netlog to "netlog.json"
+```
+
+Then import the JSON file into [the NetLog
+viewer](https://chromium.googlesource.com/catapult/+/master/netlog_viewer/).
+
+For more details, see the implementation in
+[AwUrlRequestContextGetter](/android_webview/browser/net/aw_url_request_context_getter.cc).
+For support in the network service code path, see http://crbug.com/902039.
+
+### Manual steps
+
 1. Figure out the app's data directory
    ```sh
    # appPackageName is the package name of whatever app you're interested (ex.
@@ -38,9 +62,4 @@
    ```sh
    adb pull "${appDataDir}/app_webview/${jsonFile}"
    ```
-1. Import the JSON file into [the NetLog
-   viewer](https://chromium.googlesource.com/catapult/+/master/netlog_viewer/)
-
-For more details, see the implementation in
-[AwUrlRequestContextGetter](/android_webview/browser/net/aw_url_request_context_getter.cc).
-For support in the network service code path, see http://crbug.com/902039.
+ 1. Follow the step above for using the Netlog viewer
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
index 6f4f333..3057d79 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
@@ -36,35 +36,28 @@
     public void
     testModeBrowser() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode(
-                "browser", false, "native-include-thread-names", true, false, false));
+        Assert.assertTrue(
+                shim.runTestForMode("browser", false, "native-include-thread-names", false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSampleEverything() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, true));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSamplePartial() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, false));
-    }
-
-    @Test
-    @MediumTest
-    public void testModeBrowserDynamicPseudoSamplePartialNonStreaming() throws Exception {
-        HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, true, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false));
     }
 }
diff --git a/android_webview/tools/record_netlog.py b/android_webview/tools/record_netlog.py
new file mode 100755
index 0000000..559c9fa
--- /dev/null
+++ b/android_webview/tools/record_netlog.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# Copyright 2019 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.
+"""Takes a netlog for the WebViews in a given application.
+
+Developer guide:
+https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/net-debugging.md
+"""
+
+from __future__ import print_function
+
+import argparse
+import logging
+import os
+import re
+import sys
+import time
+
+sys.path.append(
+    os.path.join(
+        os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
+import devil_chromium  # pylint: disable=import-error
+from devil.android import device_errors  # pylint: disable=import-error
+from devil.android import flag_changer  # pylint: disable=import-error
+from devil.android import device_utils  # pylint: disable=import-error
+from devil.android.tools import script_common  # pylint: disable=import-error
+from devil.utils import logging_common  # pylint: disable=import-error
+
+WEBVIEW_COMMAND_LINE = 'webview-command-line'
+
+
+def _WaitUntilCtrlC():
+  try:
+    while True:
+      time.sleep(1)
+  except KeyboardInterrupt:
+    print()  # print a new line after the "^C" the user typed to the console
+
+
+# TODO(ntfschr): upstream this into devil, since we can avoid a read+write to
+# improve performance.
+def _PullFileWithRoot(device, device_path, host_path):
+  dirname = os.path.dirname(host_path)
+  if dirname and not os.path.exists(dirname):
+    os.makedirs(dirname)
+  with open(host_path, 'w') as f:
+    contents = device.ReadFile(device_path, as_root=True)
+    f.write(contents)
+
+
+def CheckAppNotRunning(device, package_name, force):
+  processes = device.ListProcesses(package_name)
+  if processes:
+    msg = ('Netlog requires setting commandline flags, which only works if the '
+           'application ({}) is not already running. Please kill the app and '
+           'restart the script.'.format(
+               package_name))
+    if force:
+      logging.warning(msg)
+    else:
+      # Extend the sentence to mention the user can skip the check.
+      msg = re.sub(r'\.$', ', or pass --force to ignore this check.', msg)
+      raise RuntimeError(msg)
+
+
+def main():
+  parser = argparse.ArgumentParser(description="""
+Configures WebView to start recording a netlog. This script chooses a suitable
+netlog filename for the application, and will pull the netlog off the device
+when the user terminates the script (with ctrl-C). For a more complete usage
+guide, open your web browser to:
+https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/net-debugging.md
+""")
+  parser.add_argument(
+      '--package',
+      required=True,
+      type=str,
+      help='Package name of the application you intend to use.')
+  parser.add_argument(
+      '--force',
+      default=False,
+      action='store_true',
+      help='Suppress user checks.')
+
+  script_common.AddEnvironmentArguments(parser)
+  script_common.AddDeviceArguments(parser)
+  logging_common.AddLoggingArguments(parser)
+
+  args = parser.parse_args()
+  logging_common.InitializeLogging(args)
+  devil_chromium.Initialize()
+  script_common.InitializeEnvironment(args)
+
+  # Only use a single device, for the sake of simplicity (of implementation and
+  # user experience).
+  devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices)
+  device = devices[0]
+  if len(devices) > 1:
+    raise device_errors.MultipleDevicesError(devices)
+
+  package_name = args.package
+  device_netlog_file_name = 'netlog.json'
+  device_netlog_path = os.path.join(
+      device.GetApplicationDataDirectory(package_name), 'app_webview',
+      device_netlog_file_name)
+
+  CheckAppNotRunning(device, package_name, args.force)
+
+  # Append to the existing flags, to allow users to experiment with other
+  # features/flags enabled. The CustomCommandLineFlags will restore the original
+  # flag state after the user presses 'ctrl-C'.
+  changer = flag_changer.FlagChanger(device, WEBVIEW_COMMAND_LINE)
+  new_flags = changer.GetCurrentFlags()
+  new_flags.append('--log-net-log={}'.format(device_netlog_path))
+
+  logging.info('Running with flags %r', new_flags)
+  with flag_changer.CustomCommandLineFlags(device, WEBVIEW_COMMAND_LINE,
+                                           new_flags):
+    print('Netlog will start recording as soon as app starts up. Press ctrl-C '
+          'to stop recording.')
+    _WaitUntilCtrlC()
+
+  host_netlog_path = 'netlog.json'
+  print('Pulling netlog to "%s"' % host_netlog_path)
+  # The netlog file will be under the app's uid, which the default shell doesn't
+  # have permission to read (but root does). Prefer this to EnableRoot(), which
+  # restarts the adb daemon.
+  _PullFileWithRoot(device, device_netlog_path, host_netlog_path)
+  device.RemovePath(device_netlog_path, as_root=True)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 05d2da1..24d9588 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -192,10 +192,13 @@
 
   ~StateAnimationMetricsReporter() override = default;
 
-  void Start(bool is_in_tablet_mode) {
-    DCHECK(!started_);
-    is_in_tablet_mode_ = is_in_tablet_mode;
+  void SetTargetState(ash::mojom::AppListViewState target_state) {
+    target_state_ = target_state;
+  }
+
+  void Start() {
 #if defined(DCHECK)
+    DCHECK(!started_);
     started_ = ui::ScopedAnimationDurationScaleMode::duration_scale_mode() !=
                ui::ScopedAnimationDurationScaleMode::ZERO_DURATION;
 #endif
@@ -203,13 +206,36 @@
 
   void Report(int value) override {
     UMA_HISTOGRAM_PERCENTAGE("Apps.StateTransition.AnimationSmoothness", value);
-    if (is_in_tablet_mode_) {
-      UMA_HISTOGRAM_PERCENTAGE(
-          "Apps.StateTransition.AnimationSmoothness.TabletMode", value);
-    } else {
-      UMA_HISTOGRAM_PERCENTAGE(
-          "Apps.StateTransition.AnimationSmoothness.ClamshellMode", value);
+    switch (*target_state_) {
+      case ash::mojom::AppListViewState::kClosed:
+        UMA_HISTOGRAM_PERCENTAGE(
+            "Apps.StateTransition.AnimationSmoothness.Close.ClamshellMode",
+            value);
+        break;
+      case ash::mojom::AppListViewState::kPeeking:
+        UMA_HISTOGRAM_PERCENTAGE(
+            "Apps.StateTransition.AnimationSmoothness.Peeking.ClamshellMode",
+            value);
+        break;
+      case ash::mojom::AppListViewState::kHalf:
+        UMA_HISTOGRAM_PERCENTAGE(
+            "Apps.StateTransition.AnimationSmoothness.Half.ClamshellMode",
+            value);
+        break;
+      case ash::mojom::AppListViewState::kFullscreenAllApps:
+        UMA_HISTOGRAM_PERCENTAGE(
+            "Apps.StateTransition.AnimationSmoothness.FullscreenAllApps."
+            "ClamshellMode",
+            value);
+        break;
+      case ash::mojom::AppListViewState::kFullscreenSearch:
+        UMA_HISTOGRAM_PERCENTAGE(
+            "Apps.StateTransition.AnimationSmoothness.FullscreenSearch."
+            "ClamshellMode",
+            value);
+        break;
     }
+    target_state_.reset();
     view_->OnStateTransitionAnimationCompleted();
 #if defined(DCHECK)
     started_ = false;
@@ -220,7 +246,7 @@
 #if defined(DCHECK)
   bool started_ = false;
 #endif
-  bool is_in_tablet_mode_ = false;
+  base::Optional<ash::mojom::AppListViewState> target_state_;
   AppListView* view_;
 
   DISALLOW_COPY_AND_ASSIGN(StateAnimationMetricsReporter);
@@ -1370,6 +1396,7 @@
   settings.SetTweenType(gfx::Tween::EASE_OUT);
   settings.SetPreemptionStrategy(
       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+  state_animation_metrics_reporter_->SetTargetState(target_state);
   settings.SetAnimationMetricsReporter(state_animation_metrics_reporter_.get());
   settings.AddObserver(transition_animation_observer_.get());
 
@@ -1392,6 +1419,8 @@
     animation_duration /= 2;
   }
 
+  state_animation_metrics_reporter_->SetTargetState(
+      ash::mojom::AppListViewState::kClosed);
   SetState(ash::mojom::AppListViewState::kClosed);
   app_list_main_view_->contents_view()->FadeOutOnClose(animation_duration);
 }
@@ -1606,7 +1635,7 @@
 }
 
 ui::AnimationMetricsReporter* AppListView::GetStateTransitionMetricsReporter() {
-  state_animation_metrics_reporter_->Start(is_tablet_mode_);
+  state_animation_metrics_reporter_->Start();
   return state_animation_metrics_reporter_.get();
 }
 
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index 9a5e9bb4..5e06c60 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -51,7 +51,7 @@
 constexpr SkColor kDividerBackgroundColor = SK_ColorBLACK;
 constexpr SkColor kWhiteBarBackgroundColor = SK_ColorWHITE;
 constexpr int kDividerBoundsChangeDurationMs = 250;
-constexpr int kWhiteBarBoundsChangeDurationMs = 150;
+constexpr int kWhiteBarBoundsChangeDurationMs = 250;
 
 // The distance to the divider edge in which a touch gesture will be considered
 // as a valid event on the divider.
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index 0693776..054853d9 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -124,6 +124,25 @@
   return ToJavaFloatArray(env, floats.data(), floats.size());
 }
 
+BASE_EXPORT ScopedJavaLocalRef<jdoubleArray>
+ToJavaDoubleArray(JNIEnv* env, const double* doubles, size_t len) {
+  jdoubleArray double_array = env->NewDoubleArray(len);
+  CheckException(env);
+  DCHECK(double_array);
+
+  env->SetDoubleArrayRegion(double_array, 0, len,
+                            reinterpret_cast<const jdouble*>(doubles));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jdoubleArray>(env, double_array);
+}
+
+BASE_EXPORT ScopedJavaLocalRef<jdoubleArray> ToJavaDoubleArray(
+    JNIEnv* env,
+    const std::vector<double>& doubles) {
+  return ToJavaDoubleArray(env, doubles.data(), doubles.size());
+}
+
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
     JNIEnv* env, const std::vector<std::string>& v) {
   ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
index c5a1c03..917f1d0 100644
--- a/base/android/jni_array.h
+++ b/base/android/jni_array.h
@@ -60,6 +60,14 @@
     JNIEnv* env,
     const std::vector<float>& floats);
 
+// Returns a new Java double array converted from the given C++ double array.
+BASE_EXPORT ScopedJavaLocalRef<jdoubleArray>
+ToJavaDoubleArray(JNIEnv* env, const double* doubles, size_t len);
+
+BASE_EXPORT ScopedJavaLocalRef<jdoubleArray> ToJavaDoubleArray(
+    JNIEnv* env,
+    const std::vector<double>& doubles);
+
 // Returns a array of Java byte array converted from |v|.
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
     JNIEnv* env, const std::vector<std::string>& v);
diff --git a/base/profiler/native_unwinder_mac.cc b/base/profiler/native_unwinder_mac.cc
index 0bd145c..8c6b18e 100644
--- a/base/profiler/native_unwinder_mac.cc
+++ b/base/profiler/native_unwinder_mac.cc
@@ -131,7 +131,7 @@
 }
 
 bool NativeUnwinderMac::CanUnwindFrom(const Frame* current_frame) const {
-  return current_frame->module;
+  return current_frame->module && current_frame->module->IsNative();
 }
 
 UnwindResult NativeUnwinderMac::TryUnwind(x86_thread_state64_t* thread_context,
@@ -222,10 +222,13 @@
     // libunwind adds the expected stack size, it will look for the return
     // address in the wrong place. This check ensures we don't continue trying
     // to unwind using the resulting bad IP value.
-    //
-    // We return UNRECOGNIZED_FRAME on the optimistic assumption that this may
-    // be a frame the AuxUnwinder knows how to handle (e.g. a frame in V8
-    // generated code).
+    return UnwindResult::ABORTED;
+  }
+
+  if (!current_frame->module->IsNative()) {
+    // This is a non-native module associated with the auxiliary unwinder
+    // (e.g. corresponding to a frame in V8 generated code). Report as
+    // UNRECOGNIZED_FRAME to allow that unwinder to unwind the frame.
     return UnwindResult::UNRECOGNIZED_FRAME;
   }
 
diff --git a/base/profiler/native_unwinder_win.cc b/base/profiler/native_unwinder_win.cc
index 47f6309..bd93438 100644
--- a/base/profiler/native_unwinder_win.cc
+++ b/base/profiler/native_unwinder_win.cc
@@ -10,7 +10,7 @@
 namespace base {
 
 bool NativeUnwinderWin::CanUnwindFrom(const Frame* current_frame) const {
-  return current_frame->module;
+  return current_frame->module && current_frame->module->IsNative();
 }
 
 // Attempts to unwind the frame represented by the context values. If
@@ -28,22 +28,24 @@
   for (;;) {
     if (!stack->back().module) {
       // There's no loaded module corresponding to the current frame. This can
-      // be due to executing code that is not in a module (e.g. V8 generated
-      // code or runtime-generated code associated with third-party injected
-      // DLLs). It can also be due to the the module having been unloaded since
-      // we recorded the stack.  In the latter case the function unwind
-      // information was part of the unloaded module, so it's not possible to
-      // unwind further.
+      // be due to executing code not in a module (e.g. runtime-generated code
+      // associated with third-party injected DLLs) or the module having been
+      // unloaded since we recorded the stack. In the latter case the function
+      // unwind information was part of the unloaded module, so it's not
+      // possible to unwind further.
       //
-      // If a module was found, it's still theoretically possible for the
+      // NB: if a module was found it's still theoretically possible for the
       // detected module module to be different than the one that was loaded
-      // when the stack was copied (i.e. if the module was unloaded and a
-      // different module loaded in overlapping memory). This likely would cause
-      // a crash, but has not been observed in practice.
-      //
-      // We return UNRECOGNIZED_FRAME on the optimistic assumption that this may
-      // be a frame the AuxUnwinder knows how to handle (e.g. a frame in V8
-      // generated code).
+      // when the stack was copied, if the module was unloaded and a different
+      // module loaded in overlapping memory. This likely would cause a crash
+      // but has not been observed in practice.
+      return UnwindResult::ABORTED;
+    }
+
+    if (!stack->back().module->IsNative()) {
+      // This is a non-native module associated with the auxiliary unwinder
+      // (e.g. corresponding to a frame in V8 generated code). Report as
+      // UNRECOGNIZED_FRAME to allow that unwinder to unwind the frame.
       return UnwindResult::UNRECOGNIZED_FRAME;
     }
 
diff --git a/base/profiler/register_context.h b/base/profiler/register_context.h
index 7c7dfd8..9c6eaf1 100644
--- a/base/profiler/register_context.h
+++ b/base/profiler/register_context.h
@@ -19,6 +19,8 @@
 #include <mach/machine/thread_status.h>
 #endif
 
+namespace base {
+
 // Helper function to account for the fact that platform-specific register state
 // types may be unsigned and of the same size as uintptr_t, but not of the same
 // type -- e.g. unsigned int vs. unsigned long on 32-bit Windows and unsigned
@@ -104,4 +106,6 @@
 
 #endif  // #if defined(OS_WIN)
 
+}  // namespace base
+
 #endif  // BASE_PROFILER_REGISTER_CONTEXT_H_
diff --git a/base/profiler/stack_sampler_impl.cc b/base/profiler/stack_sampler_impl.cc
index fffb59a1..0b808fba 100644
--- a/base/profiler/stack_sampler_impl.cc
+++ b/base/profiler/stack_sampler_impl.cc
@@ -87,6 +87,7 @@
 
 void StackSamplerImpl::AddAuxUnwinder(Unwinder* unwinder) {
   aux_unwinder_ = unwinder;
+  aux_unwinder_->AddNonNativeModules(module_cache_);
 }
 
 void StackSamplerImpl::RecordStackFrames(StackBuffer* stack_buffer,
@@ -103,7 +104,20 @@
   if (test_delegate_)
     test_delegate_->OnPreStackWalk();
 
-  profile_builder->OnSampleCompleted(WalkStack(&thread_context, stack_top));
+  profile_builder->OnSampleCompleted(
+      WalkStack(module_cache_, &thread_context, stack_top,
+                native_unwinder_.get(), aux_unwinder_));
+}
+// static
+
+std::vector<Frame> StackSamplerImpl::WalkStackForTesting(
+    ModuleCache* module_cache,
+    RegisterContext* thread_context,
+    uintptr_t stack_top,
+    Unwinder* native_unwinder,
+    Unwinder* aux_unwinder) {
+  return WalkStack(module_cache, thread_context, stack_top, native_unwinder,
+                   aux_unwinder);
 }
 
 // Suspends the thread, copies its stack, top address of the stack copy, and
@@ -160,10 +174,12 @@
   return true;
 }
 
-// Walks the stack represented by |thread_context|, recording and returning the
-// frames.
-std::vector<Frame> StackSamplerImpl::WalkStack(RegisterContext* thread_context,
-                                               uintptr_t stack_top) {
+// static
+std::vector<Frame> StackSamplerImpl::WalkStack(ModuleCache* module_cache,
+                                               RegisterContext* thread_context,
+                                               uintptr_t stack_top,
+                                               Unwinder* native_unwinder,
+                                               Unwinder* aux_unwinder) {
   std::vector<Frame> stack;
   // Reserve enough memory for most stacks, to avoid repeated
   // allocations. Approximately 99.9% of recorded stacks are 128 frames or
@@ -172,10 +188,32 @@
 
   // Record the first frame from the context values.
   stack.emplace_back(RegisterContextInstructionPointer(thread_context),
-                     module_cache_->GetModuleForAddress(
+                     module_cache->GetModuleForAddress(
                          RegisterContextInstructionPointer(thread_context)));
 
-  native_unwinder_->TryUnwind(thread_context, stack_top, module_cache_, &stack);
+  size_t prior_stack_size;
+  UnwindResult result;
+  do {
+    // Choose an authoritative unwinder for the current module. Use the aux
+    // unwinder if it thinks it can unwind from the current frame, otherwise use
+    // the native unwinder.
+    Unwinder* unwinder =
+        aux_unwinder && aux_unwinder->CanUnwindFrom(&stack.back())
+            ? aux_unwinder
+            : native_unwinder;
+
+    prior_stack_size = stack.size();
+    result =
+        unwinder->TryUnwind(thread_context, stack_top, module_cache, &stack);
+
+    // The native unwinder should be the only one that returns COMPLETED
+    // since the stack starts in native code.
+    DCHECK(result != UnwindResult::COMPLETED || unwinder == native_unwinder);
+  } while (result != UnwindResult::ABORTED &&
+           result != UnwindResult::COMPLETED &&
+           // Give up if the authoritative unwinder for the module was unable to
+           // unwind.
+           stack.size() > prior_stack_size);
 
   return stack;
 }
diff --git a/base/profiler/stack_sampler_impl.h b/base/profiler/stack_sampler_impl.h
index d7aaac1..8b73e0d 100644
--- a/base/profiler/stack_sampler_impl.h
+++ b/base/profiler/stack_sampler_impl.h
@@ -35,14 +35,24 @@
   void RecordStackFrames(StackBuffer* stack_buffer,
                          ProfileBuilder* profile_builder) override;
 
+  // Exposes the internal function for unit testing.
+  static std::vector<Frame> WalkStackForTesting(ModuleCache* module_cache,
+                                                RegisterContext* thread_context,
+                                                uintptr_t stack_top,
+                                                Unwinder* native_unwinder,
+                                                Unwinder* aux_unwinder);
+
  private:
   bool CopyStack(StackBuffer* stack_buffer,
                  uintptr_t* stack_top,
                  ProfileBuilder* profile_builder,
                  RegisterContext* thread_context);
 
-  std::vector<Frame> WalkStack(RegisterContext* thread_context,
-                               uintptr_t stack_top);
+  static std::vector<Frame> WalkStack(ModuleCache* module_cache,
+                                      RegisterContext* thread_context,
+                                      uintptr_t stack_top,
+                                      Unwinder* native_unwinder,
+                                      Unwinder* aux_unwinder);
 
   const std::unique_ptr<ThreadDelegate> thread_delegate_;
   const std::unique_ptr<Unwinder> native_unwinder_;
diff --git a/base/profiler/stack_sampler_impl_unittest.cc b/base/profiler/stack_sampler_impl_unittest.cc
index 130eaff..86aac6a 100644
--- a/base/profiler/stack_sampler_impl_unittest.cc
+++ b/base/profiler/stack_sampler_impl_unittest.cc
@@ -134,18 +134,19 @@
 
 class TestModule : public ModuleCache::Module {
  public:
-  TestModule(uintptr_t base_address, size_t size)
-      : base_address_(base_address), size_(size) {}
+  TestModule(uintptr_t base_address, size_t size, bool is_native = true)
+      : base_address_(base_address), size_(size), is_native_(is_native) {}
 
   uintptr_t GetBaseAddress() const override { return base_address_; }
   std::string GetId() const override { return ""; }
   FilePath GetDebugBasename() const override { return FilePath(); }
   size_t GetSize() const override { return size_; }
-  bool IsNative() const override { return true; }
+  bool IsNative() const override { return is_native_; }
 
  private:
   const uintptr_t base_address_;
   const size_t size_;
+  const bool is_native_;
 };
 
 // Injects a fake module covering the initial instruction pointer value, to
@@ -158,6 +159,70 @@
       std::make_unique<TestModule>(stack[0], sizeof(uintptr_t)));
 }
 
+// Returns a plausible instruction pointer value for use in tests that don't
+// care about the instruction pointer value in the context, and hence don't need
+// InjectModuleForContextInstructionPointer().
+uintptr_t GetTestInstructionPointer() {
+  return reinterpret_cast<uintptr_t>(&GetTestInstructionPointer);
+}
+
+// An unwinder fake that replays the provided outputs.
+class FakeTestUnwinder : public Unwinder {
+ public:
+  struct Result {
+    Result(bool can_unwind)
+        : can_unwind(can_unwind), result(UnwindResult::UNRECOGNIZED_FRAME) {}
+
+    Result(UnwindResult result, std::vector<uintptr_t> instruction_pointers)
+        : can_unwind(true),
+          result(result),
+          instruction_pointers(instruction_pointers) {}
+
+    bool can_unwind;
+    UnwindResult result;
+    std::vector<uintptr_t> instruction_pointers;
+  };
+
+  // Construct the unwinder with the outputs. The relevant unwinder functions
+  // are expected to be invoked at least as many times as the number of values
+  // specified in the arrays (except for CanUnwindFrom() which will always
+  // return true if provided an empty array.
+  explicit FakeTestUnwinder(std::vector<Result> results)
+      : results_(std::move(results)) {}
+
+  FakeTestUnwinder(const FakeTestUnwinder&) = delete;
+  FakeTestUnwinder& operator=(const FakeTestUnwinder&) = delete;
+
+  bool CanUnwindFrom(const Frame* current_frame) const override {
+    bool can_unwind = results_[current_unwind_].can_unwind;
+    // NB: If CanUnwindFrom() returns false then TryUnwind() will not be
+    // invoked, so current_unwind_ is guarantee to be incremented only once for
+    // each result.
+    if (!can_unwind)
+      ++current_unwind_;
+    return can_unwind;
+  }
+
+  UnwindResult TryUnwind(RegisterContext* thread_context,
+                         uintptr_t stack_top,
+                         ModuleCache* module_cache,
+                         std::vector<Frame>* stack) const override {
+    CHECK_LT(current_unwind_, results_.size());
+    const Result& current_result = results_[current_unwind_];
+    ++current_unwind_;
+    CHECK(current_result.can_unwind);
+    for (const auto instruction_pointer : current_result.instruction_pointers)
+      stack->emplace_back(
+          instruction_pointer,
+          module_cache->GetModuleForAddress(instruction_pointer));
+    return current_result.result;
+  }
+
+ private:
+  mutable size_t current_unwind_ = 0;
+  std::vector<Result> results_;
+};
+
 }  // namespace
 
 TEST(StackSamplerImplTest, CopyStack) {
@@ -250,4 +315,120 @@
             RegisterContextFramePointer(&thread_context));
 }
 
+TEST(StackSamplerImplTest, WalkStack_Completed) {
+  ModuleCache module_cache;
+  RegisterContext thread_context;
+  RegisterContextInstructionPointer(&thread_context) =
+      GetTestInstructionPointer();
+  module_cache.InjectModuleForTesting(std::make_unique<TestModule>(1u, 1u));
+  FakeTestUnwinder native_unwinder({{UnwindResult::COMPLETED, {1u}}});
+
+  std::vector<Frame> stack = StackSamplerImpl::WalkStackForTesting(
+      &module_cache, &thread_context, 0u, &native_unwinder, nullptr);
+
+  ASSERT_EQ(2u, stack.size());
+  EXPECT_EQ(1u, stack[1].instruction_pointer);
+}
+
+TEST(StackSamplerImplTest, WalkStack_Aborted) {
+  ModuleCache module_cache;
+  RegisterContext thread_context;
+  RegisterContextInstructionPointer(&thread_context) =
+      GetTestInstructionPointer();
+  module_cache.InjectModuleForTesting(std::make_unique<TestModule>(1u, 1u));
+  FakeTestUnwinder native_unwinder({{UnwindResult::ABORTED, {1u}}});
+
+  std::vector<Frame> stack = StackSamplerImpl::WalkStackForTesting(
+      &module_cache, &thread_context, 0u, &native_unwinder, nullptr);
+
+  ASSERT_EQ(2u, stack.size());
+  EXPECT_EQ(1u, stack[1].instruction_pointer);
+}
+
+TEST(StackSamplerImplTest, WalkStack_NotUnwound) {
+  ModuleCache module_cache;
+  RegisterContext thread_context;
+  RegisterContextInstructionPointer(&thread_context) =
+      GetTestInstructionPointer();
+  FakeTestUnwinder native_unwinder({{UnwindResult::UNRECOGNIZED_FRAME, {}}});
+
+  std::vector<Frame> stack = StackSamplerImpl::WalkStackForTesting(
+      &module_cache, &thread_context, 0u, &native_unwinder, nullptr);
+
+  ASSERT_EQ(1u, stack.size());
+}
+
+TEST(StackSamplerImplTest, WalkStack_AuxUnwind) {
+  ModuleCache module_cache;
+  RegisterContext thread_context;
+  RegisterContextInstructionPointer(&thread_context) =
+      GetTestInstructionPointer();
+
+  // Treat the context instruction pointer as being in the aux unwinder's
+  // non-native module.
+  module_cache.AddNonNativeModule(
+      std::make_unique<TestModule>(GetTestInstructionPointer(), 1u, false));
+
+  FakeTestUnwinder aux_unwinder({{UnwindResult::ABORTED, {1u}}});
+
+  std::vector<Frame> stack = StackSamplerImpl::WalkStackForTesting(
+      &module_cache, &thread_context, 0u, nullptr, &aux_unwinder);
+
+  ASSERT_EQ(2u, stack.size());
+  EXPECT_EQ(GetTestInstructionPointer(), stack[0].instruction_pointer);
+  EXPECT_EQ(1u, stack[1].instruction_pointer);
+}
+
+TEST(StackSamplerImplTest, WalkStack_AuxThenNative) {
+  ModuleCache module_cache;
+  RegisterContext thread_context;
+  RegisterContextInstructionPointer(&thread_context) = 0u;
+
+  // Treat the context instruction pointer as being in the aux unwinder's
+  // non-native module.
+  module_cache.AddNonNativeModule(std::make_unique<TestModule>(0u, 1u, false));
+  // Inject a fake native module for the second frame.
+  module_cache.InjectModuleForTesting(std::make_unique<TestModule>(1u, 1u));
+
+  FakeTestUnwinder aux_unwinder(
+      {{{UnwindResult::UNRECOGNIZED_FRAME, {1u}}, {false}}});
+  FakeTestUnwinder native_unwinder({{UnwindResult::COMPLETED, {2u}}});
+
+  std::vector<Frame> stack = StackSamplerImpl::WalkStackForTesting(
+      &module_cache, &thread_context, 0u, &native_unwinder, &aux_unwinder);
+
+  ASSERT_EQ(3u, stack.size());
+  EXPECT_EQ(0u, stack[0].instruction_pointer);
+  EXPECT_EQ(1u, stack[1].instruction_pointer);
+  EXPECT_EQ(2u, stack[2].instruction_pointer);
+}
+
+TEST(StackSamplerImplTest, WalkStack_NativeThenAux) {
+  ModuleCache module_cache;
+  RegisterContext thread_context;
+  RegisterContextInstructionPointer(&thread_context) = 0u;
+
+  // Inject fake native modules for the instruction pointer from the context and
+  // the third frame.
+  module_cache.InjectModuleForTesting(std::make_unique<TestModule>(0u, 1u));
+  module_cache.InjectModuleForTesting(std::make_unique<TestModule>(2u, 1u));
+  // Treat the second frame's pointer as being in the aux unwinder's non-native
+  // module.
+  module_cache.AddNonNativeModule(std::make_unique<TestModule>(1u, 1u, false));
+
+  FakeTestUnwinder aux_unwinder(
+      {{false}, {UnwindResult::UNRECOGNIZED_FRAME, {2u}}, {false}});
+  FakeTestUnwinder native_unwinder({{UnwindResult::UNRECOGNIZED_FRAME, {1u}},
+                                    {UnwindResult::COMPLETED, {3u}}});
+
+  std::vector<Frame> stack = StackSamplerImpl::WalkStackForTesting(
+      &module_cache, &thread_context, 0u, &native_unwinder, &aux_unwinder);
+
+  ASSERT_EQ(4u, stack.size());
+  EXPECT_EQ(0u, stack[0].instruction_pointer);
+  EXPECT_EQ(1u, stack[1].instruction_pointer);
+  EXPECT_EQ(2u, stack[2].instruction_pointer);
+  EXPECT_EQ(3u, stack[3].instruction_pointer);
+}
+
 }  // namespace base
diff --git a/base/profiler/unwinder.h b/base/profiler/unwinder.h
index 09b3efa..7ffc1ff 100644
--- a/base/profiler/unwinder.h
+++ b/base/profiler/unwinder.h
@@ -37,6 +37,10 @@
  public:
   virtual ~Unwinder() = default;
 
+  // Invoked to allow the unwinder to add any non-native modules it recognizes
+  // to the ModuleCache.
+  virtual void AddNonNativeModules(ModuleCache* module_cache) {}
+
   // Returns true if the unwinder recognizes the code referenced by
   // |current_frame| as code from which it should be able to unwind. When
   // multiple unwinders are in use, each should return true for a disjoint set
diff --git a/base/sampling_heap_profiler/poisson_allocation_sampler.h b/base/sampling_heap_profiler/poisson_allocation_sampler.h
index 79d2a4b..7709e02 100644
--- a/base/sampling_heap_profiler/poisson_allocation_sampler.h
+++ b/base/sampling_heap_profiler/poisson_allocation_sampler.h
@@ -33,7 +33,7 @@
 //
 class BASE_EXPORT PoissonAllocationSampler {
  public:
-  enum AllocatorType : uint32_t { kMalloc, kPartitionAlloc, kBlinkGC, kMax };
+  enum AllocatorType : uint32_t { kMalloc, kPartitionAlloc, kBlinkGC };
 
   // When the sampler is just enabled it needs to see up to that amount
   // of allocation sizes before it starts recording samples.
diff --git a/base/task/sequence_manager/work_queue_unittest.cc b/base/task/sequence_manager/work_queue_unittest.cc
index ccf6822..5dba2b5 100644
--- a/base/task/sequence_manager/work_queue_unittest.cc
+++ b/base/task/sequence_manager/work_queue_unittest.cc
@@ -8,10 +8,13 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/task/sequence_manager/lazy_now.h"
 #include "base/task/sequence_manager/real_time_domain.h"
-#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/sequence_manager.h"
 #include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/task/sequence_manager/work_queue_sets.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace base {
@@ -35,19 +38,22 @@
   WeakPtrFactory<Cancelable> weak_ptr_factory;
 };
 
+class RealTimeDomainFake : public RealTimeDomain {
+ public:
+  LazyNow CreateLazyNow() const override {
+    return LazyNow(DefaultTickClock::GetInstance());
+  }
+
+  TimeTicks Now() const override { return TimeTicks::Now(); }
+};
+
 }  // namespace
 
 class WorkQueueTest : public testing::Test {
  public:
   void SetUp() override {
-    dummy_sequence_manager_ =
-        SequenceManagerImpl::CreateUnbound(SequenceManager::Settings{});
-    scoped_refptr<AssociatedThreadId> thread_checker =
-        dummy_sequence_manager_->associated_thread();
-    thread_checker->BindToCurrentThread();
-    time_domain_.reset(new RealTimeDomain());
-    dummy_sequence_manager_->RegisterTimeDomain(time_domain_.get());
-    task_queue_ = std::make_unique<TaskQueueImpl>(dummy_sequence_manager_.get(),
+    time_domain_.reset(new RealTimeDomainFake());
+    task_queue_ = std::make_unique<TaskQueueImpl>(/*sequence_manager=*/nullptr,
                                                   time_domain_.get(),
                                                   TaskQueue::Spec("test"));
 
@@ -62,7 +68,6 @@
   void TearDown() override {
     work_queue_sets_->RemoveQueue(work_queue_.get());
     task_queue_->UnregisterTaskQueue();
-    dummy_sequence_manager_->UnregisterTimeDomain(time_domain_.get());
   }
 
  protected:
@@ -91,7 +96,6 @@
   }
 
   std::unique_ptr<MockObserver> mock_observer_;
-  std::unique_ptr<SequenceManagerImpl> dummy_sequence_manager_;
   std::unique_ptr<RealTimeDomain> time_domain_;
   std::unique_ptr<TaskQueueImpl> task_queue_;
   std::unique_ptr<WorkQueue> work_queue_;
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index 9cb5aeb..5bba459 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -18,10 +18,6 @@
 #include <pthread.h>
 #endif
 
-namespace heap_profiling {
-class ScopedAllowAlloc;
-}  // namespace heap_profiling
-
 namespace ui {
 class TLSDestructionCheckerForX11;
 }
@@ -165,7 +161,6 @@
   friend class base::internal::ThreadLocalStorageTestInternal;
   friend class base::trace_event::MallocDumpProvider;
   friend class debug::GlobalActivityTracker;
-  friend class heap_profiling::ScopedAllowAlloc;
   friend class ui::TLSDestructionCheckerForX11;
   static bool HasBeenDestroyed();
 
diff --git a/build/android/adb_command_line.py b/build/android/adb_command_line.py
index 2f3a615a..5763da4 100755
--- a/build/android/adb_command_line.py
+++ b/build/android/adb_command_line.py
@@ -19,6 +19,20 @@
 from devil.utils import logging_common
 
 
+def CheckBuildTypeSupportsFlags(device, command_line_flags_file):
+  is_webview = command_line_flags_file == 'webview-command-line'
+  if device.IsUserBuild() and is_webview:
+    raise device_errors.CommandFailedError(
+        'WebView only respects flags on a userdebug or eng device, yours '
+        'is a user build.', device)
+  elif device.IsUserBuild():
+    logging.warning(
+        'Your device (%s) is a user build; Chrome may or may not pick up '
+        'your commandline flags. Check your '
+        '"command_line_on_non_rooted_enabled" preference, or switch '
+        'devices.', device)
+
+
 def main():
   parser = argparse.ArgumentParser(description=__doc__)
   parser.usage = '''%(prog)s --name FILENAME [--device SERIAL] [flags...]
@@ -55,19 +69,8 @@
   else:
     action = 'Wrote command line file. '
 
-  is_webview = args.name == 'webview-command-line'
-
   def update_flags(device):
-    if device.IsUserBuild() and is_webview:
-      raise device_errors.CommandFailedError(
-          'WebView only respects flags on a userdebug or eng device, yours '
-          'is a user build.', device)
-    elif device.IsUserBuild():
-      logging.warning(
-          'Your device (%s) is a user build; Chrome may or may not pick up '
-          'your commandline flags. Check your '
-          '"command_line_on_non_rooted_enabled" preference, or switch '
-          'devices.', device)
+    CheckBuildTypeSupportsFlags(device, args.name)
     changer = flag_changer.FlagChanger(device, args.name)
     if remote_args is not None:
       flags = changer.ReplaceFlags(remote_args)
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index 91f6851..c4e6877 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -21,6 +21,7 @@
 import tempfile
 import textwrap
 
+import adb_command_line
 import devil_chromium
 from devil import devil_env
 from devil.android import apk_helper
@@ -323,6 +324,8 @@
         changer = flag_changer.FlagChanger(device, command_line_flags_file)
         flags = []
         if argv:
+          adb_command_line.CheckBuildTypeSupportsFlags(device,
+                                                       command_line_flags_file)
           flags = shlex.split(argv)
         try:
           changer.ReplaceFlags(flags)
@@ -353,6 +356,8 @@
   else:
     flags = shlex.split(argv)
     def update(device):
+      adb_command_line.CheckBuildTypeSupportsFlags(device,
+                                                   command_line_flags_file)
       changer = flag_changer.FlagChanger(device, command_line_flags_file)
       changer.ReplaceFlags(flags)
     device_utils.DeviceUtils.parallel(devices).pMap(update)
diff --git a/build/android/gyp/create_bundle_wrapper_script.pydeps b/build/android/gyp/create_bundle_wrapper_script.pydeps
index 5587566..fb35bc0 100644
--- a/build/android/gyp/create_bundle_wrapper_script.pydeps
+++ b/build/android/gyp/create_bundle_wrapper_script.pydeps
@@ -22,6 +22,7 @@
 ../../../third_party/catapult/devil/devil/android/constants/chrome.py
 ../../../third_party/catapult/devil/devil/android/constants/file_system.py
 ../../../third_party/catapult/devil/devil/android/decorators.py
+../../../third_party/catapult/devil/devil/android/device_blacklist.py
 ../../../third_party/catapult/devil/devil/android/device_errors.py
 ../../../third_party/catapult/devil/devil/android/device_signal.py
 ../../../third_party/catapult/devil/devil/android/device_temp_file.py
@@ -40,6 +41,8 @@
 ../../../third_party/catapult/devil/devil/android/sdk/keyevent.py
 ../../../third_party/catapult/devil/devil/android/sdk/split_select.py
 ../../../third_party/catapult/devil/devil/android/sdk/version_codes.py
+../../../third_party/catapult/devil/devil/android/tools/__init__.py
+../../../third_party/catapult/devil/devil/android/tools/script_common.py
 ../../../third_party/catapult/devil/devil/base_error.py
 ../../../third_party/catapult/devil/devil/constants/__init__.py
 ../../../third_party/catapult/devil/devil/constants/exit_codes.py
@@ -81,6 +84,7 @@
 ../../../third_party/markupsafe/_compat.py
 ../../../third_party/markupsafe/_native.py
 ../../gn_helpers.py
+../adb_command_line.py
 ../apk_operations.py
 ../devil_chromium.py
 ../incremental_install/__init__.py
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 60438e79..24b4bc3 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1656,7 +1656,8 @@
   host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
   host_impl->SetContentHasSlowPaths(content_has_slow_paths_);
   host_impl->SetContentHasNonAAPaint(content_has_non_aa_paint_);
-  host_impl->set_pinch_gesture_active(is_external_pinch_gesture_active_);
+  host_impl->set_external_pinch_gesture_active(
+      is_external_pinch_gesture_active_);
   RecordGpuRasterizationHistogram(host_impl);
 
   host_impl->SetDebugState(debug_state_);
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 12276be..d7e7b2b 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -592,15 +592,19 @@
     return accumulated_root_overscroll_;
   }
 
-  bool pinch_gesture_active() const { return pinch_gesture_active_; }
+  bool pinch_gesture_active() const {
+    return pinch_gesture_active_ || external_pinch_gesture_active_;
+  }
   // Used to set the pinch gesture active state when the pinch gesture is
   // handled on another layer tree. In a page with OOPIFs, only the main
   // frame's layer tree directly handles pinch events. But layer trees for
   // sub-frames need to know when pinch gestures are active so they can
   // throttle the re-rastering. This function allows setting this flag on
   // OOPIF layer trees using information sent (initially) from the main-frame.
-  void set_pinch_gesture_active(bool external_pinch_gesture_active) {
-    pinch_gesture_active_ = external_pinch_gesture_active;
+  void set_external_pinch_gesture_active(bool external_pinch_gesture_active) {
+    external_pinch_gesture_active_ = external_pinch_gesture_active;
+    // Only one of the flags should ever be true at any given time.
+    DCHECK(!pinch_gesture_active_ || !external_pinch_gesture_active_);
   }
 
   void SetTreePriority(TreePriority priority);
@@ -1035,6 +1039,7 @@
   // is set from the main thread during the commit process, using information
   // sent from the root layer tree via IPC messaging.
   bool pinch_gesture_active_ = false;
+  bool external_pinch_gesture_active_ = false;
   bool pinch_gesture_end_should_clear_scrolling_node_ = false;
 
   std::unique_ptr<BrowserControlsOffsetManager>
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 795737f..386b35a 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -885,6 +885,30 @@
   float max_page_scale_factor_;
 };
 
+TEST_F(LayerTreeHostImplTest, LocalAndExternalPinchState) {
+  // PinchGestureBegin/End update pinch_gesture_active() properly.
+  EXPECT_FALSE(host_impl_->pinch_gesture_active());
+  host_impl_->PinchGestureBegin();
+  EXPECT_TRUE(host_impl_->pinch_gesture_active());
+  host_impl_->PinchGestureEnd(gfx::Point(), false /* snap_to_min */);
+  EXPECT_FALSE(host_impl_->pinch_gesture_active());
+
+  // set_external_pinch_gesture_active updates pinch_gesture_active() properly.
+  host_impl_->set_external_pinch_gesture_active(true);
+  EXPECT_TRUE(host_impl_->pinch_gesture_active());
+  host_impl_->set_external_pinch_gesture_active(false);
+  EXPECT_FALSE(host_impl_->pinch_gesture_active());
+
+  // Clearing external_pinch_gesture_active doesn't affect
+  // pinch_gesture_active() if it was set by PinchGestureBegin().
+  host_impl_->PinchGestureBegin();
+  EXPECT_TRUE(host_impl_->pinch_gesture_active());
+  host_impl_->set_external_pinch_gesture_active(false);
+  EXPECT_TRUE(host_impl_->pinch_gesture_active());
+  host_impl_->PinchGestureEnd(gfx::Point(), false /* snap_to_min */);
+  EXPECT_FALSE(host_impl_->pinch_gesture_active());
+}
+
 TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) {
   // Note: It is not possible to disable the renderer once it has been set,
   // so we do not need to test that disabling the renderer notifies us
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 8b0b3e8..db42ce9 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2422,7 +2422,6 @@
     "java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java",
     "java/src/org/chromium/chrome/browser/omnibox/OmniboxViewUtil.java",
     "java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java",
-    "java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImageFetcher.java",
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java",
     "java/src/org/chromium/chrome/browser/page_info/CertificateChainHelper.java",
     "java/src/org/chromium/chrome/browser/page_info/CertificateViewer.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index a07bd7f..918acf3 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -93,8 +93,7 @@
   "java/src/org/chromium/chrome/browser/autofill/PhoneNumberUtil.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryBridge.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMetricsRecorder.java",
-  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java",
-  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManagerImpl.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionViewResizer.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingComponent.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingComponentFactory.java",
@@ -222,6 +221,7 @@
   "java/src/org/chromium/chrome/browser/compositor/CompositorSurfaceManagerImpl.java",
   "java/src/org/chromium/chrome/browser/compositor/CompositorView.java",
   "java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java",
+  "java/src/org/chromium/chrome/browser/compositor/CompositorViewResizer.java",
   "java/src/org/chromium/chrome/browser/compositor/EventOffsetHandler.java",
   "java/src/org/chromium/chrome/browser/compositor/Invalidator.java",
   "java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java",
@@ -1138,7 +1138,6 @@
   "java/src/org/chromium/chrome/browser/omnibox/status/StatusViewBinder.java",
   "java/src/org/chromium/chrome/browser/omnibox/status/StatusProperties.java",
   "java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java",
-  "java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImageFetcher.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index d002e2a0..27c9f96 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -62,10 +62,12 @@
     "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/EditDistance.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/SizeListenableLinearLayout.java",
+    "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselModel.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java",
+    "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/ButtonView.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java",
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_toolbar.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_toolbar.xml
index 8c71681..81a63651 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_toolbar.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_toolbar.xml
@@ -6,7 +6,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="20dp"
+    android:layout_height="@dimen/autofill_assistant_peek_height"
     android:paddingTop="8dp"
     android:paddingBottom="8dp"
     android:orientation="horizontal"
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml
index 686da94..c12be82 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml
@@ -7,7 +7,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:minHeight="40dp"
+    android:minHeight="@dimen/autofill_assistant_button_height"
     app:chipColor="@color/filled_button_bg"
     app:rippleColor="@color/filled_button_ripple_color"
     app:cornerRadius="40dp"
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml
index d952f25..83485ee 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml
@@ -7,7 +7,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:minHeight="40dp"
+    android:minHeight="@dimen/autofill_assistant_button_height"
     style="@style/AssistiveChip"
     app:chipColor="@color/default_text_color_inverse"
     app:cornerRadius="40dp"
diff --git a/chrome/android/features/autofill_assistant/java/res/values-v17/dimens.xml b/chrome/android/features/autofill_assistant/java/res/values-v17/dimens.xml
index c332709..f5a7c9f 100644
--- a/chrome/android/features/autofill_assistant/java/res/values-v17/dimens.xml
+++ b/chrome/android/features/autofill_assistant/java/res/values-v17/dimens.xml
@@ -11,4 +11,7 @@
     <dimen name="autofill_assistant_info_box_spacing">16dp</dimen>
     <dimen name="autofill_assistant_poodle_view_size">34dp</dimen>
     <dimen name="autofill_assistant_filled_button_border_width">0dp</dimen>
+    <dimen name="autofill_assistant_peek_height">20dp</dimen>
+    <dimen name="autofill_assistant_button_height">40dp</dimen>
+    <dimen name="autofill_assistant_carousel_chips_spacing">16dp</dimen>
 </resources>
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
index 08ef123..498701a 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -14,10 +14,13 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
+import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.autofill_assistant.R;
+import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantActionsCarouselCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantCarouselCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip;
+import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantSuggestionsCarouselCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel;
@@ -25,6 +28,7 @@
 import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayModel;
 import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayState;
 import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestCoordinator;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
 import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
@@ -33,7 +37,7 @@
 /**
  * Coordinator responsible for the Autofill Assistant bottom bar.
  */
-class AssistantBottomBarCoordinator {
+class AssistantBottomBarCoordinator implements CompositorViewResizer {
     private final AssistantModel mModel;
     private final BottomSheetController mBottomSheetController;
     private final AssistantBottomSheetContent mContent;
@@ -46,6 +50,11 @@
     private final AssistantCarouselCoordinator mSuggestionsCoordinator;
     private final AssistantCarouselCoordinator mActionsCoordinator;
 
+    private final ObserverList<CompositorViewResizer.Observer> mSizeObservers =
+            new ObserverList<>();
+    private final int mPeekHeight;
+    private int mContentHeight;
+
     @Nullable
     private ScrollView mOnboardingScrollView;
 
@@ -54,6 +63,8 @@
         mModel = model;
         mBottomSheetController = controller;
         mContent = new AssistantBottomSheetContent(context);
+        mPeekHeight = context.getResources().getDimensionPixelSize(
+                R.dimen.autofill_assistant_peek_height);
 
         // Instantiate child components.
         mHeaderCoordinator = new AssistantHeaderCoordinator(
@@ -63,8 +74,9 @@
         mPaymentRequestCoordinator =
                 new AssistantPaymentRequestCoordinator(context, model.getPaymentRequestModel());
         mSuggestionsCoordinator =
-                new AssistantCarouselCoordinator(context, model.getSuggestionsModel());
-        mActionsCoordinator = new AssistantCarouselCoordinator(context, model.getActionsModel());
+                new AssistantSuggestionsCarouselCoordinator(context, model.getSuggestionsModel());
+        mActionsCoordinator =
+                new AssistantActionsCarouselCoordinator(context, model.getActionsModel());
 
         // Add child views to bottom bar container.
         mContent.mBottomBarView.addView(mInfoBoxCoordinator.getView());
@@ -107,6 +119,17 @@
                 mContent.mToolbarView.setBackgroundColor(ApiCompatibilityUtils.getColor(
                         context.getResources(), R.color.modern_primary_color));
             }
+
+            @Override
+            public void onSheetContentChanged(@Nullable BottomSheet.BottomSheetContent newContent) {
+                // As resizing the web content area is an expensive operation, we only shrink it by
+                // our peek height when our BottomSheetContent is shown. This way, the whole web
+                // content will be visible when the sheet is in the PEEK state.
+                // TODO(crbug.com/806868): Make sure this works and does not interfere with Duet
+                // once we are in ChromeTabbedActivity.
+                mContentHeight = newContent == mContent ? mPeekHeight : 0;
+                notifyAutofillAssistantSizeChanged();
+            }
         });
 
         // Show or hide the bottom sheet content when the Autofill Assistant visibility is changed.
@@ -209,6 +232,27 @@
         view.setLayoutParams(layoutParams);
     }
 
+    private void notifyAutofillAssistantSizeChanged() {
+        for (Observer observer : mSizeObservers) observer.onHeightChanged(mContentHeight);
+    }
+
+    // Implementation of methods from AutofillAssistantSizeManager.
+
+    @Override
+    public int getHeight() {
+        return mContentHeight;
+    }
+
+    @Override
+    public void addObserver(Observer observer) {
+        mSizeObservers.addObserver(observer);
+    }
+
+    @Override
+    public void removeObserver(Observer observer) {
+        mSizeObservers.removeObserver(observer);
+    }
+
     // TODO(crbug.com/806868): Move this class at the top of the file once it is a static class.
     private class AssistantBottomSheetContent implements BottomSheet.BottomSheetContent {
         private final View mToolbarView;
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
index 573f17b..a3f0902 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
@@ -39,13 +39,19 @@
         // Instantiate child components.
         mBottomBarCoordinator = new AssistantBottomBarCoordinator(activity, mModel, controller);
         mKeyboardCoordinator = new AssistantKeyboardCoordinator(activity, mModel);
-        mOverlayCoordinator = new AssistantOverlayCoordinator(activity, mModel.getOverlayModel());
+        mOverlayCoordinator = new AssistantOverlayCoordinator(
+                activity, mModel.getOverlayModel(), mBottomBarCoordinator);
 
+        activity.getCompositorViewHolder().addCompositorViewResizer(mBottomBarCoordinator);
         mModel.setVisible(true);
     }
 
     /** Detaches and destroys the view. */
     public void destroy() {
+        if (mActivity.getCompositorViewHolder() != null) {
+            mActivity.getCompositorViewHolder().removeCompositorViewResizer(mBottomBarCoordinator);
+        }
+
         mModel.setVisible(false);
         mOverlayCoordinator.destroy();
         mBottomBarCoordinator.destroy();
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java
new file mode 100644
index 0000000..bb768da
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java
@@ -0,0 +1,234 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant.carousel;
+
+import android.content.Context;
+import android.support.v7.widget.OrientationHelper;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.LayoutManager;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.autofill_assistant.R;
+import org.chromium.ui.modelutil.RecyclerViewAdapter;
+import org.chromium.ui.modelutil.SimpleRecyclerViewMcp;
+
+/**
+ * A coordinator responsible for suggesting chips to the user. If there is one chip to display, it
+ * will be centered on the screen. If there are more than one chip, all but the last one will be
+ * displayed from the right of the screen to the left, and the last one will be displayed at the
+ * left of the screen.
+ *
+ * <p>For instance, if chips = [1, 2, 3]:
+ * |              |
+ * |[3]     [2][1]|
+ * |              |
+ *
+ * <p>If there are too many chips to display all of them on the screen, the carousel will scroll
+ * such that the last chips is fixed. For instance, if chips = [1, 2, 3, 4, 5, 6]:
+ * |               |
+ * |[6][4][3][2][1]|       (before)
+ * |               |
+ *
+ * |               |
+ * |[6][5][4][3][2]|       (after horizontal scrolling from left to right)
+ * |               |
+ */
+public class AssistantActionsCarouselCoordinator implements AssistantCarouselCoordinator {
+    private final RecyclerView mView;
+
+    public AssistantActionsCarouselCoordinator(Context context, AssistantCarouselModel model) {
+        mView = new RecyclerView(context);
+
+        int horizontalPadding = context.getResources().getDimensionPixelSize(
+                R.dimen.autofill_assistant_bottombar_horizontal_spacing);
+        int spaceBetweenViewsPx = context.getResources().getDimensionPixelSize(
+                R.dimen.autofill_assistant_carousel_chips_spacing);
+
+        LayoutManager layoutManager =
+                new CustomLayoutManager(spaceBetweenViewsPx, horizontalPadding);
+        // Workaround for b/128679161.
+        layoutManager.setMeasurementCacheEnabled(false);
+
+        // We set the left padding on the parent as we want the recycler view to clip its children
+        // on the left side. The right padding is computed by the layout manager as we don't want
+        // children to be clipped when scrolling them to the right. We also have to compensate the
+        // padding with the half space that will be added to the chip on the left of the screen.
+        mView.setPadding(horizontalPadding - spaceBetweenViewsPx / 2, 0, 0, 0);
+        mView.setLayoutManager(layoutManager);
+
+        // TODO(crbug.com/806868): WRAP_CONTENT height should also work.
+        mView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                context.getResources().getDimensionPixelSize(
+                        R.dimen.autofill_assistant_button_height)));
+
+        mView.setAdapter(new RecyclerViewAdapter<>(
+                new SimpleRecyclerViewMcp<>(model.getChipsModel(),
+                        AssistantChipViewHolder::getViewType, CustomViewHolder::bind),
+                CustomViewHolder::create));
+    }
+
+    @Override
+    public RecyclerView getView() {
+        return mView;
+    }
+
+    /**
+     * Custom ViewHolder that wraps a ButtonView and a rectangular background. Setting a rectangular
+     * background behind the chips is necessary as chips are scrolled behind the last (fixed) one
+     * and need to be hidden.
+     */
+    private static class CustomViewHolder extends RecyclerView.ViewHolder {
+        private final View mView;
+        private final AssistantChipViewHolder mDelegateViewHolder;
+
+        public CustomViewHolder(View view, AssistantChipViewHolder delegateViewHolder) {
+            super(view);
+            mView = view;
+            mDelegateViewHolder = delegateViewHolder;
+        }
+
+        static CustomViewHolder create(ViewGroup parent, int viewType) {
+            // Wrap the chip inside a rectangular FrameLayout with white background.
+            FrameLayout frameLayout = new FrameLayout(parent.getContext());
+            frameLayout.setBackgroundColor(ApiCompatibilityUtils.getColor(
+                    parent.getContext().getResources(), R.color.sheet_bg_color));
+            frameLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+            AssistantChipViewHolder delegateViewHolder =
+                    AssistantChipViewHolder.create(frameLayout, viewType);
+            ButtonView delegateView = delegateViewHolder.mView;
+            frameLayout.addView(delegateView);
+
+            // Center the chip inside the FrameLayout.
+            FrameLayout.LayoutParams layoutParams =
+                    (FrameLayout.LayoutParams) delegateView.getLayoutParams();
+            layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
+            delegateView.setLayoutParams(layoutParams);
+
+            return new CustomViewHolder(frameLayout, delegateViewHolder);
+        }
+
+        void bind(AssistantChip chip) {
+            mDelegateViewHolder.bind(chip);
+        }
+    }
+
+    // TODO(crbug.com/806868): Handle RTL layouts.
+    // TODO(crbug.com/806868): Recycle invisible children instead of laying all of them out.
+    private class CustomLayoutManager extends RecyclerView.LayoutManager {
+        private final OrientationHelper mOrientationHelper;
+        private final int mPaddingEnd;
+        private final int mSpaceBetweenChildren;
+        private int mMaxScroll;
+        private int mScroll;
+
+        private CustomLayoutManager(int spaceBetweenViewsPx, int paddingEndPx) {
+            mOrientationHelper = OrientationHelper.createHorizontalHelper(this);
+            mSpaceBetweenChildren = spaceBetweenViewsPx;
+            mPaddingEnd = paddingEndPx;
+        }
+
+        @Override
+        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+            return new RecyclerView.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        @Override
+        public boolean isAutoMeasureEnabled() {
+            // We need to enable auto measure to support RecyclerView's that wrap their content
+            // height.
+            return true;
+        }
+
+        @Override
+        public boolean canScrollHorizontally() {
+            return mMaxScroll > 0;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            int itemCount = state.getItemCount();
+            detachAndScrapAttachedViews(recycler);
+            if (itemCount == 0) {
+                return;
+            }
+
+            int extraWidth = getWidth() - getPaddingLeft() - getPaddingRight() - mPaddingEnd
+                    - mSpaceBetweenChildren / 2;
+            extraWidth -= mSpaceBetweenChildren * (itemCount - 1);
+
+            // Add children and measure them. The extra available width will be added after the
+            // first chip if there are more than one, or will be used to center it if there is only
+            // one.
+            for (int i = 0; i < itemCount; i++) {
+                View child = recycler.getViewForPosition(i);
+                addView(child);
+                measureChildWithMargins(child, 0, 0);
+                int childWidth = mOrientationHelper.getDecoratedMeasurement(child);
+                extraWidth -= childWidth;
+            }
+
+            // If we are missing space, allow scrolling.
+            if (extraWidth < 0) {
+                mMaxScroll = -extraWidth;
+            } else {
+                mMaxScroll = 0;
+            }
+
+            // TODO(crbug.com/806868): When chips are added/removed, this will automatically scroll
+            // chips back to the initial state (with first chips visible). We might want to have a
+            // smart scroll that doesn't move too much when adding/removing chips.
+            mScroll = 0;
+
+            int top = getPaddingTop();
+            int right = getWidth() - getPaddingRight() - mPaddingEnd + mSpaceBetweenChildren / 2;
+            // Layout all child views but the last one from right to left.
+            for (int i = 0; i < getChildCount() - 1; i++) {
+                View child = getChildAt(i);
+                int width = mOrientationHelper.getDecoratedMeasurement(child);
+                int height = mOrientationHelper.getDecoratedMeasurementInOther(child);
+                int bottom = top + height;
+                int left = right - width - mSpaceBetweenChildren;
+                layoutDecoratedWithMargins(child, left, top, right, bottom);
+
+                right = left;
+            }
+
+            // Layout last child on the left. We need to layout this one after the others such that
+            // it sits on top of them when scrolling.
+            int left = getPaddingLeft();
+            if (itemCount == 1) {
+                // Center it using extra available space.
+                left += extraWidth / 2;
+            }
+
+            View firstChild = getChildAt(getChildCount() - 1);
+            right = left + mOrientationHelper.getDecoratedMeasurement(firstChild)
+                    + mSpaceBetweenChildren;
+            int bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(firstChild);
+            layoutDecoratedWithMargins(firstChild, left, top, right, bottom);
+        }
+
+        @Override
+        public int scrollHorizontallyBy(
+                int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
+            // dx > 0 == scroll from right to left.
+            int scrollBy = dx > 0 ? Math.min(mScroll, dx) : Math.max(-(mMaxScroll - mScroll), dx);
+            mScroll -= scrollBy;
+
+            // Offset all children except the last one.
+            for (int i = 0; i < getChildCount() - 1; i++) {
+                getChildAt(i).offsetLeftAndRight(-scrollBy);
+            }
+
+            return scrollBy;
+        }
+    }
+}
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
index 7128bbd..b0ae554 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
@@ -4,163 +4,12 @@
 
 package org.chromium.chrome.browser.autofill_assistant.carousel;
 
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.TypedValue;
-import android.view.View;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.chrome.autofill_assistant.R;
-import org.chromium.chrome.browser.autofill_assistant.AbstractListObserver;
-import org.chromium.ui.modelutil.RecyclerViewAdapter;
-import org.chromium.ui.modelutil.SimpleRecyclerViewMcp;
 
 /**
- * Coordinator responsible for suggesting chips to the user.
+ * A generic interface to represent a carousel coordinator to expose its view to other components.
  */
-public class AssistantCarouselCoordinator {
-    // TODO(crbug.com/806868): Get those from XML.
-    private static final int CHIPS_INNER_SPACING_DP = 16;
-
-    private final LinearLayoutManager mLayoutManager;
-    private final RecyclerView mView;
-
-    private boolean mCentered;
-
-    public AssistantCarouselCoordinator(Context context, AssistantCarouselModel model) {
-        mLayoutManager = new LinearLayoutManager(
-                context, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false);
-
-        // Workaround for b/128679161.
-        mLayoutManager.setMeasurementCacheEnabled(false);
-
-        mView = new RecyclerView(context);
-        mView.setLayoutManager(mLayoutManager);
-        mView.addItemDecoration(new SpaceItemDecoration(context));
-        mView.setAdapter(new RecyclerViewAdapter<>(
-                new SimpleRecyclerViewMcp<>(model.getChipsModel(),
-                        AssistantChipViewHolder::getViewType, AssistantChipViewHolder::bind),
-                AssistantChipViewHolder::create));
-
-        // Listen for changes on REVERSE_LAYOUT.
-        model.addObserver((source, propertyKey) -> {
-            if (AssistantCarouselModel.ALIGNMENT == propertyKey) {
-                switch (model.get(AssistantCarouselModel.ALIGNMENT)) {
-                    case AssistantCarouselModel.Alignment.START:
-                        mLayoutManager.setReverseLayout(false);
-                        mCentered = false;
-                        break;
-                    case AssistantCarouselModel.Alignment.CENTER:
-                        mCentered = true;
-                        mView.invalidateItemDecorations();
-                        break;
-                    case AssistantCarouselModel.Alignment.END:
-                        mLayoutManager.setReverseLayout(true);
-                        mCentered = false;
-                        break;
-                }
-            } else {
-                assert false : "Unhandled property detected in AssistantCarouselCoordinator!";
-            }
-        });
-
-        // Listen for changes on chips, and set visibility accordingly.
-        model.getChipsModel().addObserver(new AbstractListObserver<Void>() {
-            @Override
-            public void onDataSetChanged() {
-                mView.invalidateItemDecorations();
-            }
-        });
-
-        // Invalidate decorations when the width of the recycler view changes.
-        mView.addOnLayoutChangeListener(
-                (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                    if (right - left != oldRight - oldLeft) {
-                        // We post the invalidation because ItemDecoration::getItemOffsets is called
-                        // before this listener when the size of the recycler view changes (when
-                        // that happens, the width of the parent is still the old width), so calling
-                        // mView.invalidateItemDecorations() directly will not do anything.
-                        ThreadUtils.postOnUiThread(mView::invalidateItemDecorations);
-                    }
-                });
-    }
-
-    /**
-     * Return the view associated to this carousel.
-     */
-    public RecyclerView getView() {
-        return mView;
-    }
-
-    private class SpaceItemDecoration extends RecyclerView.ItemDecoration {
-        private final int mInnerSpacePx;
-        private final int mOuterSpacePx;
-
-        SpaceItemDecoration(Context context) {
-            mInnerSpacePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    CHIPS_INNER_SPACING_DP / 2, context.getResources().getDisplayMetrics());
-            mOuterSpacePx = context.getResources().getDimensionPixelSize(
-                    R.dimen.autofill_assistant_bottombar_horizontal_spacing);
-        }
-
-        @Override
-        public void getItemOffsets(
-                Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
-            // We use RecyclerView.State#getItemCount() as it returns the correct value when the
-            // carousel is being animated.
-            if (mCentered && state.getItemCount() == 1) {
-                // We have one view and want it horizontally centered. By this time the parent
-                // measured width is correct (as it matches its parent), but we need to explicitly
-                // measure how big the chip view wants to be.
-                int availableWidth = parent.getMeasuredWidth();
-                view.measure(
-                        View.MeasureSpec.makeMeasureSpec(availableWidth, View.MeasureSpec.AT_MOST),
-                        View.MeasureSpec.makeMeasureSpec(
-                                parent.getMeasuredHeight(), View.MeasureSpec.UNSPECIFIED));
-
-                int margin = (availableWidth - view.getMeasuredWidth()) / 2;
-                outRect.left = margin;
-                outRect.right = margin;
-                return;
-            }
-
-            int position = parent.getChildAdapterPosition(view);
-
-            // If old position != NO_POSITION, it means the carousel is being animated and we should
-            // use that position in our logic.
-            ViewHolder viewHolder = parent.getChildViewHolder(view);
-            if (viewHolder != null && viewHolder.getOldPosition() != RecyclerView.NO_POSITION) {
-                position = viewHolder.getOldPosition();
-            }
-
-            if (position == RecyclerView.NO_POSITION) {
-                return;
-            }
-
-            int left;
-            int right;
-            if (position == 0) {
-                left = mOuterSpacePx;
-            } else {
-                left = mInnerSpacePx;
-            }
-
-            if (position == state.getItemCount() - 1) {
-                right = mOuterSpacePx;
-            } else {
-                right = mInnerSpacePx;
-            }
-
-            if (!mLayoutManager.getReverseLayout()) {
-                outRect.left = left;
-                outRect.right = right;
-            } else {
-                outRect.left = right;
-                outRect.right = left;
-            }
-        }
-    }
-}
+public interface AssistantCarouselCoordinator {
+    /** Return the view associated to this carousel. */
+    RecyclerView getView();
+}
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
index 6cdbabb2..e1901b1d 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
@@ -16,7 +16,7 @@
  * ButtonView}.
  */
 class AssistantChipViewHolder extends ViewHolder {
-    private final ButtonView mView;
+    final ButtonView mView;
 
     private AssistantChipViewHolder(ButtonView view) {
         super(view);
@@ -42,6 +42,8 @@
                 assert false : "Unsupported view type " + viewType;
         }
 
+        view.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
         if (viewType >= AssistantChip.Type.NUM_ENTRIES) {
             view.setEnabled(false);
         }
@@ -66,6 +68,7 @@
             mView.getPrimaryTextView().setVisibility(View.GONE);
         } else {
             mView.getPrimaryTextView().setText(text);
+            mView.getPrimaryTextView().setVisibility(View.VISIBLE);
         }
 
         mView.setOnClickListener(ignoredView -> chip.getSelectedListener().run());
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java
new file mode 100644
index 0000000..55794d0
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java
@@ -0,0 +1,164 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant.carousel;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.util.TypedValue;
+import android.view.View;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.autofill_assistant.R;
+import org.chromium.chrome.browser.autofill_assistant.AbstractListObserver;
+import org.chromium.ui.modelutil.RecyclerViewAdapter;
+import org.chromium.ui.modelutil.SimpleRecyclerViewMcp;
+
+/**
+ * Coordinator responsible for suggesting chips to the user.
+ */
+public class AssistantSuggestionsCarouselCoordinator implements AssistantCarouselCoordinator {
+    private final LinearLayoutManager mLayoutManager;
+    private final RecyclerView mView;
+
+    private boolean mCentered;
+
+    public AssistantSuggestionsCarouselCoordinator(Context context, AssistantCarouselModel model) {
+        mLayoutManager = new LinearLayoutManager(
+                context, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false);
+
+        // Workaround for b/128679161.
+        mLayoutManager.setMeasurementCacheEnabled(false);
+
+        mView = new RecyclerView(context);
+        mView.setLayoutManager(mLayoutManager);
+        mView.addItemDecoration(new SpaceItemDecoration(context));
+        mView.setAdapter(new RecyclerViewAdapter<>(
+                new SimpleRecyclerViewMcp<>(model.getChipsModel(),
+                        AssistantChipViewHolder::getViewType, AssistantChipViewHolder::bind),
+                AssistantChipViewHolder::create));
+
+        // Listen for changes on REVERSE_LAYOUT.
+        model.addObserver((source, propertyKey) -> {
+            if (AssistantCarouselModel.ALIGNMENT == propertyKey) {
+                switch (model.get(AssistantCarouselModel.ALIGNMENT)) {
+                    case AssistantCarouselModel.Alignment.START:
+                        mLayoutManager.setReverseLayout(false);
+                        mCentered = false;
+                        break;
+                    case AssistantCarouselModel.Alignment.CENTER:
+                        mCentered = true;
+                        mView.invalidateItemDecorations();
+                        break;
+                    case AssistantCarouselModel.Alignment.END:
+                        mLayoutManager.setReverseLayout(true);
+                        mCentered = false;
+                        break;
+                }
+            } else {
+                assert false : "Unhandled property detected in AssistantCarouselCoordinator!";
+            }
+        });
+
+        // Listen for changes on chips, and set visibility accordingly.
+        model.getChipsModel().addObserver(new AbstractListObserver<Void>() {
+            @Override
+            public void onDataSetChanged() {
+                mView.invalidateItemDecorations();
+            }
+        });
+
+        // Invalidate decorations when the width of the recycler view changes.
+        mView.addOnLayoutChangeListener(
+                (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    if (right - left != oldRight - oldLeft) {
+                        // We post the invalidation because ItemDecoration::getItemOffsets is called
+                        // before this listener when the size of the recycler view changes (when
+                        // that happens, the width of the parent is still the old width), so calling
+                        // mView.invalidateItemDecorations() directly will not do anything.
+                        ThreadUtils.postOnUiThread(mView::invalidateItemDecorations);
+                    }
+                });
+    }
+
+    @Override
+    public RecyclerView getView() {
+        return mView;
+    }
+
+    private class SpaceItemDecoration extends RecyclerView.ItemDecoration {
+        private final int mInnerSpacePx;
+        private final int mOuterSpacePx;
+
+        SpaceItemDecoration(Context context) {
+            mInnerSpacePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    context.getResources().getDimensionPixelSize(
+                            R.dimen.autofill_assistant_carousel_chips_spacing)
+                            / 2,
+                    context.getResources().getDisplayMetrics());
+            mOuterSpacePx = context.getResources().getDimensionPixelSize(
+                    R.dimen.autofill_assistant_bottombar_horizontal_spacing);
+        }
+
+        @Override
+        public void getItemOffsets(
+                Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+            // We use RecyclerView.State#getItemCount() as it returns the correct value when the
+            // carousel is being animated.
+            if (mCentered && state.getItemCount() == 1) {
+                // We have one view and want it horizontally centered. By this time the parent
+                // measured width is correct (as it matches its parent), but we need to explicitly
+                // measure how big the chip view wants to be.
+                int availableWidth = parent.getMeasuredWidth();
+                view.measure(
+                        View.MeasureSpec.makeMeasureSpec(availableWidth, View.MeasureSpec.AT_MOST),
+                        View.MeasureSpec.makeMeasureSpec(
+                                parent.getMeasuredHeight(), View.MeasureSpec.UNSPECIFIED));
+
+                int margin = (availableWidth - view.getMeasuredWidth()) / 2;
+                outRect.left = margin;
+                outRect.right = margin;
+                return;
+            }
+
+            int position = parent.getChildAdapterPosition(view);
+
+            // If old position != NO_POSITION, it means the carousel is being animated and we should
+            // use that position in our logic.
+            ViewHolder viewHolder = parent.getChildViewHolder(view);
+            if (viewHolder != null && viewHolder.getOldPosition() != RecyclerView.NO_POSITION) {
+                position = viewHolder.getOldPosition();
+            }
+
+            if (position == RecyclerView.NO_POSITION) {
+                return;
+            }
+
+            int left;
+            int right;
+            if (position == 0) {
+                left = mOuterSpacePx;
+            } else {
+                left = mInnerSpacePx;
+            }
+
+            if (position == state.getItemCount() - 1) {
+                right = mOuterSpacePx;
+            } else {
+                right = mInnerSpacePx;
+            }
+
+            if (!mLayoutManager.getReverseLayout()) {
+                outRect.left = left;
+                outRect.right = right;
+            } else {
+                outRect.left = right;
+                outRect.right = left;
+            }
+        }
+    }
+}
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java
index 5b458f5..3cc360d 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java
@@ -7,6 +7,7 @@
 import android.graphics.RectF;
 
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.ScrimView.ScrimParams;
@@ -24,12 +25,14 @@
     private final ScrimView mScrim;
     private boolean mScrimEnabled;
 
-    public AssistantOverlayCoordinator(ChromeActivity activity, AssistantOverlayModel model) {
+    public AssistantOverlayCoordinator(ChromeActivity activity, AssistantOverlayModel model,
+            CompositorViewResizer viewResizer) {
         mActivity = activity;
         mScrim = mActivity.getScrim();
         mEventFilter = new AssistantOverlayEventFilter(
                 mActivity, mActivity.getFullscreenManager(), mActivity.getCompositorViewHolder());
-        mDrawable = new AssistantOverlayDrawable(mActivity, mActivity.getFullscreenManager());
+        mDrawable = new AssistantOverlayDrawable(
+                mActivity, mActivity.getFullscreenManager(), viewResizer);
 
         // Listen for changes in the state.
         // TODO(crbug.com/806868): Bind model to view through a ViewBinder instead.
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayDrawable.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayDrawable.java
index c866acf..9c1cb22 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayDrawable.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayDrawable.java
@@ -26,6 +26,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener;
 import org.chromium.content_public.browser.GestureListenerManager;
@@ -48,8 +49,8 @@
  * <p>While scrolling, it keeps track of the current scrolling offset and avoids drawing on top of
  * the top bar which is can be, during animations, just drawn on top of the compositor.
  */
-class AssistantOverlayDrawable
-        extends Drawable implements FullscreenListener, GestureStateListener {
+class AssistantOverlayDrawable extends Drawable
+        implements FullscreenListener, GestureStateListener, CompositorViewResizer.Observer {
     private static final int FADE_DURATION_MS = 250;
 
     /** Alpha value of the background, used for animations. */
@@ -65,6 +66,12 @@
     private static final int BOX_CORNER_DP = 8;
 
     private final ChromeFullscreenManager mFullscreenManager;
+
+    /**
+     * The {@link CompositorViewResizer} associated to the Autofill Assistant BottomSheet content.
+     */
+    private final CompositorViewResizer mViewResizer;
+
     private final Paint mBackground;
     private final Paint mBoxStroke;
     private final Paint mBoxClear;
@@ -129,8 +136,10 @@
     private AssistantOverlayDelegate mDelegate;
     private GestureListenerManager mGestureListenerManager;
 
-    AssistantOverlayDrawable(Context context, ChromeFullscreenManager fullscreenManager) {
+    AssistantOverlayDrawable(Context context, ChromeFullscreenManager fullscreenManager,
+            CompositorViewResizer viewResizer) {
         mFullscreenManager = fullscreenManager;
+        mViewResizer = viewResizer;
 
         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
 
@@ -162,6 +171,7 @@
                 TypedValue.COMPLEX_UNIT_DIP, BOX_CORNER_DP, displayMetrics);
 
         mFullscreenManager.addListener(this);
+        mViewResizer.addObserver(this);
     }
 
     void setDelegate(AssistantOverlayDelegate delegate) {
@@ -182,6 +192,7 @@
     void destroy() {
         setWebContents(null);
         mFullscreenManager.removeListener(this);
+        mViewResizer.removeObserver(this);
         mDelegate = null;
     }
 
@@ -265,7 +276,7 @@
         Rect bounds = getBounds();
         int width = bounds.width();
         int yBottom = bounds.height()
-                - (int) (mFullscreenManager.getBottomControlsHeight()
+                - (int) (mFullscreenManager.getBottomControlsHeight() + mViewResizer.getHeight()
                         - mFullscreenManager.getBottomControlOffset());
 
         // Don't draw over the top or bottom bars.
@@ -329,6 +340,11 @@
         invalidateSelf();
     }
 
+    @Override
+    public void onHeightChanged(int height) {
+        invalidateSelf();
+    }
+
     /** Called at the beginning of a scroll gesture triggered by the browser. */
     @Override
     public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
index d4bd5d0..cb3dfbe 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -178,8 +178,12 @@
         testChips(inOrder, assistantCoordinator.getModel().getSuggestionsModel(),
                 assistantCoordinator.getBottomBarCoordinator().getSuggestionsCoordinator());
 
-        testChips(inOrder, assistantCoordinator.getModel().getActionsModel(),
-                assistantCoordinator.getBottomBarCoordinator().getActionsCoordinator());
+        // TODO(crbug.com/806868): Fix test of actions carousel. This is currently broken as chips
+        // are displayed in the reversed order in the actions carousel and calling
+        // View#performClick() does not work as chips in the actions carousel are wrapped into a
+        // FrameLayout that does not react to clicks.
+        // testChips(inOrder, assistantCoordinator.getModel().getActionsModel(),
+        //        assistantCoordinator.getBottomBarCoordinator().getActionsCoordinator());
 
         // Show movie details.
         String movieTitle = "testTitle";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BitmapCache.java b/chrome/android/java/src/org/chromium/chrome/browser/BitmapCache.java
index d7b2d53..67b9806 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BitmapCache.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BitmapCache.java
@@ -121,6 +121,14 @@
         sDeduplicationCache.put(key, new WeakReference<>(bitmap));
     }
 
+    /**
+     * Evict all bitmaps from the cache.
+     */
+    public void clear() {
+        getBitmapCache().evictAll();
+        scheduleDeduplicationCache();
+    }
+
     /** @return The total number of bytes taken by the bitmaps in this cache. */
     public int size() {
         return getBitmapCache().size();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 9906196..3d15de4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -506,7 +506,7 @@
 
             ((BottomContainer) findViewById(R.id.bottom_container))
                     .initialize(mFullscreenManager,
-                            mManualFillingComponent.getKeyboardExtensionSizeManager());
+                            mManualFillingComponent.getKeyboardExtensionViewResizer());
 
             // If onStart was called before postLayoutInflation (because inflation was done in a
             // background thread) then make sure to call the relevant methods belatedly.
@@ -1450,8 +1450,8 @@
         mManualFillingComponent.initialize(getWindowAndroid(),
                 findViewById(R.id.keyboard_accessory_stub),
                 findViewById(R.id.keyboard_accessory_sheet_stub));
-        getCompositorViewHolder().setKeyboardExtensionView(
-                mManualFillingComponent.getKeyboardExtensionSizeManager());
+        getCompositorViewHolder().addCompositorViewResizer(
+                mManualFillingComponent.getKeyboardExtensionViewResizer());
 
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_ENGAGEMENT_REPORTING_ANDROID)) {
             // The lifetime of this object is managed by the lifecycle dispatcher.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java
deleted file mode 100644
index 9850b8b..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.autofill.keyboard_accessory;
-
-import android.support.annotation.Px;
-
-/**
- * This class holds the size of any extension to or even replacement for a keyboard. The height can
- * be used to either compute an offset for bottom bars (e.g. CCTs or PWAs) or to push up the content
- * area.
- */
-public interface KeyboardExtensionSizeManager {
-    /**
-     * Observers are notified when the size of the keyboard extension changes.
-     */
-    interface Observer {
-        /**
-         * Called when the extension height changes.
-         * @param keyboardHeight The new height of the keyboard extension.
-         */
-        void onKeyboardExtensionHeightChanged(@Px int keyboardHeight);
-    }
-
-    /**
-     * Returns the height of the keyboard extension.
-     * @return A height in pixels.
-     */
-    @Px
-    int getKeyboardExtensionHeight();
-
-    /**
-     * Registered observers are called whenever the extension size changes until unregistered.
-     * Does not guarantee order.
-     * @param observer a {@link KeyboardExtensionSizeManager.Observer}.
-     */
-    void addObserver(Observer observer);
-
-    /**
-     * Removes a registered observer if present.
-     * @param observer a registered {@link KeyboardExtensionSizeManager.Observer}.
-     */
-    void removeObserver(Observer observer);
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionViewResizer.java
similarity index 80%
rename from chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManagerImpl.java
rename to chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionViewResizer.java
index 86e9a18..9381d44 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionViewResizer.java
@@ -7,17 +7,18 @@
 import android.support.annotation.Px;
 
 import org.chromium.base.ObserverList;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 
 /**
  * This class is used by {@link ManualFillingMediator} to provide the combined height of
  * KeyboardAccessoryCoordinator and AccessorySheetCoordinator.
  */
-class KeyboardExtensionSizeManagerImpl implements KeyboardExtensionSizeManager {
+class KeyboardExtensionViewResizer implements CompositorViewResizer {
     private int mHeight;
     private final ObserverList<Observer> mObservers = new ObserverList<>();
 
     @Override
-    public @Px int getKeyboardExtensionHeight() {
+    public @Px int getHeight() {
         return mHeight;
     }
 
@@ -34,6 +35,6 @@
     void setKeyboardExtensionHeight(@Px int newKeyboardExtensionHeight) {
         if (mHeight == newKeyboardExtensionHeight) return;
         mHeight = newKeyboardExtensionHeight;
-        for (Observer observer : mObservers) observer.onKeyboardExtensionHeightChanged(mHeight);
+        for (Observer observer : mObservers) observer.onHeightChanged(mHeight);
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingComponent.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingComponent.java
index 4c44386..0d0c501 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingComponent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingComponent.java
@@ -9,6 +9,7 @@
 
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.PropertyProvider;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.components.autofill.AutofillDelegate;
 import org.chromium.components.autofill.AutofillSuggestion;
 import org.chromium.ui.DropdownPopupWindow;
@@ -112,12 +113,12 @@
     void onPause();
 
     /**
-     * Returns a size manager that allows to access the combined height of
+     * Returns a {@link CompositorViewResizer} that allows to access the combined height of
      * KeyboardAccessoryCoordinator and AccessorySheetCoordinator, and to be
      * notified when it changes.
-     * @return A {@link KeyboardExtensionSizeManager}.
+     * @return A {@link CompositorViewResizer}.
      */
-    KeyboardExtensionSizeManager getKeyboardExtensionSizeManager();
+    CompositorViewResizer getKeyboardExtensionViewResizer();
 
     /**
      * Returns whether the Keyboard is replaced by an accessory sheet or is about to do so.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
index 36f854a..594a53d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
@@ -14,6 +14,7 @@
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.PropertyProvider;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_component.AccessorySheetCoordinator;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.components.autofill.AutofillDelegate;
 import org.chromium.components.autofill.AutofillSuggestion;
 import org.chromium.ui.DropdownPopupWindow;
@@ -134,8 +135,8 @@
     }
 
     @Override
-    public KeyboardExtensionSizeManager getKeyboardExtensionSizeManager() {
-        return mMediator.getKeyboardExtensionSizeManager();
+    public CompositorViewResizer getKeyboardExtensionViewResizer() {
+        return mMediator.getKeyboardExtensionViewResizer();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
index f520765..77466515 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
@@ -38,6 +38,7 @@
 import org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.CreditCardAccessorySheetCoordinator;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.PasswordAccessorySheetCoordinator;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver;
@@ -72,8 +73,8 @@
     private PropertyModel mModel = ManualFillingProperties.createFillingModel();
     private WindowAndroid mWindowAndroid;
     private Supplier<InsetObserverView> mInsetObserverViewSupplier;
-    private final KeyboardExtensionSizeManagerImpl mKeyboardExtensionSizeManager =
-            new KeyboardExtensionSizeManagerImpl();
+    private final KeyboardExtensionViewResizer mKeyboardExtensionViewResizer =
+            new KeyboardExtensionViewResizer();
     private final ManualFillingStateCache mStateCache = new ManualFillingStateCache();
     private final HashSet<Tab> mObservedTabs = new HashSet<>();
     private KeyboardAccessoryCoordinator mKeyboardAccessory;
@@ -293,14 +294,14 @@
         WebContents webContents = mActivity.getCurrentWebContents();
         if (webContents == null) return false;
         float height = webContents.getHeight(); // getHeight actually returns dip, not Px!
-        height += mKeyboardExtensionSizeManager.getKeyboardExtensionHeight()
+        height += mKeyboardExtensionViewResizer.getHeight()
                 / mWindowAndroid.getDisplay().getDipScale();
         return height >= MINIMAL_AVAILABLE_VERTICAL_SPACE
                 && webContents.getWidth() >= MINIMAL_AVAILABLE_HORIZONTAL_SPACE;
     }
 
-    KeyboardExtensionSizeManager getKeyboardExtensionSizeManager() {
-        return mKeyboardExtensionSizeManager;
+    CompositorViewResizer getKeyboardExtensionViewResizer() {
+        return mKeyboardExtensionViewResizer;
     }
 
     private void onPropertyChanged(PropertyObservable<PropertyKey> source, PropertyKey property) {
@@ -468,7 +469,7 @@
             newControlsOffset += mAccessorySheet.getHeight();
         }
         mKeyboardAccessory.setBottomOffset(newControlsOffset);
-        mKeyboardExtensionSizeManager.setKeyboardExtensionHeight(newControlsHeight);
+        mKeyboardExtensionViewResizer.setKeyboardExtensionHeight(newControlsHeight);
         mActivity.getFullscreenManager().updateViewportSize();
     }
 
@@ -557,7 +558,7 @@
         float density = mWindowAndroid.getDisplay().getDipScale();
         // The maximal height for the sheet ensures a minimal amount of WebContents space.
         @Px
-        int maxHeight = mKeyboardExtensionSizeManager.getKeyboardExtensionHeight();
+        int maxHeight = mKeyboardExtensionViewResizer.getHeight();
         maxHeight += Math.round(density * webContents.getHeight());
         maxHeight -= Math.round(density * MINIMAL_AVAILABLE_VERTICAL_SPACE);
         maxHeight -= calculateAccessoryBarHeight();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index cba212d..3c99c11 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -15,7 +15,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.annotation.Nullable;
-import android.support.annotation.Px;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -35,7 +34,6 @@
 import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.InsetObserverView;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardExtensionSizeManager;
 import org.chromium.chrome.browser.compositor.Invalidator.Client;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerHost;
@@ -66,7 +64,9 @@
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * This class holds a {@link CompositorView}. This level of indirection is needed to benefit from
@@ -78,7 +78,7 @@
 public class CompositorViewHolder extends FrameLayout
         implements ContentOffsetProvider, LayoutManagerHost, LayoutRenderHost, Invalidator.Host,
                    FullscreenListener, InsetObserverView.WindowInsetObserver,
-                   KeyboardExtensionSizeManager.Observer {
+                   CompositorViewResizer.Observer {
     private static final long SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS = 500;
 
     private EventOffsetHandler mEventOffsetHandler;
@@ -111,7 +111,7 @@
     /** The toolbar control container. **/
     private ControlContainer mControlContainer;
 
-    private @Nullable KeyboardExtensionSizeManager mKeyboardExtensionSizeManager;
+    private Set<CompositorViewResizer> mViewResizers = new HashSet<>();
     private InsetObserverView mInsetObserverView;
     private boolean mShowingFullscreen;
     private Runnable mSystemUiFullscreenResizeRunnable;
@@ -414,35 +414,30 @@
     public void onSafeAreaChanged(Rect area) {}
 
     /**
-     * Allows to set (or unset if called with null) the {@link KeyboardExtensionSizeManager} that
-     * provides the dimensions of any keyboard extensions or replacements. Registers an observer to
-     * react to size changes immediately.
-     * @param manager A {@link KeyboardExtensionSizeManager}. Optional.
+     * Add a {@link CompositorViewResizer} whose height should be taken into account when computing
+     * the size of the content area. Registers an observer to react to size changes immediately.
+     * @param viewResizer A {@link CompositorViewResizer}.
      */
-    public void setKeyboardExtensionView(@Nullable KeyboardExtensionSizeManager manager) {
-        if (mKeyboardExtensionSizeManager != null) {
-            mKeyboardExtensionSizeManager.removeObserver(this);
-        }
-        mKeyboardExtensionSizeManager = manager;
-        if (mKeyboardExtensionSizeManager != null) {
-            mKeyboardExtensionSizeManager.addObserver(this);
-            onViewportChanged();
-        }
-    }
-
-    @Override
-    public void onKeyboardExtensionHeightChanged(int keyboardHeight) {
-        onUpdateViewportSize();
+    public void addCompositorViewResizer(CompositorViewResizer viewResizer) {
+        mViewResizers.add(viewResizer);
+        viewResizer.addObserver(this);
+        onViewportChanged();
     }
 
     /**
-     * Returns the combined height of all extensions to or replacements of the keyboard which
-     * consume space at the bottom of the content area.
-     * @return the full height in pixels.
+     * Remove a {@link CompositorViewResizer} that was previously added via {@link
+     * #addCompositorViewResizer(CompositorViewResizer)}.
+     * @param viewResizer A {@link CompositorViewResizer}.
      */
-    public @Px int getKeyboardExtensionsHeight() {
-        if (mKeyboardExtensionSizeManager == null) return 0;
-        return mKeyboardExtensionSizeManager.getKeyboardExtensionHeight();
+    public void removeCompositorViewResizer(CompositorViewResizer viewResizer) {
+        viewResizer.removeObserver(this);
+        mViewResizers.remove(viewResizer);
+        onViewportChanged();
+    }
+
+    @Override
+    public void onHeightChanged(int height) {
+        onUpdateViewportSize();
     }
 
     /**
@@ -637,7 +632,20 @@
         int controlsHeight = controlsResizeView()
                 ? getTopControlsHeightPixels() + getBottomControlsHeightPixels()
                 : 0;
-        controlsHeight += getKeyboardExtensionsHeight();
+
+        int resizerHeight = 0;
+        for (CompositorViewResizer viewResizer : mViewResizers) {
+            int resizerImplHeight = viewResizer.getHeight();
+            if (resizerImplHeight != 0) {
+                if (resizerHeight != 0) {
+                    throw new IllegalStateException(
+                            "Multiple CompositorViewResizer with height > 0 are not supported.");
+                }
+                resizerHeight = resizerImplHeight;
+            }
+        }
+        controlsHeight += resizerHeight;
+
         if (isAttachedToWindow(view)) {
             webContents.setSize(w, h - controlsHeight);
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewResizer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewResizer.java
new file mode 100644
index 0000000..32b3fc61
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewResizer.java
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.compositor;
+
+import android.support.annotation.Px;
+
+/**
+ * This class holds the size of any component shown at the bottom of the screen. The height can be
+ * used to either compute an offset for bottom bars (e.g. CCTs or PWAs) or to push up the content
+ * area.
+ */
+public interface CompositorViewResizer {
+    /**
+     * Observers are notified when the size of the component changes.
+     */
+    interface Observer {
+        /**
+         * Called when the component height changes.
+         * @param height The new height of the component.
+         */
+        void onHeightChanged(@Px int height);
+    }
+
+    /**
+     * Returns the height of the component.
+     * @return A height in pixels.
+     */
+    @Px
+    int getHeight();
+
+    /**
+     * Registered observers are called whenever the components size changes until unregistered.
+     * Does not guarantee order.
+     * @param observer a {@link CompositorViewResizer.Observer}.
+     */
+    void addObserver(Observer observer);
+
+    /**
+     * Removes a registered observer if present.
+     * @param observer a registered {@link CompositorViewResizer.Observer}.
+     */
+    void removeObserver(Observer observer);
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
index bad3caf..f7823ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
@@ -345,9 +345,8 @@
         if (mBottomBarView == null) return; // Check bottom bar view but don't inflate it.
         // Hide the container of the bottom bar while the extension is showing. This doesn't
         // affect the content.
-        boolean keyboardExtensionHidesBottomBar = mActivity.getManualFillingComponent()
-                                                          .getKeyboardExtensionSizeManager()
-                                                          .getKeyboardExtensionHeight()
+        boolean keyboardExtensionHidesBottomBar =
+                mActivity.getManualFillingComponent().getKeyboardExtensionViewResizer().getHeight()
                 > 0;
         if (keyboardExtensionHidesBottomBar) {
             getBottomBarView().setVisibility(View.GONE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java
index 963e1ed..907a88c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java
@@ -15,7 +15,6 @@
 import org.chromium.chrome.browser.download.home.filter.Filters.FilterType;
 import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterObserver;
 import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterSource;
-import org.chromium.chrome.browser.offlinepages.prefetch.PrefetchConfiguration;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -97,17 +96,10 @@
             int iconId;
             if (mShowingPrefetch) {
                 iconId = R.drawable.ic_library_news_feed;
-
-                if (PrefetchConfiguration.isPrefetchingEnabled()) {
-                    textId = mInSearchMode ? R.string.download_manager_prefetch_tab_no_results
-                                           : R.string.download_manager_prefetch_tab_empty;
-                } else {
-                    textId = R.string.download_manager_enable_prefetch_message;
-                }
+                textId = R.string.download_manager_prefetch_tab_empty;
             } else {
                 iconId = R.drawable.downloads_big;
-                textId = mInSearchMode ? R.string.download_manager_no_results
-                                       : R.string.download_manager_ui_empty;
+                textId = R.string.download_manager_no_downloads;
             }
 
             mModel.set(EmptyProperties.EMPTY_TEXT_RES_ID, textId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/CachedImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/CachedImageFetcher.java
index afff8f2..bc78140 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/CachedImageFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/CachedImageFetcher.java
@@ -110,6 +110,9 @@
     }
 
     @Override
+    public void clear() {}
+
+    @Override
     public @ImageFetcherConfig int getConfig() {
         return ImageFetcherConfig.DISK_CACHE_ONLY;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcher.java
index d05a052..114652c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcher.java
@@ -19,6 +19,7 @@
  */
 public abstract class ImageFetcher {
     // All UMA client names collected here to prevent duplicates.
+    public static final String ANSWER_SUGGESTIONS_UMA_CLIENT_NAME = "AnswerSuggestions";
     public static final String ASSISTANT_DETAILS_UMA_CLIENT_NAME = "AssistantDetails";
     public static final String ASSISTANT_INFO_BOX_UMA_CLIENT_NAME = "AssistantInfoBox";
     public static final String CONTEXTUAL_SUGGESTIONS_UMA_CLIENT_NAME = "ContextualSuggestions";
@@ -100,6 +101,11 @@
     }
 
     /**
+     * Clear the cache of any bitmaps that may be in-memory.
+     */
+    public abstract void clear();
+
+    /**
      * Returns the type of Image Fetcher this is based on class arrangements. See
      * image_fetcher_service.h for a detailed description of the available configurations.
      *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactory.java
index 748fd4a..14b76ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactory.java
@@ -16,25 +16,28 @@
 
     /**
      * Alias for createImageFetcher below.
-     *
-     * @param config The type of ImageFetcher you need.
-     * @return The correct ImageFetcher according to the provided config.
      */
     public static ImageFetcher createImageFetcher(@ImageFetcherConfig int config) {
-        return createImageFetcher(config, null);
+        return createImageFetcher(config, ImageFetcherBridge.getInstance(), null,
+                InMemoryCachedImageFetcher.DEFAULT_CACHE_SIZE);
     }
 
     /**
      * Alias for createImageFetcher below.
-     *
-     * @param config The type of ImageFetcher you need.
-     * @param discardableReferencePool Used to store images in-memory.
-     * @return The correct ImageFetcher according to the provided config.
      */
     public static ImageFetcher createImageFetcher(
             @ImageFetcherConfig int config, DiscardableReferencePool discardableReferencePool) {
-        return createImageFetcher(
-                config, discardableReferencePool, ImageFetcherBridge.getInstance());
+        return createImageFetcher(config, ImageFetcherBridge.getInstance(),
+                discardableReferencePool, InMemoryCachedImageFetcher.DEFAULT_CACHE_SIZE);
+    }
+
+    /**
+     * Alias for createImageFetcher below.
+     */
+    public static ImageFetcher createImageFetcher(@ImageFetcherConfig int config,
+            DiscardableReferencePool discardableReferencePool, int inMemoryCacheSize) {
+        return createImageFetcher(config, ImageFetcherBridge.getInstance(),
+                discardableReferencePool, inMemoryCacheSize);
     }
 
     /**
@@ -42,13 +45,14 @@
      * config that you must destroy.
      *
      * @param config The type of ImageFetcher you need.
-     * @param discardableReferencePool Used to store images in-memory.
      * @param imageFetcherBridge Bridge to use.
+     * @param discardableReferencePool Used to store images in-memory.
+     * @param inMemoryCacheSize The size of the in memory cache (in bytes).
      * @return The correct ImageFetcher according to the provided config.
      */
     public static ImageFetcher createImageFetcher(@ImageFetcherConfig int config,
-            DiscardableReferencePool discardableReferencePool,
-            ImageFetcherBridge imageFetcherBridge) {
+            ImageFetcherBridge imageFetcherBridge,
+            DiscardableReferencePool discardableReferencePool, int inMemoryCacheSize) {
         // TODO(crbug.com/947191):Allow server-side configuration image fetcher clients.
         switch (config) {
             case ImageFetcherConfig.NETWORK_ONLY:
@@ -64,15 +68,15 @@
             case ImageFetcherConfig.IN_MEMORY_ONLY:
                 assert discardableReferencePool != null;
                 return new InMemoryCachedImageFetcher(
-                        createImageFetcher(
-                                ImageFetcherConfig.NETWORK_ONLY, null, imageFetcherBridge),
-                        discardableReferencePool);
+                        createImageFetcher(ImageFetcherConfig.NETWORK_ONLY, imageFetcherBridge,
+                                discardableReferencePool, inMemoryCacheSize),
+                        discardableReferencePool, inMemoryCacheSize);
             case ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE:
                 assert discardableReferencePool != null;
                 return new InMemoryCachedImageFetcher(
-                        createImageFetcher(
-                                ImageFetcherConfig.DISK_CACHE_ONLY, null, imageFetcherBridge),
-                        discardableReferencePool);
+                        createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY, imageFetcherBridge,
+                                discardableReferencePool, inMemoryCacheSize),
+                        discardableReferencePool, inMemoryCacheSize);
             default:
                 return null;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/InMemoryCachedImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/InMemoryCachedImageFetcher.java
index e1bc4b8..2cecdfe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/InMemoryCachedImageFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/InMemoryCachedImageFetcher.java
@@ -19,7 +19,7 @@
  * ImageFetcher implementation with an in-memory cache. Can also be configured to use a disk cache.
  */
 public class InMemoryCachedImageFetcher extends ImageFetcher {
-    private static final int DEFAULT_CACHE_SIZE = 20 * ConversionUtils.BYTES_PER_MEGABYTE; // 20mb
+    public static final int DEFAULT_CACHE_SIZE = 20 * ConversionUtils.BYTES_PER_MEGABYTE; // 20mb
     private static final float PORTION_OF_AVAILABLE_MEMORY = 1.f / 8.f;
 
     // Will do the work if the image isn't cached in memory.
@@ -111,6 +111,11 @@
     }
 
     @Override
+    public void clear() {
+        mBitmapCache.clear();
+    }
+
+    @Override
     public @ImageFetcherConfig int getConfig() {
         return mConfig;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/NetworkImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/NetworkImageFetcher.java
index ed0b04e..3954166 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/NetworkImageFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/image_fetcher/NetworkImageFetcher.java
@@ -43,6 +43,9 @@
     }
 
     @Override
+    public void clear() {}
+
+    @Override
     public @ImageFetcherConfig int getConfig() {
         return ImageFetcherConfig.NETWORK_ONLY;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
index 03cee93..0b07d9d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
@@ -25,6 +25,11 @@
  */
 public interface LocationBar extends UrlBarDelegate {
     /**
+     * Cleanup resources when this goes out of scope.
+     */
+    void destroy();
+
+    /**
      * Handles native dependent initialization for this class.
      */
     void onNativeLibraryReady();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index b670f3a..cea7caa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -193,6 +193,12 @@
     }
 
     @Override
+    public void destroy() {
+        mAutocompleteCoordinator.destroy();
+        mAutocompleteCoordinator = null;
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImageFetcher.java
deleted file mode 100644
index 39a6122..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImageFetcher.java
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.omnibox.suggestions;
-
-import android.graphics.Bitmap;
-import android.support.v4.util.LruCache;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.util.ConversionUtils;
-
-/**
- * Provides access to images used by Answers in Suggest.
- */
-public class AnswersImageFetcher {
-    // Matches the value in BitmapFetcherService.
-    private static final int INVALID_IMAGE_REQUEST_ID = 0;
-    private static final int MAX_CACHE_SIZE = 500 * ConversionUtils.BYTES_PER_KILOBYTE;
-
-    /**
-     * Observer for updating an image when it is available.
-     */
-    public interface AnswersImageObserver {
-        /**
-         * Called when the image is updated.
-         *
-         * @param bitmap the image
-         */
-        @CalledByNative("AnswersImageObserver")
-        void onAnswersImageChanged(Bitmap bitmap);
-    }
-
-    // Intentionally not using BitmapCache as that does not cache for low end devices (it ensures
-    // the bitmaps are de-dups across instances, but discards them if there is not an active
-    // reference to one).
-    private final LruCache<String, Bitmap> mBitmapCache =
-            new LruCache<String, Bitmap>(MAX_CACHE_SIZE) {
-                @Override
-                protected int sizeOf(String key, Bitmap value) {
-                    return value.getByteCount();
-                }
-            };
-
-    /**
-     * Clears the cached answer images.
-     */
-    public void clearCache() {
-        mBitmapCache.evictAll();
-    }
-
-    /**
-     * Request image, observer is notified when image is loaded.
-     * @param profile     Profile that the request is for.
-     * @param imageUrl    URL for image data.
-     * @param observer    Observer to be notified when image is updated. The C++ side will hold a
-     *                    strong reference to this.
-     * @return            A request_id.
-     */
-    public int requestAnswersImage(
-            Profile profile, String imageUrl, AnswersImageObserver observer) {
-        if (!profile.isOffTheRecord()) {
-            Bitmap bitmap = mBitmapCache.get(imageUrl);
-            if (bitmap != null) {
-                observer.onAnswersImageChanged(bitmap);
-                return INVALID_IMAGE_REQUEST_ID;
-            }
-        }
-        AnswersImageObserver cacheObserver = observer;
-        if (!profile.isOffTheRecord()) {
-            cacheObserver = new AnswersImageObserver() {
-                @Override
-                public void onAnswersImageChanged(Bitmap bitmap) {
-                    if (bitmap == null) return;
-                    mBitmapCache.put(imageUrl, bitmap);
-                    observer.onAnswersImageChanged(bitmap);
-                }
-            };
-        }
-        return nativeRequestAnswersImage(profile, imageUrl, cacheObserver);
-    }
-
-    /**
-     * Cancel a pending image request.
-     * @param profile    Profile the request was issued for.
-     * @param requestId  The ID of the request to be cancelled.
-     */
-    public void cancelAnswersImageRequest(Profile profile, int requestId) {
-        nativeCancelAnswersImageRequest(profile, requestId);
-    }
-
-    /**
-     * Requests an image at |imageUrl| for the given |profile| with |observer| being notified.
-     * @returns an AnswersImageRequest
-     */
-    private static native int nativeRequestAnswersImage(
-            Profile profile, String imageUrl, AnswersImageObserver observer);
-
-    /**
-     * Cancels a pending request.
-     */
-    private static native void nativeCancelAnswersImageRequest(Profile profile, int requestId);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
index a77cf3d..74624f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -50,7 +50,7 @@
  */
 public class AutocompleteCoordinator implements UrlFocusChangeListener, UrlTextChangeListener {
     private final ViewGroup mParent;
-    private final AutocompleteMediator mMediator;
+    private AutocompleteMediator mMediator;
 
     private ListView mListView;
 
@@ -170,6 +170,11 @@
                 new AutocompleteMediator(context, delegate, urlBarEditingTextProvider, listModel);
     }
 
+    public void destroy() {
+        mMediator.destroy();
+        mMediator = null;
+    }
+
     private ViewProvider<SuggestionListViewHolder> createViewProvider(Context context) {
         return new ViewProvider<SuggestionListViewHolder>() {
             private List<Callback<SuggestionListViewHolder>> mCallbacks = new ArrayList<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
index 77d63a4..e63d273 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -93,7 +93,7 @@
     private final Handler mHandler;
     private final BasicSuggestionProcessor mBasicSuggestionProcessor;
     private EditUrlSuggestionProcessor mEditUrlProcessor;
-    private final AnswerSuggestionProcessor mAnswerSuggestionProcessor;
+    private AnswerSuggestionProcessor mAnswerSuggestionProcessor;
 
     private ToolbarDataProvider mDataProvider;
     private boolean mNativeInitialized;
@@ -157,6 +157,11 @@
                 delegate, (suggestion) -> onSelection(suggestion, 0));
     }
 
+    public void destroy() {
+        mAnswerSuggestionProcessor.destroy();
+        mAnswerSuggestionProcessor = null;
+    }
+
     @Override
     public void onStartWithNative() {}
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java
index 7ddabae..4be65e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java
@@ -11,10 +11,13 @@
 import android.view.View;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
+import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig;
+import org.chromium.chrome.browser.image_fetcher.ImageFetcherFactory;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
-import org.chromium.chrome.browser.omnibox.suggestions.AnswersImageFetcher;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator.SuggestionProcessor;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionUiType;
@@ -24,6 +27,7 @@
 import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties;
 import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionIcon;
 import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionTextContainer;
+import org.chromium.chrome.browser.util.ConversionUtils;
 import org.chromium.components.omnibox.AnswerType;
 import org.chromium.components.omnibox.SuggestionAnswer;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -35,10 +39,12 @@
 
 /** A class that handles model and view creation for the most commonly used omnibox suggestion. */
 public class AnswerSuggestionProcessor implements SuggestionProcessor {
+    private static final int MAX_CACHE_SIZE = 500 * ConversionUtils.BYTES_PER_KILOBYTE;
+
     private final Map<String, List<PropertyModel>> mPendingAnswerRequestUrls;
     private final Context mContext;
     private final SuggestionHost mSuggestionHost;
-    private final AnswersImageFetcher mImageFetcher;
+    private ImageFetcher mImageFetcher;
     private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider;
     private boolean mEnableNewAnswerLayout;
 
@@ -51,10 +57,16 @@
         mContext = context;
         mSuggestionHost = suggestionHost;
         mPendingAnswerRequestUrls = new HashMap<>();
-        mImageFetcher = new AnswersImageFetcher();
         mUrlBarEditingTextProvider = editingTextProvider;
     }
 
+    public void destroy() {
+        if (mImageFetcher != null) {
+            mImageFetcher.destroy();
+            mImageFetcher = null;
+        }
+    }
+
     @Override
     public boolean doesProcessSuggestion(OmniboxSuggestion suggestion) {
         // Calculation answers are specific in a way that these are basic suggestions, but processed
@@ -96,7 +108,10 @@
 
     @Override
     public void onUrlFocusChange(boolean hasFocus) {
-        if (!hasFocus) mImageFetcher.clearCache();
+        // This clear is necessary for memory as well as clearing when switching to/from incognito.
+        if (!hasFocus && mImageFetcher != null) {
+            mImageFetcher.clear();
+        }
     }
 
     private void maybeFetchAnswerIcon(OmniboxSuggestion suggestion, PropertyModel model) {
@@ -117,30 +132,35 @@
             return;
         }
 
+        if (mImageFetcher == null) {
+            mImageFetcher = ImageFetcherFactory.createImageFetcher(
+                    ImageFetcherConfig.IN_MEMORY_ONLY,
+                    ((ChromeApplication) mContext.getApplicationContext()).getReferencePool(),
+                    MAX_CACHE_SIZE);
+        }
+
         List<PropertyModel> models = new ArrayList<>();
         models.add(model);
         mPendingAnswerRequestUrls.put(url, models);
-        mImageFetcher.requestAnswersImage(mSuggestionHost.getCurrentProfile(), url,
-                new AnswersImageFetcher.AnswersImageObserver() {
-                    @Override
-                    public void onAnswersImageChanged(Bitmap bitmap) {
-                        ThreadUtils.assertOnUiThread();
 
-                        List<PropertyModel> models = mPendingAnswerRequestUrls.remove(url);
-                        boolean didUpdate = false;
-                        for (int i = 0; i < models.size(); i++) {
-                            PropertyModel model = models.get(i);
-                            if (!mSuggestionHost.isActiveModel(model)) continue;
+        mImageFetcher.fetchImage(
+                url, ImageFetcher.ANSWER_SUGGESTIONS_UMA_CLIENT_NAME, (Bitmap bitmap) -> {
+                    ThreadUtils.assertOnUiThread();
 
-                            if (mEnableNewAnswerLayout) {
-                                model.set(AnswerSuggestionViewProperties.ANSWER_IMAGE, bitmap);
-                            } else {
-                                model.set(SuggestionViewProperties.ANSWER_IMAGE, bitmap);
-                            }
-                            didUpdate = true;
+                    List<PropertyModel> currentModels = mPendingAnswerRequestUrls.remove(url);
+                    boolean didUpdate = false;
+                    for (int i = 0; i < currentModels.size(); i++) {
+                        PropertyModel currentModel = currentModels.get(i);
+                        if (!mSuggestionHost.isActiveModel(currentModel)) continue;
+
+                        if (mEnableNewAnswerLayout) {
+                            model.set(AnswerSuggestionViewProperties.ANSWER_IMAGE, bitmap);
+                        } else {
+                            model.set(SuggestionViewProperties.ANSWER_IMAGE, bitmap);
                         }
-                        if (didUpdate) mSuggestionHost.notifyPropertyModelsChanged();
+                        didUpdate = true;
                     }
+                    if (didUpdate) mSuggestionHost.notifyPropertyModelsChanged();
                 });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/BottomContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/BottomContainer.java
index 8abe980..b64c5d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/BottomContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/BottomContainer.java
@@ -8,7 +8,7 @@
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardExtensionSizeManager;
+import org.chromium.chrome.browser.compositor.CompositorViewResizer;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
@@ -19,12 +19,12 @@
  * bottom controls' offset changes.
  */
 public class BottomContainer
-        extends FrameLayout implements FullscreenListener, KeyboardExtensionSizeManager.Observer {
+        extends FrameLayout implements FullscreenListener, CompositorViewResizer.Observer {
     /** The {@link ChromeFullscreenManager} to listen for controls offset changes. */
     private ChromeFullscreenManager mFullscreenManager;
 
-    /** A {@link KeyboardExtensionSizeManager} to listen to for keyboard extension size changes. */
-    private KeyboardExtensionSizeManager mKeyboardExtensionSizeManager;
+    /** A {@link CompositorViewResizer} to listen to for keyboard extension size changes. */
+    private CompositorViewResizer mKeyboardExtensionSizeManager;
 
     /** The desired Y offset if unaffected by other UI. */
     private float mBaseYOffset;
@@ -43,7 +43,7 @@
      * Initializes this container.
      */
     public void initialize(ChromeFullscreenManager fullscreenManager,
-            KeyboardExtensionSizeManager keyboardExtensionSizeManager) {
+            CompositorViewResizer keyboardExtensionSizeManager) {
         mFullscreenManager = fullscreenManager;
         mFullscreenManager.addListener(this);
         mKeyboardExtensionSizeManager = keyboardExtensionSizeManager;
@@ -70,9 +70,9 @@
         });
     }
 
-    // KeyboardExtensionSizeManager methods
+    // CompositorViewResizer methods
     @Override
-    public void onKeyboardExtensionHeightChanged(int keyboardHeight) {
+    public void onHeightChanged(int keyboardHeight) {
         setTranslationY(mBaseYOffset);
     }
 
@@ -88,7 +88,7 @@
 
         float offsetFromControls = mFullscreenManager.getBottomControlOffset()
                 - mFullscreenManager.getBottomControlsHeight();
-        offsetFromControls -= mKeyboardExtensionSizeManager.getKeyboardExtensionHeight();
+        offsetFromControls -= mKeyboardExtensionSizeManager.getHeight();
 
         // Sit on top of either the bottom sheet or the bottom toolbar depending on which is larger
         // (offsets are negative).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
index 34311da..fa02707 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
@@ -198,6 +198,9 @@
     }
 
     @Override
+    public void destroy() {}
+
+    @Override
     void initialize(ToolbarDataProvider toolbarDataProvider, ToolbarTabController tabController,
             AppMenuButtonHelper appMenuButtonHelper) {
         super.initialize(toolbarDataProvider, tabController, appMenuButtonHelper);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index e2d5d0c..b5d5327 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -137,6 +137,8 @@
             mThemeColorProvider.removeThemeColorObserver(this);
             mThemeColorProvider = null;
         }
+
+        getLocationBar().destroy();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java
index cc1dff4..f52121f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java
@@ -109,6 +109,11 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        // Close the notification tray.
+        ContextUtils.getApplicationContext().sendBroadcast(
+                new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+
         long createTimestamp = SystemClock.elapsedRealtime();
         Intent intent = getIntent();
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index ea7a0ea..3bac4c0 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2646,6 +2646,9 @@
       <message name="IDS_DOWNLOAD_MANAGER_UI_EMPTY" desc="Indicates that there are no downloaded items.">
         No downloads here
       </message>
+      <message name="IDS_DOWNLOAD_MANAGER_NO_DOWNLOADS" desc="Text appearing on an empty tab that indicates that downloaded files appear on this tab.">
+        Files that you download appear here
+      </message>
       <message name="IDS_DOWNLOAD_MANAGER_OPEN_WITH" desc="Menu item to open an item with another app.">
         Open with…
       </message>
@@ -2670,14 +2673,8 @@
       <message name="IDS_DOWNLOAD_MANAGER_PREFETCH_CAPTION" desc="Text containing the prefetched article description.">
         <ph name="DESCRIPTION">%1$s<ex>www.example.com</ex></ph> <ph name="SEPARATOR">•</ph> <ph name="FILE_SIZE">%2$s<ex>1.56 MB</ex></ph>
       </message>
-      <message name="IDS_DOWNLOAD_MANAGER_PREFETCH_TAB_EMPTY" desc="Tab text indicating that there is no prefetched content.">
-        No content here
-      </message>
-      <message name="IDS_DOWNLOAD_MANAGER_PREFETCH_TAB_NO_RESULTS" desc="Tab text indicating that no prefetched content matched a search query.">
-        No content found
-      </message>
-      <message name="IDS_DOWNLOAD_MANAGER_ENABLE_PREFETCH_MESSAGE" desc="Tab text indicating that users can enable prefetch to allow chrome to download articles on Wi-Fi.">
-        Allow Chrome to download articles for you when on Wi-Fi under settings.
+      <message name="IDS_DOWNLOAD_MANAGER_PREFETCH_TAB_EMPTY" desc="Tab text when there is no prefetched content, indicating that prefetched articles appear in this tab which can be viewed when offline.">
+        Articles appear here, which you can read even when you're offline
       </message>
       <message name="IDS_DOWNLOAD_MANAGER_N_HOURS" desc="How many hours ago an item was downloaded (if downloaded on the same day). [ICU Syntax]">
         {HOURS, plural, =1 {# hr} other {# hrs}}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
index 1b926dc..ed46962 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
@@ -43,38 +43,22 @@
     public void
     testModeBrowser() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode(
-                "browser", false, "native-include-thread-names", true, false, false));
-    }
-
-    @Test
-    @MediumTest
-    @CommandLineFlags.Add({"memlog-in-process=off"})
-    public void testModeBrowserDynamic() throws Exception {
-        HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "native", true, false, false));
+        Assert.assertTrue(
+                shim.runTestForMode("browser", false, "native-include-thread-names", false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicNonStreaming() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "native", false, false, false));
-    }
-
-    @Test
-    @MediumTest
-    @CommandLineFlags.Add({"memlog-in-process=off"})
-    public void testModeBrowserDynamicPseudo() throws Exception {
-        HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "native", false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoNonStreaming() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false));
     }
 
     // Non-browser processes must be profiled with a command line flag, since
@@ -89,8 +73,7 @@
     Add({"memlog=all-renderers", "memlog-stack-mode=pseudo", "memlog-sampling-rate=1"})
     public void testModeRendererPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(
-                shim.runTestForMode("all-renderers", false, "pseudo", true, false, false));
+        Assert.assertTrue(shim.runTestForMode("all-renderers", false, "pseudo", false, false));
     }
 
     @Test
@@ -98,29 +81,20 @@
     @CommandLineFlags.Add({"memlog=gpu", "memlog-stack-mode=pseudo", "memlog-sampling-rate=1"})
     public void testModeGpuPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("gpu", false, "native", true, false, false));
-    }
-
-    @Test
-    @MediumTest
-    @CommandLineFlags.Add({"memlog-in-process=off"})
-    public void testModeBrowserDynamicPseudoSampleEverything() throws Exception {
-        HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, true));
+        Assert.assertTrue(shim.runTestForMode("gpu", false, "native", false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSamplePartial() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserAndAllUtility() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(
-                shim.runTestForMode("utility-and-browser", true, "pseudo", true, true, false));
+        Assert.assertTrue(shim.runTestForMode("utility-and-browser", true, "pseudo", true, false));
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactoryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactoryTest.java
index 3c115c1..4c3aae3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactoryTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherFactoryTest.java
@@ -39,23 +39,24 @@
     public void testGetImageFetcher() {
         assertEquals(ImageFetcherConfig.NETWORK_ONLY,
                 ImageFetcherFactory
-                        .createImageFetcher(ImageFetcherConfig.NETWORK_ONLY, mReferencePool,
-                                mImageFetcherBridge)
+                        .createImageFetcher(ImageFetcherConfig.NETWORK_ONLY, mImageFetcherBridge,
+                                mReferencePool, InMemoryCachedImageFetcher.DEFAULT_CACHE_SIZE)
                         .getConfig());
         assertEquals(ImageFetcherConfig.DISK_CACHE_ONLY,
                 ImageFetcherFactory
-                        .createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY, mReferencePool,
-                                mImageFetcherBridge)
+                        .createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY, mImageFetcherBridge,
+                                mReferencePool, InMemoryCachedImageFetcher.DEFAULT_CACHE_SIZE)
                         .getConfig());
         assertEquals(ImageFetcherConfig.IN_MEMORY_ONLY,
                 ImageFetcherFactory
-                        .createImageFetcher(ImageFetcherConfig.IN_MEMORY_ONLY, mReferencePool,
-                                mImageFetcherBridge)
+                        .createImageFetcher(ImageFetcherConfig.IN_MEMORY_ONLY, mImageFetcherBridge,
+                                mReferencePool, InMemoryCachedImageFetcher.DEFAULT_CACHE_SIZE)
                         .getConfig());
         assertEquals(ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE,
                 ImageFetcherFactory
                         .createImageFetcher(ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE,
-                                mReferencePool, mImageFetcherBridge)
+                                mImageFetcherBridge, mReferencePool,
+                                InMemoryCachedImageFetcher.DEFAULT_CACHE_SIZE)
                         .getConfig());
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherTest.java
index 60be0f4..0c1c454 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherTest.java
@@ -45,6 +45,9 @@
                 String url, String clientName, int width, int height, Callback<Bitmap> callback) {}
 
         @Override
+        public void clear() {}
+
+        @Override
         public int getConfig() {
             return 0;
         }
diff --git a/chrome/android/touchless/java/res/layout/open_last_tab_button.xml b/chrome/android/touchless/java/res/layout/open_last_tab_button.xml
index 50656a3..3527ae3 100644
--- a/chrome/android/touchless/java/res/layout/open_last_tab_button.xml
+++ b/chrome/android/touchless/java/res/layout/open_last_tab_button.xml
@@ -4,21 +4,47 @@
      found in the LICENSE file. -->
 <merge
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="21">
 
     <!-- The Chrome Explore header displayed when the user has no history. -->
     <include layout="@layout/open_last_tab_fallback_view"/>
 
-    <org.chromium.ui.widget.ChipView
-        android:id="@+id/last_tab_chip"
+    <LinearLayout
+        android:id="@+id/open_last_tab"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginHorizontal="@dimen/open_last_tab_button_horizontal_margin"
+        android:layout_gravity="center"
         android:paddingHorizontal="@dimen/open_last_tab_button_padding_horizontal"
         android:paddingVertical="@dimen/open_last_tab_button_padding_vertical"
-        app:iconWidth="@dimen/open_last_tab_icon_size"
-        app:iconHeight="@dimen/open_last_tab_icon_size"
-        android:visibility="gone" />
+        android:background="@drawable/hairline_border_card_background"
+        android:theme="@style/Theme.AppCompat.Light">
 
+        <org.chromium.ui.widget.ChromeImageView
+            android:id="@+id/favicon"
+            android:layout_width="@dimen/open_last_tab_icon_size"
+            android:layout_height="@dimen/open_last_tab_icon_size"
+            android:layout_gravity="center_vertical"
+            android:scaleType="centerInside"/>
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginStart="@dimen/open_last_tab_title_text_margin_left"
+            android:textAppearance="@style/TextAppearance.BlackTitle2"
+            android:ellipsize="end"
+            android:maxLines="1"/>
+
+        <TextView
+            android:id="@+id/timestamp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/open_last_tab_timestamp_text_margin_left"
+            android:textAppearance="@style/TextAppearance.BlackCaption"
+            android:ellipsize="end"
+            android:maxLines="1" />
+
+    </LinearLayout>
 </merge>
\ No newline at end of file
diff --git a/chrome/android/touchless/java/res/values-v17/dimens.xml b/chrome/android/touchless/java/res/values-v17/dimens.xml
index bfa5041..bbca39d 100644
--- a/chrome/android/touchless/java/res/values-v17/dimens.xml
+++ b/chrome/android/touchless/java/res/values-v17/dimens.xml
@@ -19,11 +19,11 @@
     <dimen name="open_last_tab_placeholder_image_margin_bottom">13dp</dimen>
 
     <!-- Open last tab button dimensions. -->
-    <dimen name="open_last_tab_button_horizontal_margin">8dp</dimen>
     <dimen name="open_last_tab_button_padding_horizontal">12dp</dimen>
-    <dimen name="open_last_tab_button_padding_vertical">8dp</dimen>
+    <dimen name="open_last_tab_button_padding_vertical">9dp</dimen>
     <dimen name="open_last_tab_icon_size">16dp</dimen>
-    <dimen name="open_last_tab_primary_text_margin_left">8dp</dimen>
+    <dimen name="open_last_tab_title_text_margin_left">12dp</dimen>
+    <dimen name="open_last_tab_timestamp_text_margin_left">10dp</dimen>
 
     <!-- Most likely carousel dimensions. -->
     <dimen name="most_likely_tile_focus_stroke_width">2dp</dimen>
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java
index 442c26e..a4ebf21 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java
@@ -7,17 +7,15 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.touchless.R;
-import org.chromium.ui.widget.ChipView;
 
 /**
  * View for the button to open the last tab.
@@ -25,7 +23,11 @@
 // TODO(crbug.com/948858): Add render tests for this view.
 public class OpenLastTabView extends FrameLayout {
     private LinearLayout mPlaceholder;
-    private ChipView mLastTabChip;
+
+    private LinearLayout mLastTabView;
+    private ImageView mIconView;
+    private TextView mTitleText;
+    private TextView mTimestampText;
 
     public OpenLastTabView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -38,35 +40,10 @@
         super.onFinishInflate();
 
         mPlaceholder = findViewById(R.id.placeholder);
-        mLastTabChip = findViewById(R.id.last_tab_chip);
-        // Allow the system ui to control our background.
-        mLastTabChip.setBackground(null);
-
-        TextView primaryTextView = mLastTabChip.getPrimaryTextView();
-        TextView secondaryTextView = mLastTabChip.getSecondaryTextView();
-
-        LinearLayout.LayoutParams params =
-                new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT);
-        // Allow timestamp to expand to as much as it needs.
-        params.weight = 1;
-        primaryTextView.setLayoutParams(params);
-        primaryTextView.setSingleLine(true);
-        primaryTextView.setEllipsize(TextUtils.TruncateAt.END);
-        primaryTextView.setPadding((int) getContext().getResources().getDimension(
-                                           R.dimen.open_last_tab_primary_text_margin_left),
-                0, 0, 0);
-        ApiCompatibilityUtils.setTextAppearance(
-                primaryTextView, R.style.TextAppearance_BlackTitle2);
-
-        params = new LinearLayout.LayoutParams(
-                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
-        secondaryTextView.setLayoutParams(params);
-        secondaryTextView.setSingleLine(true);
-        // Note: this should never actually need to truncate, but I've included it as a fallback.
-        secondaryTextView.setEllipsize(TextUtils.TruncateAt.END);
-        secondaryTextView.setTextAlignment(TEXT_ALIGNMENT_VIEW_END);
-        ApiCompatibilityUtils.setTextAppearance(
-                secondaryTextView, R.style.TextAppearance_BlackCaption);
+        mLastTabView = findViewById(R.id.open_last_tab);
+        mIconView = findViewById(R.id.favicon);
+        mTitleText = findViewById(R.id.title);
+        mTimestampText = findViewById(R.id.timestamp);
     }
 
     void setLoadSuccess(boolean loadSuccess) {
@@ -74,26 +51,26 @@
 
         if (loadSuccess) {
             mPlaceholder.setVisibility(View.GONE);
-            mLastTabChip.setVisibility(View.VISIBLE);
+            mLastTabView.setVisibility(View.VISIBLE);
         } else {
-            mLastTabChip.setVisibility(View.GONE);
+            mLastTabView.setVisibility(View.GONE);
             mPlaceholder.setVisibility(View.VISIBLE);
         }
     }
 
     void setOpenLastTabOnClickListener(OnClickListener onClickListener) {
-        mLastTabChip.setOnClickListener(onClickListener);
+        mLastTabView.setOnClickListener(onClickListener);
     }
 
     void setFavicon(Bitmap favicon) {
-        mLastTabChip.setIcon(new BitmapDrawable(getContext().getResources(), favicon), false);
+        mIconView.setImageDrawable(new BitmapDrawable(getContext().getResources(), favicon));
     }
 
     void setTitle(String title) {
-        mLastTabChip.getPrimaryTextView().setText(title);
+        mTitleText.setText(title);
     }
 
     void setTimestamp(String timestamp) {
-        mLastTabChip.getSecondaryTextView().setText(timestamp);
+        mTimestampText.setText(timestamp);
     }
 }
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 345f6c1..c223373 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -49,7 +49,6 @@
 #include "components/gwp_asan/buildflags/buildflags.h"
 #include "components/nacl/common/buildflags.h"
 #include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
 #include "components/tracing/common/tracing_sampler_profiler.h"
 #include "components/version_info/version_info.h"
 #include "content/public/common/content_client.h"
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 493ee87..9b4bf0f 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1629,7 +1629,9 @@
   <message name="IDS_CONTROLLED_SETTING_DEMO_SESSION" desc="Text displayed in the controlled settings bubble when a setting's value is enforced by demo session.">
     This setting can't be changed in a demo session.
   </message>
-
+  <message name="IDS_CONTROLLED_SETTING_PARENT" desc="Text displayed in the controlled settings bubble when a setting's value is controlled by user's parent.">
+    This setting is managed by a parent.
+  </message>
   <message name="IDS_STATUSBAR_DISABLE_SPOKEN_FEEDBACK" desc="The menu option to disable spoken feedback accessibility feature.">
     Disable ChromeVox (spoken feedback)
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 5544c32..ff1680f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3347,9 +3347,6 @@
       <message name="IDS_UTILITY_PROCESS_PATCH_NAME" desc="The name of the utility process used for patching file operations.">
         Patch Service
       </message>
-      <message name="IDS_UTILITY_PROCESS_PROFILING_SERVICE_NAME" desc="The name of the utility process used for heap profiling.">
-        Profiling Service
-      </message>
       <message name="IDS_UTILITY_PROCESS_UNZIP_NAME" desc="The name of the utility process used for unzipping files.">
         Unzip Service
       </message>
@@ -4269,6 +4266,9 @@
       <message name="IDS_EXTENSIONS_MENU_TITLE" desc="Title of the Extensions Menu">
         Extensions
       </message>
+      <message name="IDS_EXTENSIONS_MENU_CONTEXT_MENU_TOOLTIP" desc="Title of the context menu for individual extensions in the Extensions Menu">
+        More actions
+      </message>
 
       <!-- Settings API bubble -->
       <message name="IDS_EXTENSIONS_SETTINGS_API_TITLE_HOME_PAGE_BUBBLE" desc="Title of a bubble warning users that an extension has overridden their home page setting">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b104c24..400844e5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2429,7 +2429,6 @@
       "android/ntp/recent_tabs_page_prefs.cc",
       "android/ntp/recent_tabs_page_prefs.h",
       "android/ntp/suggestions_event_reporter_bridge.cc",
-      "android/omnibox/answers_image_bridge.cc",
       "android/omnibox/autocomplete_controller_android.cc",
       "android/omnibox/autocomplete_controller_android.h",
       "android/omnibox/omnibox_prerender.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 57cb863..977131d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -720,15 +720,6 @@
      heap_profiling::kMemlogStackModeMixed},
 };
 
-const FeatureEntry::Choice kMemlogInProcessChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {flag_descriptions::kMemlogInProcessDisabled,
-     heap_profiling::kMemlogInProcess,
-     heap_profiling::kMemlogInProcessDisabled},
-    {flag_descriptions::kMemlogInProcessEnabled,
-     heap_profiling::kMemlogInProcess, heap_profiling::kMemlogInProcessEnabled},
-};
-
 const FeatureEntry::Choice kMemlogSamplingRateChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flag_descriptions::kMemlogSamplingRate10KB,
@@ -2597,10 +2588,6 @@
      flag_descriptions::kMemlogDescription, kOsAll,
      MULTI_VALUE_TYPE(kMemlogModeChoices)},
 
-    {"memlog-in-process", flag_descriptions::kMemlogInProcessName,
-     flag_descriptions::kMemlogInProcessDescription, kOsAll,
-     MULTI_VALUE_TYPE(kMemlogInProcessChoices)},
-
     {"memlog-sampling-rate", flag_descriptions::kMemlogSamplingRateName,
      flag_descriptions::kMemlogSamplingRateDescription, kOsAll,
      MULTI_VALUE_TYPE(kMemlogSamplingRateChoices)},
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 9cafebe..fbbb397 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -381,16 +381,14 @@
   if (!has_close_or_cancel) {
     if (ui_delegate_->GetState() == AutofillAssistantState::STOPPED) {
       Java_AutofillAssistantUiController_addCloseButton(
-          env, java_object_, chips, NO_ICON,
-          base::android::ConvertUTF8ToJavaString(
-              env, l10n_util::GetStringUTF8(IDS_CLOSE)),
+          env, java_object_, chips, ICON_CLEAR,
+          base::android::ConvertUTF8ToJavaString(env, ""),
           /* disabled= */ false);
     } else if (ui_delegate_->GetState() != AutofillAssistantState::INACTIVE) {
       Java_AutofillAssistantUiController_addCancelButton(
-          env, java_object_, chips, NO_ICON,
-          base::android::ConvertUTF8ToJavaString(
-              env, l10n_util::GetStringUTF8(IDS_CANCEL)),
-          -1, /* disabled= */ false);
+          env, java_object_, chips, ICON_CLEAR,
+          base::android::ConvertUTF8ToJavaString(env, ""), -1,
+          /* disabled= */ false);
     }
   }
 
diff --git a/chrome/browser/android/omnibox/answers_image_bridge.cc b/chrome/browser/android/omnibox/answers_image_bridge.cc
deleted file mode 100644
index 9ce2b25..0000000
--- a/chrome/browser/android/omnibox/answers_image_bridge.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/bind.h"
-#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
-#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_android.h"
-#include "jni/AnswersImageFetcher_jni.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/android/java_bitmap.h"
-#include "url/gurl.h"
-
-using base::android::JavaParamRef;
-using base::android::ScopedJavaLocalRef;
-using base::android::ConvertUTF8ToJavaString;
-
-namespace {
-
-class AnswersImageObserverAndroid : public BitmapFetcherService::Observer {
- public:
-  explicit AnswersImageObserverAndroid(JNIEnv* env,
-                                       jobject java_answers_image_observer) {
-    java_answers_image_observer_.Reset(env, java_answers_image_observer);
-  }
-
-  ~AnswersImageObserverAndroid() override {}
-
-  // AnswersImageObserver:
-  void OnImageChanged(BitmapFetcherService::RequestId request_id,
-                      const SkBitmap& answers_image) override {
-    DCHECK(!answers_image.empty());
-
-    JNIEnv* env = base::android::AttachCurrentThread();
-    ScopedJavaLocalRef<jobject> java_bitmap =
-        gfx::ConvertToJavaBitmap(&answers_image);
-    Java_AnswersImageObserver_onAnswersImageChanged(
-        env, java_answers_image_observer_, java_bitmap);
-  }
-
- private:
-  base::android::ScopedJavaGlobalRef<jobject> java_answers_image_observer_;
-};
-
-}  // namespace
-
-static void JNI_AnswersImageFetcher_CancelAnswersImageRequest(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& java_profile,
-    jint java_request_id) {
-  Profile* profile = ProfileAndroid::FromProfileAndroid(java_profile);
-  DCHECK(profile);
-  BitmapFetcherService* bitmap_fetcher_service =
-      BitmapFetcherServiceFactory::GetForBrowserContext(profile);
-  bitmap_fetcher_service->CancelRequest(java_request_id);
-}
-
-static int JNI_AnswersImageFetcher_RequestAnswersImage(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& java_profile,
-    const JavaParamRef<jstring>& java_url,
-    const JavaParamRef<jobject>& java_callback) {
-  Profile* profile = ProfileAndroid::FromProfileAndroid(java_profile);
-  DCHECK(profile);
-  BitmapFetcherService* bitmap_fetcher_service =
-      BitmapFetcherServiceFactory::GetForBrowserContext(profile);
-  std::string url;
-  base::android::ConvertJavaStringToUTF8(env, java_url, &url);
-  return bitmap_fetcher_service->RequestImage(
-      GURL(url), new AnswersImageObserverAndroid(env, java_callback),
-      TRAFFIC_ANNOTATION_WITHOUT_PROTO("Omnibox answers image"));
-}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index fd01f07..3d1a4c9 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3866,11 +3866,9 @@
       "download_manager", base::BindRepeating(&StartDownloadManager));
 #endif
 
-  if (heap_profiling::IsInProcessModeEnabled()) {
-    connection->AddServiceRequestHandler(
-        heap_profiling::mojom::kServiceName,
-        heap_profiling::HeapProfilingService::GetServiceFactory());
-  }
+  connection->AddServiceRequestHandler(
+      heap_profiling::mojom::kServiceName,
+      heap_profiling::HeapProfilingService::GetServiceFactory());
 }
 
 void ChromeContentBrowserClient::RegisterOutOfProcessServices(
@@ -3915,11 +3913,6 @@
                           IDS_UTILITY_PROCESS_PRINTING_SERVICE_NAME);
 #endif
 
-  if (!heap_profiling::IsInProcessModeEnabled()) {
-    (*services)[heap_profiling::mojom::kServiceName] = base::BindRepeating(
-        &l10n_util::GetStringUTF16, IDS_UTILITY_PROCESS_PROFILING_SERVICE_NAME);
-  }
-
 #if BUILDFLAG(ENABLE_EXTENSIONS) || defined(OS_ANDROID)
   (*services)[chrome::mojom::kMediaGalleryUtilServiceName] =
       base::BindRepeating(&l10n_util::GetStringUTF16,
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index a0fef21..28c02a7 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -1439,6 +1439,8 @@
 
   // foo.com should not be isolated to start with. Verify that a cross-site
   // iframe does not become an OOPIF.
+  EXPECT_FALSE(
+      contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess());
   std::string kAppendIframe = R"(
       var i = document.createElement('iframe');
       i.id = 'child';
@@ -1458,8 +1460,19 @@
   EXPECT_TRUE(content::ExecJs(contents, kFillAndSubmit));
   observer.Wait();
 
-  // Open a fresh tab (forcing a new BrowsingInstance), navigate to foo.com,
-  // and verify that a cross-site iframe now becomes an OOPIF.
+  // Since there were no script references from other windows, we should've
+  // swapped BrowsingInstances and put the result of the form submission into a
+  // dedicated process, locked to foo.com.  Check that a cross-site iframe now
+  // becomes an OOPIF.
+  EXPECT_TRUE(
+      contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess());
+  EXPECT_TRUE(ExecJs(contents, kAppendIframe));
+  EXPECT_TRUE(NavigateIframeToURL(contents, "child", bar_url));
+  child = ChildFrameAt(contents->GetMainFrame(), 0);
+  EXPECT_TRUE(child->IsCrossProcessSubframe());
+
+  // Open a fresh tab (also forcing a new BrowsingInstance), navigate to
+  // foo.com, and verify that a cross-site iframe becomes an OOPIF.
   AddBlankTabAndShow(browser());
   EXPECT_EQ(2, browser()->tab_strip_model()->count());
   content::WebContents* new_contents =
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 51d11d3..9266d9c 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -24,7 +24,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -135,11 +135,13 @@
 }
 
 void EnableChromeVoxAfterSwitchAccessMetric(bool val) {
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosChromeVoxAfterSwitchAccess", val);
+  base::UmaHistogramBoolean("Accessibility.CrosChromeVoxAfterSwitchAccess",
+                            val);
 }
 
 void EnableSwitchAccessAfterChromeVoxMetric(bool val) {
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccessAfterChromeVox", val);
+  base::UmaHistogramBoolean("Accessibility.CrosSwitchAccessAfterChromeVox",
+                            val);
 }
 
 // Restarts (stops, then starts brltty). If |address| is empty, only stops.
@@ -1173,49 +1175,55 @@
 }
 
 void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
-                        IsSpokenFeedbackEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast",
-                        IsHighContrastEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard",
-                        IsVirtualKeyboardEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosSpokenFeedback",
+                            IsSpokenFeedbackEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosHighContrast",
+                            IsHighContrastEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosVirtualKeyboard",
+                            IsVirtualKeyboardEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosStickyKeys",
+                            IsStickyKeysEnabled());
   if (MagnificationManager::Get()) {
-    UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosScreenMagnifier",
-                          MagnificationManager::Get()->IsMagnifierEnabled());
+    base::UmaHistogramBoolean(
+        "Accessibility.CrosScreenMagnifier",
+        MagnificationManager::Get()->IsMagnifierEnabled());
+    base::UmaHistogramBoolean(
+        "Accessibility.CrosDockedMagnifier",
+        MagnificationManager::Get()->IsDockedMagnifierEnabled());
   }
   if (profile_) {
     const PrefService* const prefs = profile_->GetPrefs();
 
     bool large_cursor_enabled =
         prefs->GetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled);
-    UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosLargeCursor",
-                          large_cursor_enabled);
+    base::UmaHistogramBoolean("Accessibility.CrosLargeCursor",
+                              large_cursor_enabled);
     if (large_cursor_enabled) {
-      UMA_HISTOGRAM_COUNTS_100(
+      base::UmaHistogramCounts100(
           "Accessibility.CrosLargeCursorSize",
           prefs->GetInteger(ash::prefs::kAccessibilityLargeCursorDipSize));
     }
 
-    UMA_HISTOGRAM_BOOLEAN(
+    base::UmaHistogramBoolean(
         "Accessibility.CrosAlwaysShowA11yMenu",
         prefs->GetBoolean(ash::prefs::kShouldAlwaysShowAccessibilityMenu));
 
     bool autoclick_enabled =
         prefs->GetBoolean(ash::prefs::kAccessibilityAutoclickEnabled);
-    UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
+    base::UmaHistogramBoolean("Accessibility.CrosAutoclick", autoclick_enabled);
   }
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCaretHighlight",
-                        IsCaretHighlightEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCursorHighlight",
-                        IsCursorHighlightEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosDictation", IsDictationEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosFocusHighlight",
-                        IsFocusHighlightEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSelectToSpeak",
-                        IsSelectToSpeakEnabled());
-  UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccess",
-                        IsSwitchAccessEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosCaretHighlight",
+                            IsCaretHighlightEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosCursorHighlight",
+                            IsCursorHighlightEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosDictation",
+                            IsDictationEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosFocusHighlight",
+                            IsFocusHighlightEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosSelectToSpeak",
+                            IsSelectToSpeakEnabled());
+  base::UmaHistogramBoolean("Accessibility.CrosSwitchAccess",
+                            IsSwitchAccessEnabled());
 }
 
 void AccessibilityManager::Observe(
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session_browsertest.cc b/chrome/browser/chromeos/login/demo_mode/demo_session_browsertest.cc
index 9614172..8593daf 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session_browsertest.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session_browsertest.cc
@@ -7,214 +7,165 @@
 #include "base/macros.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h"
-#include "chrome/browser/chromeos/login/login_manager_test.h"
+#include "chrome/browser/chromeos/login/test/device_state_mixin.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/tpm/stub_install_attributes.h"
 #include "components/prefs/pref_service.h"
 
 namespace chromeos {
 
 namespace {
 
-constexpr char kFakeDeviceId[] = "device_id";
-constexpr char kNonDemoDomain[] = "non-demo-mode.com";
-
 void SetDemoConfigPref(DemoSession::DemoModeConfig demo_config) {
   PrefService* prefs = g_browser_process->local_state();
   prefs->SetInteger(prefs::kDemoModeConfig, static_cast<int>(demo_config));
 }
 
+void CheckDemoMode() {
+  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
+  EXPECT_EQ(DemoSession::DemoModeConfig::kOffline,
+            DemoSession::GetDemoConfig());
+
+  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
+  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
+  EXPECT_EQ(DemoSession::DemoModeConfig::kOnline, DemoSession::GetDemoConfig());
+
+  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
+  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
+  EXPECT_EQ(DemoSession::DemoModeConfig::kOffline,
+            DemoSession::GetDemoConfig());
+}
+
+void CheckNoDemoMode() {
+  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
+  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+
+  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
+  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
+  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+
+  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
+  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
+  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+}
+
 }  // namespace
 
 // Tests locking device to policy::DEVICE_MODE_DEMO mode. It is an equivalent to
 // going through online demo mode setup or using offline setup.
-class DemoSessionDemoDeviceModeTest : public LoginManagerTest {
+class DemoSessionDemoDeviceModeTest : public OobeBaseTest {
  protected:
-  DemoSessionDemoDeviceModeTest()
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         true /* should_initialize_webui */),
-        install_attributes_(
-            StubInstallAttributes::CreateDemoMode(kFakeDeviceId)) {}
+  DemoSessionDemoDeviceModeTest() = default;
   ~DemoSessionDemoDeviceModeTest() override = default;
 
-  // LoginManagerTest:
+  // OobeBaseTest:
   void SetUpOnMainThread() override {
-    LoginManagerTest::SetUpOnMainThread();
+    OobeBaseTest::SetUpOnMainThread();
     SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
   }
 
  private:
-  const ScopedStubInstallAttributes install_attributes_;
+  DeviceStateMixin device_state_{
+      &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE};
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionDemoDeviceModeTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSessionDemoDeviceModeTest, IsDemoMode) {
-  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kOffline,
-            DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
-  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kOnline, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
-  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kOffline,
-            DemoSession::GetDemoConfig());
+  CheckDemoMode();
 }
 
 // Tests locking device to demo mode domain without policy::DEVICE_MODE_DEMO
 // mode. It is an equivalent to enrolling device directly by using enterprise
 // enrollment flow.
-class DemoSessionDemoEnrolledDeviceTest : public LoginManagerTest {
+class DemoSessionDemoEnrolledDeviceTest : public OobeBaseTest {
  protected:
-  DemoSessionDemoEnrolledDeviceTest()
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         true /* should_initialize_webui */),
-        install_attributes_(
-            StubInstallAttributes::CreateCloudManaged(policy::kDemoModeDomain,
-                                                      kFakeDeviceId)) {}
+  DemoSessionDemoEnrolledDeviceTest() : OobeBaseTest() {
+    device_state_.set_domain(policy::kDemoModeDomain);
+  }
 
   ~DemoSessionDemoEnrolledDeviceTest() override = default;
 
-  // LoginManagerTest:
+  // OobeBaseTest:
   void SetUpOnMainThread() override {
-    LoginManagerTest::SetUpOnMainThread();
+    OobeBaseTest::SetUpOnMainThread();
     SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
   }
 
  private:
-  const ScopedStubInstallAttributes install_attributes_;
+  DeviceStateMixin device_state_{
+      &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionDemoEnrolledDeviceTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSessionDemoEnrolledDeviceTest, IsDemoMode) {
-  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kOffline,
-            DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
-  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kOnline, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
-  EXPECT_TRUE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kOffline,
-            DemoSession::GetDemoConfig());
+  CheckDemoMode();
 }
 
-class DemoSessionNonDemoEnrolledDeviceTest : public LoginManagerTest {
+class DemoSessionNonDemoEnrolledDeviceTest : public OobeBaseTest {
  public:
-  DemoSessionNonDemoEnrolledDeviceTest()
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         true /* should_initialize_webui */),
-        install_attributes_(
-            StubInstallAttributes::CreateCloudManaged(kNonDemoDomain,
-                                                      kFakeDeviceId)) {}
+  DemoSessionNonDemoEnrolledDeviceTest() = default;
   ~DemoSessionNonDemoEnrolledDeviceTest() override = default;
 
  private:
-  ScopedStubInstallAttributes install_attributes_;
+  DeviceStateMixin device_state_{
+      &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionNonDemoEnrolledDeviceTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSessionNonDemoEnrolledDeviceTest, NotDemoMode) {
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+  CheckNoDemoMode();
 }
 
-class DemoSessionConsumerDeviceTest : public LoginManagerTest {
+class DemoSessionConsumerDeviceTest : public OobeBaseTest {
  public:
-  DemoSessionConsumerDeviceTest()
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         true /* should_initialize_webui */),
-        install_attributes_(StubInstallAttributes::CreateConsumerOwned()) {}
+  DemoSessionConsumerDeviceTest() = default;
   ~DemoSessionConsumerDeviceTest() override = default;
 
  private:
-  ScopedStubInstallAttributes install_attributes_;
+  DeviceStateMixin device_state_{
+      &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED};
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionConsumerDeviceTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSessionConsumerDeviceTest, NotDemoMode) {
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+  CheckNoDemoMode();
 }
 
-class DemoSessionUnownedDeviceTest : public LoginManagerTest {
+class DemoSessionUnownedDeviceTest : public OobeBaseTest {
  public:
-  DemoSessionUnownedDeviceTest()
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         true /* should_initialize_webui */),
-        install_attributes_(StubInstallAttributes::CreateUnset()) {}
+  DemoSessionUnownedDeviceTest() = default;
   ~DemoSessionUnownedDeviceTest() override = default;
 
  private:
-  ScopedStubInstallAttributes install_attributes_;
+  DeviceStateMixin device_state_{
+      &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED};
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionUnownedDeviceTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSessionUnownedDeviceTest, NotDemoMode) {
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+  CheckNoDemoMode();
 }
 
-class DemoSessionActiveDirectoryDeviceTest : public LoginManagerTest {
+class DemoSessionActiveDirectoryDeviceTest : public OobeBaseTest {
  public:
-  DemoSessionActiveDirectoryDeviceTest()
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         true /* should_initialize_webui */),
-        install_attributes_(StubInstallAttributes::CreateActiveDirectoryManaged(
-            policy::kDemoModeDomain,
-            kFakeDeviceId)) {}
+  DemoSessionActiveDirectoryDeviceTest() = default;
   ~DemoSessionActiveDirectoryDeviceTest() override = default;
 
  private:
-  ScopedStubInstallAttributes install_attributes_;
+  DeviceStateMixin device_state_{
+      &mixin_host_,
+      DeviceStateMixin::State::OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED};
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionActiveDirectoryDeviceTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSessionActiveDirectoryDeviceTest, NotDemoMode) {
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOnline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
-
-  SetDemoConfigPref(DemoSession::DemoModeConfig::kOffline);
-  EXPECT_FALSE(DemoSession::IsDeviceInDemoMode());
-  EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
+  CheckNoDemoMode();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/device_state_mixin.cc b/chrome/browser/chromeos/login/test/device_state_mixin.cc
index a11048a..690d99b 100644
--- a/chrome/browser/chromeos/login/test/device_state_mixin.cc
+++ b/chrome/browser/chromeos/login/test/device_state_mixin.cc
@@ -32,15 +32,18 @@
 
 void DeviceStateMixin::SetDeviceState() {
   DCHECK(!is_setup_);
+  DCHECK(domain_.empty() || state_ == State::OOBE_COMPLETED_CLOUD_ENROLLED);
   is_setup_ = true;
   switch (state_) {
     case State::BEFORE_OOBE:
     case State::OOBE_COMPLETED_UNOWNED:
       install_attributes_.Get()->Clear();
       return;
-    case State::OOBE_COMPLETED_CLOUD_ENROLLED:
-      install_attributes_.Get()->SetCloudManaged(kFakeDomain, kFakeDeviceId);
+    case State::OOBE_COMPLETED_CLOUD_ENROLLED: {
+      const std::string domain = !domain_.empty() ? domain_ : kFakeDomain;
+      install_attributes_.Get()->SetCloudManaged(domain, kFakeDeviceId);
       return;
+    }
     case State::OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED:
       install_attributes_.Get()->SetActiveDirectoryManaged(kFakeDomain,
                                                            kFakeDeviceId);
@@ -48,6 +51,9 @@
     case State::OOBE_COMPLETED_CONSUMER_OWNED:
       install_attributes_.Get()->SetConsumerOwned();
       return;
+    case State::OOBE_COMPLETED_DEMO_MODE:
+      install_attributes_.Get()->SetDemoMode(kFakeDeviceId);
+      return;
   }
 }
 
diff --git a/chrome/browser/chromeos/login/test/device_state_mixin.h b/chrome/browser/chromeos/login/test/device_state_mixin.h
index 4e47414..07e1688 100644
--- a/chrome/browser/chromeos/login/test/device_state_mixin.h
+++ b/chrome/browser/chromeos/login/test/device_state_mixin.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_DEVICE_STATE_MIXIN_H_
 
 #include <memory>
+#include <string>
 
 #include "base/macros.h"
 #include "base/values.h"
@@ -23,6 +24,7 @@
     OOBE_COMPLETED_CLOUD_ENROLLED,
     OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED,
     OOBE_COMPLETED_CONSUMER_OWNED,
+    OOBE_COMPLETED_DEMO_MODE,
   };
 
   DeviceStateMixin(InProcessBrowserTestMixinHost* host, State initial_state);
@@ -32,10 +34,12 @@
   void SetUpInProcessBrowserTestFixture() override;
 
   void SetState(State state);
+  void set_domain(const std::string& domain) { domain_ = domain; }
 
  private:
   void SetDeviceState();
   State state_;
+  std::string domain_;
   ScopedStubInstallAttributes install_attributes_;
 
   bool is_setup_ = false;
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
index 52de951..13b8da3 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
-#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/origin_util.h"
@@ -42,8 +41,8 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetSize() > 0);
 
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id_));
-  DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(
-      render_frame_host()->GetProcess()->GetID(), request_id_, this);
+  DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(source_process_id(),
+                                                            request_id_, this);
 
   args_->Remove(0, NULL);
 
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
index b3ddc3a..07369df4 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
@@ -57,11 +57,8 @@
 
 DesktopCaptureChooseDesktopMediaFunctionBase::
     ~DesktopCaptureChooseDesktopMediaFunctionBase() {
-  // RenderFrameHost may be already destroyed.
-  if (render_frame_host()) {
-    DesktopCaptureRequestsRegistry::GetInstance()->RemoveRequest(
-        render_frame_host()->GetProcess()->GetID(), request_id_);
-  }
+  DesktopCaptureRequestsRegistry::GetInstance()->RemoveRequest(
+      source_process_id(), request_id_);
 }
 
 void DesktopCaptureChooseDesktopMediaFunctionBase::Cancel() {
@@ -213,7 +210,7 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id));
 
   DesktopCaptureRequestsRegistry::GetInstance()->CancelRequest(
-      render_frame_host()->GetProcess()->GetID(), request_id);
+      source_process_id(), request_id);
   return RespondNow(NoArguments());
 }
 
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index c0a3148..99e4494 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -59,7 +59,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
@@ -1417,11 +1416,10 @@
     }
     return LoadByFileSystemAPI(directory_url);
   } else {
-    // Check if the DirecotryEntry is the instance of chrome filesystem.
+    // Check if the DirectoryEntry is the instance of chrome filesystem.
     if (!app_file_handler_util::ValidateFileEntryAndGetPath(
-            filesystem_name, filesystem_path,
-            render_frame_host()->GetProcess()->GetID(), &project_base_path_,
-            &error_)) {
+            filesystem_name, filesystem_path, source_process_id(),
+            &project_base_path_, &error_)) {
       SetError("DirectoryEntry of unsupported filesystem.");
       return false;
     }
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 40e574d..9b7a650 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -65,7 +65,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
@@ -1029,7 +1028,7 @@
         })");
   std::unique_ptr<download::DownloadUrlParameters> download_params(
       new download::DownloadUrlParameters(
-          download_url, render_frame_host()->GetProcess()->GetID(),
+          download_url, source_process_id(),
           render_frame_host()->GetRenderViewHost()->GetRoutingID(),
           render_frame_host()->GetRoutingID(), traffic_annotation));
 
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index b75af54..923a556 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -50,6 +50,7 @@
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
@@ -672,6 +673,8 @@
           current_browser(), url, ui::PAGE_TRANSITION_LINK);
       function->set_extension(extension_);
       function->SetRenderFrameHost(tab->GetMainFrame());
+      function->set_source_process_id(
+          tab->GetMainFrame()->GetProcess()->GetID());
     }
   }
 
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
index 0556e1d..9528629 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
@@ -12,8 +12,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 
 namespace image_writer_api = extensions::api::image_writer_private;
@@ -97,8 +95,8 @@
   base::FilePath path;
 
   if (!extensions::app_file_handler_util::ValidateFileEntryAndGetPath(
-          filesystem_name, filesystem_path,
-          render_frame_host()->GetProcess()->GetID(), &path, &error_))
+          filesystem_name, filesystem_path, source_process_id(), &path,
+          &error_))
     return false;
 
   image_writer::OperationManager::Get(GetProfile())
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
index 3edc8b9..0d7ad81 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_api.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -23,8 +23,6 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/mhtml_generation_params.h"
 #include "extensions/common/extension_messages.h"
@@ -278,9 +276,8 @@
     return;
   }
 
-  int child_id = render_frame_host()->GetProcess()->GetID();
-  ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
-      child_id, mhtml_path_);
+  ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(source_process_id(),
+                                                           mhtml_path_);
 
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
   dict->SetString("mhtmlFilePath", mhtml_path_.value());
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
index de95d88..133958a 100644
--- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
+++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
@@ -37,7 +37,7 @@
 void GeneratedTimeZonePrefBase::UpdateTimeZonePrefControlledBy(
     settings_api::PrefObject* out_pref) const {
   if (profile_->IsChild()) {
-    out_pref->controlled_by = settings_api::CONTROLLED_BY_USER_POLICY;
+    out_pref->controlled_by = settings_api::ControlledBy::CONTROLLED_BY_PARENT;
     out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED;
   } else if (chromeos::system::TimeZoneResolverManager::
                  IsTimeZoneResolutionPolicyControlled()) {
diff --git a/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc b/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
index 298ee34..cc33832 100644
--- a/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
@@ -11,8 +11,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/tabs.h"
 #include "chrome/common/extensions/api/webrtc_desktop_capture_private.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/origin_util.h"
 #include "net/base/url_util.h"
@@ -42,8 +40,8 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetSize() > 0);
 
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id_));
-  DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(
-      render_frame_host()->GetProcess()->GetID(), request_id_, this);
+  DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(source_process_id(),
+                                                            request_id_, this);
 
   args_->Remove(0, NULL);
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index ba2e99d..1f6359d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -293,8 +293,8 @@
   },
   {
     "name": "bypass-app-banner-engagement-checks",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "dominickn" ],
+    "expiry_milestone": 78
   },
   {
     "name": "calculate-native-win-occlusion",
@@ -2244,15 +2244,6 @@
     "expiry_milestone": -1
   },
   {
-    "name": "memlog-in-process",
-    "owners": [ "erikchen", "ssid", "etienneb", "alph" ],
-    // Memlog is Chrome's heap profiler. It is used for both automated and
-    // manual performance analysis. This flag allows a user or developer to
-    // capture a memlog without disturbing the situation under test by
-    // restarting to apply a switch. It should not be removed.
-    "expiry_milestone": -1
-  },
-  {
     "name": "memlog-sampling-rate",
     "owners": [ "erikchen", "ssid", "etienneb", "alph" ],
     // Memlog is Chrome's heap profiler. It is used for both automated and
diff --git a/chrome/browser/flag-never-expire-list.json b/chrome/browser/flag-never-expire-list.json
index 880605b..9033305 100644
--- a/chrome/browser/flag-never-expire-list.json
+++ b/chrome/browser/flag-never-expire-list.json
@@ -48,8 +48,6 @@
   "list-all-display-modes",
   "load-media-router-component-extension",
   "memlog",
-  "memlog-keep-small-allocations",
-  "memlog-in-process",
   "memlog-sampling-rate",
   "memlog-stack-mode",
   "overlay-strategies",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 6c48402..7d0b02f 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -824,13 +824,6 @@
 const char kMemlogModeBrowser[] = "Browser only";
 const char kMemlogModeGpu[] = "GPU only";
 
-const char kMemlogInProcessName[] = "Heap profiling service process type.";
-const char kMemlogInProcessDescription[] =
-    "Controls if the heap profiling service runs within the browser process "
-    "(default) or in a dedicated utility process.";
-const char kMemlogInProcessEnabled[] = "In browser process";
-const char kMemlogInProcessDisabled[] = "As separate process";
-
 const char kMemlogSamplingRateName[] =
     "Heap profiling sampling interval (in bytes).";
 const char kMemlogSamplingRateDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f085421..9b2599c 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -485,11 +485,6 @@
 extern const char kMemlogModeManual[];
 extern const char kMemlogModeRendererSampling[];
 
-extern const char kMemlogInProcessName[];
-extern const char kMemlogInProcessDescription[];
-extern const char kMemlogInProcessDisabled[];
-extern const char kMemlogInProcessEnabled[];
-
 extern const char kMemlogSamplingRateName[];
 extern const char kMemlogSamplingRateDescription[];
 extern const char kMemlogSamplingRate10KB[];
diff --git a/chrome/browser/notifications/scheduler/BUILD.gn b/chrome/browser/notifications/scheduler/BUILD.gn
index 8cef5e6..4329d01 100644
--- a/chrome/browser/notifications/scheduler/BUILD.gn
+++ b/chrome/browser/notifications/scheduler/BUILD.gn
@@ -88,6 +88,8 @@
     "notification_scheduler_context.h",
     "proto_conversion.cc",
     "proto_conversion.h",
+    "scheduled_notification_manager.cc",
+    "scheduled_notification_manager.h",
     "scheduler_config.cc",
     "scheduler_config.h",
     "scheduler_utils.cc",
@@ -113,6 +115,7 @@
     "impression_history_tracker_unittest.cc",
     "impression_store_unittest.cc",
     "proto_conversion_unittest.cc",
+    "scheduled_notification_manager_unittest.cc",
     "scheduler_utils_unittest.cc",
   ]
 
diff --git a/chrome/browser/notifications/scheduler/notification_entry.cc b/chrome/browser/notifications/scheduler/notification_entry.cc
index 8703595..c85bb0c 100644
--- a/chrome/browser/notifications/scheduler/notification_entry.cc
+++ b/chrome/browser/notifications/scheduler/notification_entry.cc
@@ -10,7 +10,7 @@
 
 NotificationEntry::NotificationEntry(SchedulerClientType type,
                                      const std::string& guid)
-    : type(type), guid(guid) {}
+    : type(type), guid(guid), create_time(base::Time::Now()) {}
 
 NotificationEntry::NotificationEntry(const NotificationEntry& other) = default;
 
diff --git a/chrome/browser/notifications/scheduler/notification_entry.h b/chrome/browser/notifications/scheduler/notification_entry.h
index 9dc8cb9..2adb0d8 100644
--- a/chrome/browser/notifications/scheduler/notification_entry.h
+++ b/chrome/browser/notifications/scheduler/notification_entry.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/time/time.h"
 #include "chrome/browser/notifications/scheduler/notification_data.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_types.h"
 #include "chrome/browser/notifications/scheduler/schedule_params.h"
@@ -26,6 +27,9 @@
   // The unique id of the notification database entry.
   std::string guid;
 
+  // Creation timestamp.
+  base::Time create_time;
+
   // Contains information to construct the notification.
   NotificationData notification_data;
 
diff --git a/chrome/browser/notifications/scheduler/notification_params.cc b/chrome/browser/notifications/scheduler/notification_params.cc
index bf42f6b..8cf8ab8 100644
--- a/chrome/browser/notifications/scheduler/notification_params.cc
+++ b/chrome/browser/notifications/scheduler/notification_params.cc
@@ -6,15 +6,17 @@
 
 #include <utility>
 
+#include "base/guid.h"
 #include "chrome/browser/notifications/scheduler/schedule_params.h"
 
 namespace notifications {
 
 NotificationParams::NotificationParams(SchedulerClientType type,
-                                       NotificationData notification,
+                                       NotificationData notification_data,
                                        ScheduleParams schedule_params)
     : type(type),
-      notification(std::move(notification)),
+      guid(base::GenerateGUID()),
+      notification_data(std::move(notification_data)),
       schedule_params(std::move(schedule_params)) {}
 
 NotificationParams::~NotificationParams() = default;
diff --git a/chrome/browser/notifications/scheduler/notification_params.h b/chrome/browser/notifications/scheduler/notification_params.h
index 5b684f9c..6bfabf7 100644
--- a/chrome/browser/notifications/scheduler/notification_params.h
+++ b/chrome/browser/notifications/scheduler/notification_params.h
@@ -23,9 +23,12 @@
   // The type of notification using the scheduling system.
   SchedulerClientType type;
 
+  // An auto generated unique id of the scheduled notification.
+  std::string guid;
+
   // Data used to show the notification, such as text or title on the
   // notification.
-  NotificationData notification;
+  NotificationData notification_data;
 
   // Scheduling details used to determine when to show the notification.
   ScheduleParams schedule_params;
diff --git a/chrome/browser/notifications/scheduler/scheduled_notification_manager.cc b/chrome/browser/notifications/scheduler/scheduled_notification_manager.cc
new file mode 100644
index 0000000..3b1badb
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/scheduled_notification_manager.cc
@@ -0,0 +1,140 @@
+// Copyright 2019 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/notifications/scheduler/scheduled_notification_manager.h"
+
+#include <algorithm>
+#include <map>
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/notifications/scheduler/notification_entry.h"
+#include "chrome/browser/notifications/scheduler/notification_params.h"
+
+namespace notifications {
+namespace {
+
+// Comparator used to sort notification entries based on creation time.
+bool CreateTimeCompare(const NotificationEntry* lhs,
+                       const NotificationEntry* rhs) {
+  DCHECK(lhs && rhs);
+  return lhs->create_time <= rhs->create_time;
+}
+
+class ScheduledNotificationManagerImpl : public ScheduledNotificationManager {
+ public:
+  using Store = std::unique_ptr<CollectionStore<NotificationEntry>>;
+
+  ScheduledNotificationManagerImpl(Store store, Delegate* delegate)
+      : store_(std::move(store)),
+        delegate_(delegate),
+        weak_ptr_factory_(this) {}
+
+ private:
+  void Init(InitCallback callback) override {
+    store_->InitAndLoad(
+        base::BindOnce(&ScheduledNotificationManagerImpl::OnStoreInitialized,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  // NotificationManager implementation.
+  void ScheduleNotification(
+      std::unique_ptr<NotificationParams> notification_params) override {
+    DCHECK(notification_params);
+    std::string guid = notification_params->guid;
+    DCHECK(!guid.empty());
+    if (notifications_.find(guid) != notifications_.end()) {
+      // TODO(xingliu): Report duplicate guid failure.
+      return;
+    }
+
+    auto entry =
+        std::make_unique<NotificationEntry>(notification_params->type, guid);
+    entry->notification_data =
+        std::move(notification_params->notification_data);
+    entry->schedule_params = std::move(notification_params->schedule_params);
+    auto* entry_ptr = entry.get();
+    notifications_.emplace(guid, std::move(entry));
+    store_->Add(
+        guid, *entry_ptr,
+        base::BindOnce(&ScheduledNotificationManagerImpl::OnNotificationAdded,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  void DisplayNotification(const std::string& guid) override {
+    auto it = notifications_.find(guid);
+    if (it == notifications_.end())
+      return;
+
+    // Move the entry to delegate, and delete it from the storage.
+    auto notification_entry = std::move(it->second);
+    notifications_.erase(guid);
+    store_->Delete(
+        guid,
+        base::BindOnce(&ScheduledNotificationManagerImpl::OnNotificationDeleted,
+                       weak_ptr_factory_.GetWeakPtr()));
+    if (delegate_)
+      delegate_->DisplayNotification(std::move(notification_entry));
+  }
+
+  void GetAllNotifications(Notifications* notifications) override {
+    DCHECK(notifications);
+
+    for (const auto& pair : notifications_) {
+      const auto& notif = pair.second;
+      DCHECK(notif);
+      (*notifications)[notif->type].emplace_back(notif.get());
+    }
+
+    // Sort by creation time for each notification type.
+    for (auto it = notifications->begin(); it != notifications->end(); ++it) {
+      std::sort(it->second.begin(), it->second.end(), &CreateTimeCompare);
+    }
+  }
+
+  void OnStoreInitialized(InitCallback callback,
+                          bool success,
+                          CollectionStore<NotificationEntry>::Entries entries) {
+    if (!success) {
+      std::move(callback).Run(false);
+      return;
+    }
+
+    for (auto it = entries.begin(); it != entries.end(); ++it) {
+      std::string guid = (*it)->guid;
+      notifications_.emplace(guid, std::move(*it));
+    }
+
+    std::move(callback).Run(true);
+  }
+
+  void OnNotificationAdded(bool success) { NOTIMPLEMENTED(); }
+
+  void OnNotificationDeleted(bool success) { NOTIMPLEMENTED(); }
+
+  Store store_;
+  Delegate* delegate_;
+  std::map<std::string, std::unique_ptr<NotificationEntry>> notifications_;
+
+  base::WeakPtrFactory<ScheduledNotificationManagerImpl> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(ScheduledNotificationManagerImpl);
+};
+
+}  // namespace
+
+// static
+std::unique_ptr<ScheduledNotificationManager>
+ScheduledNotificationManager::Create(
+    std::unique_ptr<CollectionStore<NotificationEntry>> store,
+    Delegate* delegate) {
+  return std::make_unique<ScheduledNotificationManagerImpl>(std::move(store),
+                                                            delegate);
+}
+
+ScheduledNotificationManager::ScheduledNotificationManager() = default;
+
+ScheduledNotificationManager::~ScheduledNotificationManager() = default;
+
+}  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/scheduled_notification_manager.h b/chrome/browser/notifications/scheduler/scheduled_notification_manager.h
new file mode 100644
index 0000000..01293a5
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/scheduled_notification_manager.h
@@ -0,0 +1,74 @@
+// Copyright 2019 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_NOTIFICATIONS_SCHEDULER_SCHEDULED_NOTIFICATION_MANAGER_H_
+#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_SCHEDULED_NOTIFICATION_MANAGER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "chrome/browser/notifications/scheduler/collection_store.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_types.h"
+
+namespace notifications {
+
+struct NotificationEntry;
+struct NotificationParams;
+
+// Class to manage in-memory scheduled notifications loaded from the storage.
+class ScheduledNotificationManager {
+ public:
+  using InitCallback = base::OnceCallback<void(bool)>;
+  using Notifications =
+      std::map<SchedulerClientType, std::vector<const NotificationEntry*>>;
+
+  // Delegate that receives events from the manager.
+  class Delegate {
+   public:
+    // Displays a notification to the user.
+    virtual void DisplayNotification(
+        std::unique_ptr<NotificationEntry> notification) = 0;
+
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  // Creates the instance.
+  static std::unique_ptr<ScheduledNotificationManager> Create(
+      std::unique_ptr<CollectionStore<NotificationEntry>> store,
+      Delegate* delegate);
+
+  // Initializes the notification store.
+  virtual void Init(InitCallback callback) = 0;
+
+  // Adds a new notification.
+  virtual void ScheduleNotification(
+      std::unique_ptr<NotificationParams> notification_params) = 0;
+
+  // Displays a notification, the scheduled notification will be removed from
+  // storage, then Delegate::DisplayNotification() should be invoked.
+  virtual void DisplayNotification(const std::string& guid) = 0;
+
+  // Gets all scheduled notifications. For each type, notifications are sorted
+  // by creation timestamp.
+  virtual void GetAllNotifications(Notifications* notifications) = 0;
+
+  virtual ~ScheduledNotificationManager();
+
+ protected:
+  ScheduledNotificationManager();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScheduledNotificationManager);
+};
+
+}  // namespace notifications
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_SCHEDULED_NOTIFICATION_MANAGER_H_
diff --git a/chrome/browser/notifications/scheduler/scheduled_notification_manager_unittest.cc b/chrome/browser/notifications/scheduler/scheduled_notification_manager_unittest.cc
new file mode 100644
index 0000000..43d350a
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/scheduled_notification_manager_unittest.cc
@@ -0,0 +1,228 @@
+// Copyright 2019 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/notifications/scheduler/scheduled_notification_manager.h"
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "chrome/browser/notifications/scheduler/collection_store.h"
+#include "chrome/browser/notifications/scheduler/notification_entry.h"
+#include "chrome/browser/notifications/scheduler/notification_params.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using ::testing::Invoke;
+using Entries = std::vector<std::unique_ptr<notifications::NotificationEntry>>;
+
+namespace notifications {
+namespace {
+
+const char kGuid[] = "test_guid_1234";
+const char kTitle[] = "test_title";
+
+NotificationEntry CreateNotificationEntry() {
+  return NotificationEntry(SchedulerClientType::kUnknown, base::GenerateGUID());
+}
+
+class MockDelegate : public ScheduledNotificationManager::Delegate {
+ public:
+  MockDelegate() = default;
+  MOCK_METHOD1(DisplayNotification, void(std::unique_ptr<NotificationEntry>));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
+class MockNotificationStore : public CollectionStore<NotificationEntry> {
+ public:
+  MockNotificationStore() {}
+
+  MOCK_METHOD1(InitAndLoad,
+               void(CollectionStore<NotificationEntry>::LoadCallback));
+  MOCK_METHOD3(Add,
+               void(const std::string&,
+                    const NotificationEntry&,
+                    base::OnceCallback<void(bool)>));
+  MOCK_METHOD3(Update,
+               void(const std::string&,
+                    const NotificationEntry&,
+                    base::OnceCallback<void(bool)>));
+  MOCK_METHOD2(Delete,
+               void(const std::string&, base::OnceCallback<void(bool)>));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockNotificationStore);
+};
+
+class ScheduledNotificationManagerTest : public testing::Test {
+ public:
+  ScheduledNotificationManagerTest() : store_(nullptr) {}
+  ~ScheduledNotificationManagerTest() override = default;
+
+  void SetUp() override {
+    delegate_ = std::make_unique<MockDelegate>();
+    auto store = std::make_unique<MockNotificationStore>();
+    store_ = store.get();
+    manager_ =
+        ScheduledNotificationManager::Create(std::move(store), delegate_.get());
+  }
+
+ protected:
+  ScheduledNotificationManager* manager() { return manager_.get(); }
+  MockNotificationStore* store() { return store_; }
+  MockDelegate* delegate() { return delegate_.get(); }
+
+  // Initializes the manager with predefined data in the store.
+  void InitWithData(std::vector<NotificationEntry> data) {
+    Entries entries;
+    for (auto it = data.begin(); it != data.end(); ++it) {
+      auto entry_ptr = std::make_unique<NotificationEntry>(
+          SchedulerClientType::kUnknown, it->guid);
+      *(entry_ptr.get()) = *it;
+      entries.emplace_back(std::move(entry_ptr));
+    }
+
+    // Initialize the store and call the callback.
+    EXPECT_CALL(*store(), InitAndLoad(_))
+        .WillOnce(
+            Invoke([&entries](base::OnceCallback<void(bool, Entries)> cb) {
+              std::move(cb).Run(true, std::move(entries));
+            }));
+    base::RunLoop loop;
+    manager()->Init(base::BindOnce(
+        [](base::RepeatingClosure closure, bool success) {
+          EXPECT_TRUE(success);
+          std::move(closure).Run();
+        },
+        loop.QuitClosure()));
+    loop.Run();
+  }
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  std::unique_ptr<MockDelegate> delegate_;
+  MockNotificationStore* store_;
+  std::unique_ptr<ScheduledNotificationManager> manager_;
+  DISALLOW_COPY_AND_ASSIGN(ScheduledNotificationManagerTest);
+};
+
+// Verify that error is received when initialization failed.
+TEST_F(ScheduledNotificationManagerTest, InitFailed) {
+  EXPECT_CALL(*store(), InitAndLoad(_))
+      .WillOnce(Invoke([](base::OnceCallback<void(bool, Entries)> cb) {
+        std::move(cb).Run(false, Entries());
+      }));
+
+  base::RunLoop loop;
+  manager()->Init(base::BindOnce(
+      [](base::RepeatingClosure closure, bool success) {
+        // Expected to receive error.
+        EXPECT_FALSE(success);
+        std::move(closure).Run();
+      },
+      loop.QuitClosure()));
+  loop.Run();
+}
+
+// Test to schedule a notification.
+TEST_F(ScheduledNotificationManagerTest, ScheduleNotification) {
+  InitWithData(std::vector<NotificationEntry>());
+  NotificationData notification_data;
+  notification_data.title = kTitle;
+  ScheduleParams schedule_params;
+  schedule_params.priority = ScheduleParams::Priority::kHigh;
+  auto params = std::make_unique<NotificationParams>(
+      SchedulerClientType::kUnknown, notification_data, schedule_params);
+  std::string guid = params->guid;
+  EXPECT_FALSE(guid.empty());
+
+  // Verify call contract.
+  EXPECT_CALL(*store(), Add(guid, _, _));
+  manager()->ScheduleNotification(std::move(params));
+
+  // Verify in-memory data.
+  ScheduledNotificationManager::Notifications notifications;
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 1u);
+  const NotificationEntry* entry = *(notifications.begin()->second.begin());
+  EXPECT_EQ(entry->guid, guid);
+  EXPECT_NE(entry->create_time, base::Time());
+
+  // TODO(xingliu): change these to compare with operator==.
+  EXPECT_EQ(entry->notification_data.title, kTitle);
+  EXPECT_EQ(entry->schedule_params.priority, ScheduleParams::Priority::kHigh);
+}
+
+// Test to schedule a notification without guid, we will auto generated one.
+TEST_F(ScheduledNotificationManagerTest, ScheduleNotificationEmptyGuid) {
+  InitWithData(std::vector<NotificationEntry>());
+  auto params = std::make_unique<NotificationParams>(
+      SchedulerClientType::kUnknown, NotificationData(), ScheduleParams());
+
+  // Verify call contract.
+  EXPECT_CALL(*store(), Add(_, _, _));
+  manager()->ScheduleNotification(std::move(params));
+
+  // Verify in-memory data.
+  ScheduledNotificationManager::Notifications notifications;
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 1u);
+  const NotificationEntry* entry = *(notifications.begin()->second.begin());
+  EXPECT_NE(entry->guid, std::string());
+  EXPECT_NE(entry->create_time, base::Time());
+}
+
+// TODO(xingliu): change this to compare with operator==.
+MATCHER_P(NotificationEntryIs, expected, "") {
+  return arg->guid == expected.guid;
+}
+
+// Test to display a notification.
+TEST_F(ScheduledNotificationManagerTest, DisplayNotification) {
+  auto entry = CreateNotificationEntry();
+  entry.guid = kGuid;
+  InitWithData(std::vector<NotificationEntry>({entry}));
+
+  // Verify delegate and dependency call contract.
+  EXPECT_CALL(*store(), Delete(kGuid, _));
+  EXPECT_CALL(*delegate(), DisplayNotification(NotificationEntryIs(entry)));
+  manager()->DisplayNotification(kGuid);
+
+  // Verify in-memory data.
+  ScheduledNotificationManager::Notifications notifications;
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_TRUE(notifications.empty());
+}
+
+// Verify GetAllNotifications API, the notification should be sorted based on
+// creation timestamp.
+TEST_F(ScheduledNotificationManagerTest, GetAllNotifications) {
+  // Ordering: entry1.create_time < entry0.create_time < entry2.create_time.
+  auto now = base::Time::Now();
+  auto entry0 = CreateNotificationEntry();
+  entry0.create_time = now;
+  auto entry1 = CreateNotificationEntry();
+  entry1.create_time = now - base::TimeDelta::FromMinutes(1);
+  auto entry2 = CreateNotificationEntry();
+  entry2.create_time = now + base::TimeDelta::FromMinutes(1);
+
+  InitWithData(std::vector<NotificationEntry>({entry0, entry1, entry2}));
+  ScheduledNotificationManager::Notifications notifications;
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 1u);
+  EXPECT_EQ(notifications.begin()->second.size(), 3u);
+
+  // Entries returned by GetAllNotifications() should be sorted by creation
+  // timestamp.
+  const NotificationEntry* output0 = notifications.begin()->second.front();
+  const NotificationEntry* output2 = notifications.begin()->second.back();
+  EXPECT_EQ(output0->create_time, entry1.create_time);
+  EXPECT_EQ(output2->create_time, entry2.create_time);
+}
+
+}  // namespace
+}  // namespace notifications
diff --git a/chrome/browser/profiling_host/memlog_browsertest.cc b/chrome/browser/profiling_host/memlog_browsertest.cc
index 074f641..89a5a19e 100644
--- a/chrome/browser/profiling_host/memlog_browsertest.cc
+++ b/chrome/browser/profiling_host/memlog_browsertest.cc
@@ -34,7 +34,6 @@
 struct TestParam {
   Mode mode;
   mojom::StackMode stack_mode;
-  bool stream_samples;
   bool start_profiling_with_command_line_flag;
   bool should_sample;
   bool sample_everything;
@@ -45,11 +44,6 @@
   void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
     InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
 
-    if (GetParam().stream_samples) {
-      command_line->AppendSwitchASCII(heap_profiling::kMemlogInProcess,
-                                      heap_profiling::kMemlogInProcessDisabled);
-    }
-
     if (!GetParam().start_profiling_with_command_line_flag)
       return;
 
@@ -99,7 +93,6 @@
 IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, MAYBE_EndToEnd) {
   LOG(INFO) << "Memlog mode: " << static_cast<int>(GetParam().mode);
   LOG(INFO) << "Memlog stack mode: " << static_cast<int>(GetParam().stack_mode);
-  LOG(INFO) << "Stream samples: " << GetParam().stream_samples;
   LOG(INFO) << "Started via command line flag: "
             << GetParam().start_profiling_with_command_line_flag;
   LOG(INFO) << "Should sample: " << GetParam().should_sample;
@@ -108,7 +101,6 @@
   TestDriver::Options options;
   options.mode = GetParam().mode;
   options.stack_mode = GetParam().stack_mode;
-  options.stream_samples = GetParam().stream_samples;
   options.profiling_already_started =
       GetParam().start_profiling_with_command_line_flag;
   options.should_sample = GetParam().should_sample;
@@ -132,10 +124,12 @@
   stack_modes.push_back(mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES);
   stack_modes.push_back(mojom::StackMode::PSEUDO);
 
-  for (bool stream_samples : (bool[]){true, false}) {
+  // TODO(https://crbug.com/923459): The outer loop is left in place to keep
+  // the parameterized tests order. Remove it in a follow-up patch.
+  for (int i = 0; i < 2; ++i) {
     for (const auto& mode : dynamic_start_modes) {
       for (const auto& stack_mode : stack_modes) {
-        params.push_back({mode, stack_mode, stream_samples,
+        params.push_back({mode, stack_mode,
                           false /* start_profiling_with_command_line_flag */,
                           true /* should_sample */,
                           false /* sample_everything*/});
@@ -155,7 +149,7 @@
     command_line_start_modes.push_back(Mode::kAllRenderers);
     for (const auto& mode : command_line_start_modes) {
       for (const auto& stack_mode : stack_modes) {
-        params.push_back({mode, stack_mode, stream_samples,
+        params.push_back({mode, stack_mode,
                           true /* start_profiling_with_command_line_flag */,
                           true /* should_sample */,
                           false /* sample_everything*/});
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.cc b/chrome/browser/resource_coordinator/tab_load_tracker.cc
index ec9ca2a..143e001 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker.cc
+++ b/chrome/browser/resource_coordinator/tab_load_tracker.cc
@@ -223,8 +223,10 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // TabManager::ResourceCoordinatorSignalObserver filters late notifications
   // so here we can assume the event pertains to a live web_contents and
-  // its most recent navigation.
-  DCHECK(base::ContainsKey(tabs_, web_contents));
+  // its most recent navigation. However, the graph tracks contents that aren't
+  // tracked by this object.
+  if (!base::ContainsKey(tabs_, web_contents))
+    return;
 
   MaybeTransitionToLoaded(web_contents);
 }
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.h b/chrome/browser/resource_coordinator/tab_load_tracker.h
index c16a0aab..92e97de 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker.h
+++ b/chrome/browser/resource_coordinator/tab_load_tracker.h
@@ -151,9 +151,8 @@
   void RenderProcessGone(content::WebContents* web_contents,
                          base::TerminationStatus status);
 
-  // This is an analog of a PageSignalObserver function. This class is not
-  // actually a PageSignalObserver, but these notifications are forwarded to it
-  // from the TabManager.
+  // Notifications to this are driven by the
+  // TabManager::ResourceCoordinatorSignalObserver.
   void OnPageAlmostIdle(content::WebContents* web_contents);
 
   // Returns true if |web_contents| is a UI tab and false otherwise. This is
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index e73da5d..fa636cd 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -183,10 +183,22 @@
 #endif
   browser_tab_strip_tracker_.Init();
   session_restore_observer_.reset(new TabManagerSessionRestoreObserver(this));
-  if (performance_manager::PerformanceManager::GetInstance()) {
-    resource_coordinator_signal_observer_.reset(
-        new ResourceCoordinatorSignalObserver(page_signal_receiver));
+
+  // Create the graph observer. This is the source of page almost idle data and
+  // EQT measurements.
+  if (auto* perf_man = performance_manager::PerformanceManager::GetInstance()) {
+    // The performance manager is torn down on its own sequence so its safe to
+    // pass it unretained. The observer itself learns of the tab manager tear
+    // down via the weak ptr it is given.
+    perf_man->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &performance_manager::PerformanceManager::RegisterObserver,
+            base::Unretained(perf_man),
+            std::make_unique<ResourceCoordinatorSignalObserver>(
+                weak_ptr_factory_.GetWeakPtr())));
   }
+
   stats_collector_.reset(new TabManagerStatsCollector());
   proactive_freeze_discard_params_ =
       GetStaticProactiveTabFreezeAndDiscardParams();
@@ -200,7 +212,6 @@
 
 TabManager::~TabManager() {
   tab_load_tracker_->RemoveObserver(this);
-  resource_coordinator_signal_observer_.reset();
 
   if (metrics::DesktopSessionDurationTracker::IsInitialized())
     metrics::DesktopSessionDurationTracker::Get()->RemoveObserver(this);
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index bf78f2d4..6186551 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -480,11 +480,6 @@
   // in parallel.
   size_t loading_slots_;
 
-  // |resource_coordinator_signal_observer_| is owned by TabManager and is used
-  // to receive various signals from ResourceCoordinator.
-  std::unique_ptr<ResourceCoordinatorSignalObserver>
-      resource_coordinator_signal_observer_;
-
   // Records UMAs for tab and system-related events and properties during
   // session restore.
   std::unique_ptr<TabManagerStatsCollector> stats_collector_;
diff --git a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
index f7eee2104..8675564 100644
--- a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
@@ -4,13 +4,19 @@
 
 #include "chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h"
 
+#include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
+#include "chrome/browser/performance_manager/graph/page_node_impl.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 #include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/utils.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace resource_coordinator {
 
@@ -20,53 +26,100 @@
 class TabManagerResourceCoordinatorSignalObserverHelper {
  public:
   static void OnPageAlmostIdle(content::WebContents* web_contents) {
+    // This object is create on demand, so always exists.
     TabLoadTracker::Get()->OnPageAlmostIdle(web_contents);
   }
 };
 
 TabManager::ResourceCoordinatorSignalObserver::
-    ResourceCoordinatorSignalObserver(PageSignalReceiver* page_signal_receiver)
-    : page_signal_receiver_(page_signal_receiver) {
-  if (page_signal_receiver_)
-    page_signal_receiver_->AddObserver(this);
-}
+    ResourceCoordinatorSignalObserver(
+        const base::WeakPtr<TabManager>& tab_manager)
+    : tab_manager_(tab_manager) {}
 
 TabManager::ResourceCoordinatorSignalObserver::
-    ~ResourceCoordinatorSignalObserver() {
-  if (page_signal_receiver_)
-    page_signal_receiver_->RemoveObserver(this);
+    ~ResourceCoordinatorSignalObserver() = default;
+
+bool TabManager::ResourceCoordinatorSignalObserver::ShouldObserve(
+    const NodeBase* node) {
+  return node->id().type == resource_coordinator::CoordinationUnitType::kPage ||
+         node->id().type ==
+             resource_coordinator::CoordinationUnitType::kProcess;
 }
 
-void TabManager::ResourceCoordinatorSignalObserver::OnPageAlmostIdle(
-    content::WebContents* web_contents,
-    const PageNavigationIdentity& page_navigation_id) {
-  DCHECK_NE(nullptr, page_signal_receiver_);
-
-  // Only dispatch the event if it pertains to the current navigation.
-  if (page_signal_receiver_->GetNavigationIDForWebContents(web_contents) ==
-      page_navigation_id.navigation_id) {
-    TabManagerResourceCoordinatorSignalObserverHelper::OnPageAlmostIdle(
-        web_contents);
-  }
+void TabManager::ResourceCoordinatorSignalObserver::OnPageAlmostIdleChanged(
+    PageNodeImpl* page_node) {
+  // Only notify of changes to almost idle.
+  if (!page_node->page_almost_idle())
+    return;
+  // Forward the notification over to the UI thread.
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&OnPageAlmostIdleOnUi, tab_manager_,
+                     page_node->contents_proxy(), page_node->navigation_id()));
 }
 
 void TabManager::ResourceCoordinatorSignalObserver::
-    OnExpectedTaskQueueingDurationSet(
-        content::WebContents* web_contents,
-        const PageNavigationIdentity& page_navigation_id,
-        base::TimeDelta duration) {
-  DCHECK_NE(nullptr, page_signal_receiver_);
+    OnExpectedTaskQueueingDurationSample(ProcessNodeImpl* process_node) {
+  // Report this measurement to all pages that are hosting a main frame in
+  // the process that was sampled.
+  const base::TimeDelta& duration =
+      process_node->expected_task_queueing_duration();
+  for (auto* frame_node : process_node->GetFrameNodes()) {
+    if (!frame_node->IsMainFrame())
+      continue;
+    auto* page_node = frame_node->page_node();
 
-  if (page_signal_receiver_->GetNavigationIDForWebContents(web_contents) !=
-      page_navigation_id.navigation_id) {
-    // |web_contents| has been re-navigated, drop this notification rather than
-    // recording it against the wrong origin.
-    return;
+    // Forward the notification over to the UI thread.
+    base::PostTaskWithTraits(
+        FROM_HERE, {content::BrowserThread::UI},
+        base::BindOnce(&OnExpectedTaskQueueingDurationSampleOnUi, tab_manager_,
+                       page_node->contents_proxy(), page_node->navigation_id(),
+                       duration));
   }
+}
 
-  g_browser_process->GetTabManager()
-      ->stats_collector()
-      ->RecordExpectedTaskQueueingDuration(web_contents, duration);
+// static
+content::WebContents*
+TabManager::ResourceCoordinatorSignalObserver::GetContentsForDispatch(
+    const base::WeakPtr<TabManager>& tab_manager,
+    const base::WeakPtr<WebContentsProxy>& contents_proxy,
+    int64_t navigation_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!tab_manager.get() || !contents_proxy.get() ||
+      contents_proxy.get()->LastNavigationId() != navigation_id) {
+    return nullptr;
+  }
+  return contents_proxy.get()->GetWebContents();
+}
+
+// static
+void TabManager::ResourceCoordinatorSignalObserver::OnPageAlmostIdleOnUi(
+    const base::WeakPtr<TabManager>& tab_manager,
+    const base::WeakPtr<WebContentsProxy>& contents_proxy,
+    int64_t navigation_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (auto* contents =
+          GetContentsForDispatch(tab_manager, contents_proxy, navigation_id)) {
+    TabManagerResourceCoordinatorSignalObserverHelper::OnPageAlmostIdle(
+        contents);
+  }
+}
+
+// static
+void TabManager::ResourceCoordinatorSignalObserver::
+    OnExpectedTaskQueueingDurationSampleOnUi(
+        const base::WeakPtr<TabManager>& tab_manager,
+        const base::WeakPtr<WebContentsProxy>& contents_proxy,
+        int64_t navigation_id,
+        base::TimeDelta duration) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (auto* contents =
+          GetContentsForDispatch(tab_manager, contents_proxy, navigation_id)) {
+    // This object is create on demand, so always exists.
+    g_browser_process->GetTabManager()
+        ->stats_collector()
+        ->RecordExpectedTaskQueueingDuration(contents, duration);
+  }
 }
 
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h
index 778ba64..43782e5 100644
--- a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h
+++ b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_RESOURCE_COORDINATOR_SIGNAL_OBSERVER_H_
 
 #include "base/macros.h"
+#include "chrome/browser/performance_manager/observers/graph_observer.h"
+#include "chrome/browser/performance_manager/web_contents_proxy.h"
 #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 
@@ -15,24 +17,54 @@
 // interfaces, for example it currently implements PageSignalObserver but can
 // implement more; and receives signals from resource coordinator through those
 // interfaces.
+// TODO(chrisha): Kill this thing entirely and move all of tab manager into the
+// performance manager.
 class TabManager::ResourceCoordinatorSignalObserver
-    : public PageSignalObserver {
+    : public performance_manager::GraphObserver {
  public:
+  using NodeBase = performance_manager::NodeBase;
+  using PageNodeImpl = performance_manager::PageNodeImpl;
+  using ProcessNodeImpl = performance_manager::ProcessNodeImpl;
+  using WebContentsProxy = performance_manager::WebContentsProxy;
+
   explicit ResourceCoordinatorSignalObserver(
-      PageSignalReceiver* page_signal_receiver);
+      const base::WeakPtr<TabManager>& tab_manager);
   ~ResourceCoordinatorSignalObserver() override;
 
-  // PageSignalObserver implementation.
-  void OnPageAlmostIdle(
-      content::WebContents* web_contents,
-      const PageNavigationIdentity& page_navigation_id) override;
-  void OnExpectedTaskQueueingDurationSet(
-      content::WebContents* web_contents,
-      const PageNavigationIdentity& page_navigation_id,
-      base::TimeDelta duration) override;
+  // GraphObserver:
+  // These functions run on the performance manager sequence.
+  bool ShouldObserve(const NodeBase* node) override;
+  void OnPageAlmostIdleChanged(PageNodeImpl* page_node) override;
+  void OnExpectedTaskQueueingDurationSample(
+      ProcessNodeImpl* process_node) override;
 
  private:
-  PageSignalReceiver* const page_signal_receiver_;
+  // Determines if a message should still be dispatched for the given
+  // |tab_manager|, |contents_proxy| and |navigation_id|. If so, returns the
+  // WebContents, otherwise returns nullptr. This should only be called on the
+  // UI thread.
+  static content::WebContents* GetContentsForDispatch(
+      const base::WeakPtr<TabManager>& tab_manager,
+      const base::WeakPtr<WebContentsProxy>& contents_proxy,
+      int64_t navigation_id);
+
+  // Equivalent to the the GraphObserver functions above, but these are the
+  // counterparts that run on the UI thread.
+  static void OnPageAlmostIdleOnUi(
+      const base::WeakPtr<TabManager>& tab_manager,
+      const base::WeakPtr<WebContentsProxy>& contents_proxy,
+      int64_t navigation_id);
+  static void OnExpectedTaskQueueingDurationSampleOnUi(
+      const base::WeakPtr<TabManager>& tab_manager,
+      const base::WeakPtr<WebContentsProxy>& contents_proxy,
+      int64_t navigation_id,
+      base::TimeDelta duration);
+
+  // Can only be dereferenced on the UI thread. When the tab manager dies this
+  // is used to drop messages received from the performance manager. Ideally
+  // we'd also then tear down this observer on the perf manager sequence itself,
+  // but when one dies they're both about to die.
+  base::WeakPtr<TabManager> tab_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorSignalObserver);
 };
diff --git a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html
index 76b33c6..5e56d30 100644
--- a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html
+++ b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html
@@ -37,7 +37,8 @@
       </style>
 
       <bluetooth-dialog id="deviceDialog" no-cancel on-close="onDialogClose_"
-          pairing-device="[[pairingDevice_]]">
+          pairing-device="[[pairingDevice_]]"
+          dialog-title="$i18n{bluetoothPairDeviceTitle}">
       </bluetooth-dialog>
     </template>
     <script src="bluetooth_pairing_dialog.js"></script>
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
index ada6cbc..417f625 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
@@ -266,14 +266,17 @@
 
   var root = this.node_.root;
   if (!root || !root.selectionStartObject || !root.selectionEndObject ||
-      root.selectionStartOffset === undefined ||
-      root.selectionEndOffset === undefined)
+      !root.focusObject || root.selectionStartOffset === undefined ||
+      root.selectionEndOffset === undefined || root.focusOffset === undefined)
     return;
 
-  this.anchorLine_ = new editing.EditableLine(
+  this.startLine_ = new editing.EditableLine(
       root.selectionStartObject, root.selectionStartOffset,
       root.selectionStartObject, root.selectionStartOffset);
-  this.focusLine_ = new editing.EditableLine(
+
+  // TODO(nektar): |focus| below should be |end|. Change once new selection code
+  // lands.
+  this.endLine_ = new editing.EditableLine(
       root.focusObject, root.focusOffset, root.focusObject, root.focusOffset);
 
   this.line_ = new editing.EditableLine(
@@ -361,27 +364,30 @@
   onUpdate: function(eventFrom) {
     var root = this.node_.root;
     if (!root.selectionStartObject || !root.selectionEndObject ||
-        root.selectionStartOffset === undefined ||
-        root.selectionEndOffset === undefined)
+        !root.focusObject || root.selectionStartOffset === undefined ||
+        root.selectionEndOffset === undefined || root.focusOffset === undefined)
       return;
 
-    var anchorLine = new editing.EditableLine(
+    var startLine = new editing.EditableLine(
         root.selectionStartObject, root.selectionStartOffset,
         root.selectionStartObject, root.selectionStartOffset);
-    var focusLine = new editing.EditableLine(
+
+    // TODO(nektar): |focus| below should be |end|. Change once new selection
+    // code lands.
+    var endLine = new editing.EditableLine(
         root.focusObject, root.focusOffset, root.focusObject, root.focusOffset);
 
-    var prevAnchorLine = this.anchorLine_;
-    var prevFocusLine = this.focusLine_;
-    this.anchorLine_ = anchorLine;
-    this.focusLine_ = focusLine;
+    var prevStartLine = this.startLine_;
+    var prevEndLine = this.endLine_;
+    this.startLine_ = startLine;
+    this.endLine_ = endLine;
 
     // Compute the current line based upon whether the current selection was
     // extended from anchor or focus. The default behavior is to compute lines
     // via focus.
-    var baseLineOnStart = prevFocusLine.isSameLineAndSelection(focusLine);
+    var baseLineOnStart = prevEndLine.isSameLineAndSelection(endLine);
     var isSameSelection =
-        baseLineOnStart && prevAnchorLine.isSameLineAndSelection(anchorLine);
+        baseLineOnStart && prevStartLine.isSameLineAndSelection(startLine);
 
     var cur;
     if (isSameSelection && this.line_) {
@@ -411,8 +417,8 @@
 
     // We must validate the previous lines as state changes in the accessibility
     // tree may have invalidated the lines.
-    if (anchorLine.isSameLine(prevAnchorLine) &&
-        focusLine.isSameLine(prevFocusLine)) {
+    if (startLine.isSameLine(prevStartLine) &&
+        endLine.isSameLine(prevEndLine)) {
       // Intra-line changes.
       var text = cur.text;
       if (text == '\n')
@@ -462,14 +468,14 @@
     // unordered (i.e. anchor is where the selection starts and focus
     // where it ends). The latter is correct. Change this once Blink
     // ax gets fixed.
-    var curBase = baseLineOnStart ? focusLine : anchorLine;
+    var curBase = baseLineOnStart ? endLine : startLine;
 
     if ((cur.startContainer_.role == RoleType.TEXT_FIELD ||
          (cur.startContainer_ == prev.startContainer_ &&
           cur.endContainer_ == prev.endContainer_)) &&
         cur.startContainerValue_ != prev.startContainerValue_) {
       // This block catches text changes between |prev| and | cur|. Note that we
-      // can end up here if |prevAnchorLine| or |prevFocusLine| were invalid
+      // can end up here if |prevStartLine| or |prevEndLine| were invalid
       // above for intra-line changes. This block therefore catches all text
       // changes including those that occur within a single line and up to those
       // that occur within a static text. It also catches text changes that
@@ -497,12 +503,12 @@
           .go();
     } else if (
         !cur.hasCollapsedSelection() &&
-        (curBase.isSameLine(prevAnchorLine) ||
-         curBase.isSameLine(prevFocusLine))) {
+        (curBase.isSameLine(prevStartLine) ||
+         curBase.isSameLine(prevEndLine))) {
       // This is a selection that gets extended from the same anchor.
 
       // Speech requires many more states than braille.
-      var curExtent = baseLineOnStart ? anchorLine : focusLine;
+      var curExtent = baseLineOnStart ? startLine : endLine;
       var text = '';
       var suffixMsg = '';
       if (curBase.isBeforeLine(curExtent)) {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
index 83f58f71..1757d55 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
@@ -113,6 +113,8 @@
           loadTimeData.getString('controlledSettingWithOwner'),
       controlledSettingNoOwner:
           loadTimeData.getString('controlledSettingNoOwner'),
+      controlledSettingParent:
+          loadTimeData.getString('controlledSettingParent'),
     };
 
     CrOncStrings = {
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 2d14eb3..291bf5c 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -114,6 +114,8 @@
           loadTimeData.getString('controlledSettingWithOwner'),
       controlledSettingNoOwner:
           loadTimeData.getString('controlledSettingNoOwner'),
+      controlledSettingParent:
+          loadTimeData.getString('controlledSettingParent'),
       // </if>
     };
 
diff --git a/chrome/browser/search/README.md b/chrome/browser/search/README.md
index ca61a61..567ce33 100644
--- a/chrome/browser/search/README.md
+++ b/chrome/browser/search/README.md
@@ -7,10 +7,7 @@
 variants are implemented as HTML/CSS/JS, but differ in where they are
 hosted.
 
-*   **Google**: either the **[Remote NTP][remote-ntp]** (as of
-    2017-12-05, the default) or the **[Local NTP][local-ntp]**, with
-    Google branding (as of 2017-12-05, planned to replace the Remote NTP
-    and in experiments on Beta).
+*   **Google**: The **[Local NTP][local-ntp]**, with Google branding.
 
 *   **Bing**, **Yandex**: a **[Third-Party NTP][third-party-ntp]**,
     where the NTP is hosted on third-party servers but Chrome provides
@@ -32,7 +29,6 @@
 the "Add shortcut" button, deleting/editing shortcuts from the three-dot "Edit
 shortcut" menu (replaces the "X" button), and reordering via click-and-drag.
 
-[remote-ntp]:       #remote-ntp
 [local-ntp]:        #local-ntp
 [third-party-ntp]:  #third_party-ntp
 [engines]:          https://chromium.googlesource.com/chromium/src/+/master/components/search_engines/prepopulated_engines.json
@@ -149,11 +145,6 @@
 A non-Google local NTP shows only NTP tiles, with no branding. The tiles
 are centered within the page.
 
-### Remote NTP
-
-The Remote NTP is hosted on Google servers. It is intended for removal,
-and is not documented here.
-
 ### Third-Party NTP
 
 TODO(sfiera)
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc
index b1ed01e5..8b31555 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc
@@ -41,7 +41,9 @@
   // Waits for all tasks in to finish.
   void Wait() { scoped_task_environment_.RunUntilIdle(); }
 
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+      base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED};
   base::ScopedTempDir temp_dir_;
   base::test::ScopedFeatureList scoped_feature_list_;
 };
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
index caee110..d4bf60de 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
@@ -67,7 +67,9 @@
   }
 
   RecurrenceRankerConfigProto config_;
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+      base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED};
   base::ScopedTempDir temp_dir_;
   base::test::ScopedFeatureList scoped_feature_list_;
 
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 8441002..1979aab 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -331,8 +331,10 @@
 
   const uint16_t browser_index = GetBrowserIndex(command_id);
   // Check that the index is valid and the browser has not been closed.
+  // It's unclear why, but the browser's window may be null: crbug.com/937088
   if (browser_index < browser_menu_items_.size() &&
-      browser_menu_items_[browser_index]) {
+      browser_menu_items_[browser_index] &&
+      browser_menu_items_[browser_index]->window()) {
     Browser* browser = browser_menu_items_[browser_index];
     TabStripModel* tab_strip = browser->tab_strip_model();
     const uint16_t tab_index = GetWebContentsIndex(command_id);
@@ -344,10 +346,6 @@
                                       TabStripModel::CLOSE_USER_GESTURE);
       }
     } else {
-      // These extra checks should gather info for http://crbug.com/937088
-      CHECK(browser);
-      CHECK(browser->window());
-      CHECK(browser->window()->GetNativeWindow());
       multi_user_util::MoveWindowToCurrentDesktop(
           browser->window()->GetNativeWindow());
       if (tab_index != kNoTab && tab_strip->ContainsIndex(tab_index))
diff --git a/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc
index e19d00b..449ca75 100644
--- a/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc
@@ -35,16 +35,23 @@
 
   // UIPerformanceTest:
   std::vector<std::string> GetUMAHistogramNames() const override {
+    DCHECK(!suffix_.empty());
     return {
-        "Apps.StateTransition.AnimationSmoothness.ClamshellMode",
+        std::string("Apps.StateTransition.AnimationSmoothness.") + suffix_,
     };
   }
 
+ protected:
+  void set_suffix(const std::string& suffix) { suffix_ = suffix; }
+
  private:
+  std::string suffix_;
+
   DISALLOW_COPY_AND_ASSIGN(LauncherAnimationsTest);
 };
 
 IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, Fullscreen) {
+  set_suffix("FullscreenAllApps.ClamshellMode");
   // Browser window is used to identify display, so we can use
   // use the 1st browser window regardless of number of windows created.
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
@@ -76,6 +83,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, Peeking) {
+  set_suffix("Peeking.ClamshellMode");
   // Browser window is used to identify display, so we can use
   // use the 1st browser window regardless of number of windows created.
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index 3601441..6d36b63 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -66,6 +66,12 @@
 
 const char kHashMark[] = "#";
 
+void FocusWebContents(Browser* browser) {
+  auto* const contents = browser->tab_strip_model()->GetActiveWebContents();
+  if (contents)
+    contents->Focus();
+}
+
 void OpenBookmarkManagerForNode(Browser* browser, int64_t node_id) {
   GURL url = GURL(kChromeUIBookmarksURL)
                  .Resolve(base::StringPrintf(
@@ -314,6 +320,11 @@
 void ShowSettingsSubPageInTabbedBrowser(Browser* browser,
                                         const std::string& sub_page) {
   base::RecordAction(UserMetricsAction("ShowOptions"));
+
+  // Since the user may be triggering navigation from another UI element such as
+  // a menu, ensure the web contents (and therefore the settings page that is
+  // about to be shown) is focused. (See crbug/926492 for motivation.)
+  FocusWebContents(browser);
   GURL gurl = GetSettingsUrl(sub_page);
   NavigateParams params(GetSingletonTabNavigateParams(browser, gurl));
   params.path_behavior = NavigateParams::IGNORE_AND_NAVIGATE;
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.h b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.h
index aab52b7..e908066 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.h
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.h
@@ -14,10 +14,6 @@
 class Browser;
 @class BrowserWindowTouchBarController;
 
-namespace content {
-class WebContents;
-}
-
 // Provides a default touch bar for the browser window. This class implements
 // the NSTouchBarDelegate and handles the items in the touch bar.
 API_AVAILABLE(macos(10.12.2))
@@ -29,19 +25,19 @@
 // True if the current page is starred. Used by star touch bar button.
 @property(nonatomic, assign) BOOL isStarred;
 
-// Designated initializer.
-- (instancetype)initWithBrowser:(Browser*)browser
-                     controller:(BrowserWindowTouchBarController*)controller;
+// True if the back button is enabled.
+@property(nonatomic, assign) BOOL canGoBack;
+
+// True if the forward button is enabled.
+@property(nonatomic, assign) BOOL canGoForward;
+
+@property(nonatomic, assign) BrowserWindowTouchBarController* controller;
+
+@property(nonatomic) Browser* browser;
 
 // Creates and returns a touch bar for the browser window.
 - (NSTouchBar*)makeTouchBar;
 
-- (void)updateWebContents:(content::WebContents*)contents;
-
-// Updates the back/forward button. Called when creating the touch bar or when
-// the back and forward commands have changed.
-- (void)updateBackForwardControl;
-
 - (BrowserWindowTouchBarController*)controller;
 
 @end
@@ -49,6 +45,11 @@
 // Private methods exposed for testing.
 @interface BrowserWindowDefaultTouchBar (ExposedForTesting)
 
+@property(readonly, class) NSString* reloadOrStopItemIdentifier;
+@property(readonly, class) NSString* backItemIdentifier;
+@property(readonly, class) NSString* forwardItemIdentifier;
+@property(readonly, class) NSString* fullscreenOriginItemIdentifier;
+
 // Updates the reload/stop button. Called when creating the touch bar or the
 // page load state has been updated.
 - (void)updateReloadStopButton;
@@ -56,10 +57,6 @@
 // Returns the reload/stop button on the touch bar. Creates it if it's null.
 - (NSButton*)reloadStopButton;
 
-// Returns the back/forward segmented control on the touch bar. Creates it if
-// it's null.
-- (NSSegmentedControl*)backForwardControl;
-
 // Returns the bridge object that BrowserWindowDefaultTouchBar uses to receive
 // notifications.
 - (BookmarkTabHelperObserver*)bookmarkTabObserver;
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
index 84099212..936f484e 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
@@ -13,6 +13,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/command_observer.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/profiles/profile.h"
@@ -32,6 +33,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
 #include "components/vector_icons/vector_icons.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #import "skia/ext/skia_utils_mac.h"
@@ -51,7 +53,8 @@
 NSString* const kTabFullscreenTouchBarId = @"tab-fullscreen";
 
 // Touch bar items identifiers.
-NSString* const kBackForwardTouchId = @"BACK-FWD";
+NSString* const kBackTouchId = @"BACK";
+NSString* const kForwardTouchId = @"FORWARD";
 NSString* const kReloadOrStopTouchId = @"RELOAD-STOP";
 NSString* const kHomeTouchId = @"HOME";
 NSString* const kSearchTouchId = @"SEARCH";
@@ -59,9 +62,11 @@
 NSString* const kNewTabTouchId = @"NEW-TAB";
 NSString* const kFullscreenOriginLabelTouchId = @"FULLSCREEN-ORIGIN-LABEL";
 
-// The button indexes in the back and forward segment control.
-const int kBackSegmentIndex = 0;
-const int kForwardSegmentIndex = 1;
+// This is a combined back and forward control which can no longer be selected
+// but may be in an existing customized Touch Bar. It now represents a group
+// containing the back and forward buttons, and adding the back or forward
+// buttons to the Touch Bar individually magically decomposes the group.
+NSString* const kBackForwardTouchId = @"BACK-FWD";
 
 // Touch bar icon colors values.
 const SkColor kTouchBarDefaultIconColor = SK_ColorWHITE;
@@ -95,7 +100,7 @@
                          target:owner
                          action:@selector(executeCommand:)];
   button.tag = command;
-  [button setAccessibilityLabel:l10n_util::GetNSString(tooltip_id)];
+  button.accessibilityTitle = l10n_util::GetNSString(tooltip_id);
   return button;
 }
 
@@ -128,6 +133,8 @@
 class API_AVAILABLE(macos(10.12.2)) TouchBarNotificationBridge
     : public CommandObserver,
       public BookmarkTabHelperObserver,
+      public TabStripModelObserver,
+      public content::NotificationObserver,
       public content::WebContentsObserver {
  public:
   TouchBarNotificationBridge(BrowserWindowDefaultTouchBar* owner,
@@ -135,48 +142,93 @@
       : owner_(owner), browser_(browser), contents_(nullptr) {
     TabStripModel* model = browser_->tab_strip_model();
     DCHECK(model);
-
+    model->AddObserver(this);
     UpdateWebContents(model->GetActiveWebContents());
+
+    auto* command_controller = browser->command_controller();
+    command_controller->AddCommandObserver(IDC_BACK, this);
+    owner.canGoBack = command_controller->IsCommandEnabled(IDC_BACK);
+    command_controller->AddCommandObserver(IDC_FORWARD, this);
+    owner.canGoBack = command_controller->IsCommandEnabled(IDC_FORWARD);
+
+    auto* profile = browser->profile();
+    auto* prefs = profile->GetPrefs();
+    show_home_button_.Init(
+        prefs::kShowHomeButton, prefs,
+        base::BindRepeating(&TouchBarNotificationBridge::UpdateTouchBar,
+                            base::Unretained(this)));
+
+    profile_pref_registrar_.Init(prefs);
+    profile_pref_registrar_.Add(
+        DefaultSearchManager::kDefaultSearchProviderDataPrefName,
+        base::BindRepeating(&TouchBarNotificationBridge::UpdateTouchBar,
+                            base::Unretained(this)));
+
+    notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
+                                content::Source<Profile>(profile));
   }
 
+  bool show_home_button() { return show_home_button_.GetValue(); }
+
   ~TouchBarNotificationBridge() override {
-    if (contents_)
-      BookmarkTabHelper::FromWebContents(contents_)->RemoveObserver(this);
+    browser_->tab_strip_model()->RemoveObserver(this);
+    UpdateWebContents(nullptr);
   }
 
   void UpdateTouchBar() { [[owner_ controller] invalidateTouchBar]; }
 
   void UpdateWebContents(content::WebContents* new_contents) {
-    if (contents_) {
+    if (contents_ == new_contents)
+      return;
+    if (contents_)
       BookmarkTabHelper::FromWebContents(contents_)->RemoveObserver(this);
-    }
 
     contents_ = new_contents;
-    Observe(contents_);
 
-    bool is_starred = false;
-    if (contents_) {
-      BookmarkTabHelper* helper = BookmarkTabHelper::FromWebContents(contents_);
-      helper->AddObserver(this);
-      is_starred = helper->is_starred();
-    }
+    // Stop observing the old WebContents and start observing the new one (if
+    // nonnull). Qualified to disambiguate from NotificationObserver::Observe().
+    WebContentsObserver::Observe(contents_);
 
-    [owner_ setIsPageLoading:contents_ && contents_->IsLoading()];
-    [owner_ setIsStarred:is_starred];
+    BookmarkTabHelper* bookmark_helper =
+        contents_ ? BookmarkTabHelper::FromWebContents(contents_) : nullptr;
+    if (bookmark_helper)
+      bookmark_helper->AddObserver(this);
+
+    owner_.isPageLoading = contents_ && contents_->IsLoading();
+    owner_.isStarred = bookmark_helper && bookmark_helper->is_starred();
+    UpdateTouchBar();
   }
 
   // BookmarkTabHelperObserver:
   void URLStarredChanged(content::WebContents* web_contents,
                          bool starred) override {
     DCHECK(web_contents == contents_);
-    [owner_ setIsStarred:starred];
+    owner_.isStarred = starred;
   }
 
  protected:
   // CommandObserver:
   void EnabledStateChangedForCommand(int command, bool enabled) override {
     DCHECK(command == IDC_BACK || command == IDC_FORWARD);
-    [owner_ updateBackForwardControl];
+    if (command == IDC_BACK)
+      owner_.canGoBack = enabled;
+    else if (command == IDC_FORWARD)
+      owner_.canGoForward = enabled;
+  }
+
+  // TabStripModelObserver:
+  void OnTabStripModelChanged(
+      TabStripModel* tab_strip_model,
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override {
+    UpdateWebContents(selection.new_contents);
+  }
+
+  // NotificationObserver:
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override {
+    owner_.browser = nullptr;
   }
 
   // WebContentsObserver:
@@ -187,52 +239,40 @@
 
   void DidStartLoading() override {
     DCHECK(contents_ && contents_->IsLoading());
-    [owner_ setIsPageLoading:YES];
+    owner_.isPageLoading = YES;
   }
 
   void DidStopLoading() override {
     DCHECK(contents_ && !contents_->IsLoading());
-    [owner_ setIsPageLoading:NO];
+    owner_.isPageLoading = NO;
   }
 
+  void WebContentsDestroyed() override { UpdateWebContents(nullptr); }
+
  private:
   BrowserWindowDefaultTouchBar* owner_;  // Weak.
   Browser* browser_;                     // Weak.
   content::WebContents* contents_;       // Weak.
 
+  // Used to monitor the optional home button pref.
+  BooleanPrefMember show_home_button_;
+
+  content::NotificationRegistrar notification_registrar_;
+
+  PrefChangeRegistrar profile_pref_registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(TouchBarNotificationBridge);
 };
 
-id<NSAccessibility> ToNSAccessibility(id object) {
-  return [object conformsToProtocol:@protocol(NSAccessibility)] ? object : nil;
-}
-
 }  // namespace
 
 @interface BrowserWindowDefaultTouchBar () {
-  // Used to execute commands such as navigating back and forward.
-  CommandUpdater* commandUpdater_;  // Weak, owned by Browser.
-
-  // The browser associated with the touch bar.
-  Browser* browser_;  // Weak.
-
-  BrowserWindowTouchBarController* controller_;  // Weak.
-
-  // Used to monitor the optional home button pref.
-  BooleanPrefMember showHomeButton_;
-
-  // Used to listen for default search engine pref changes.
-  PrefChangeRegistrar profilePrefRegistrar_;
-
   // Used to receive and handle notifications.
   std::unique_ptr<TouchBarNotificationBridge> notificationBridge_;
 
   // The stop/reload button in the touch bar.
   base::scoped_nsobject<NSButton> reloadStopButton_;
 
-  // The back/forward segmented control in the touch bar.
-  base::scoped_nsobject<NSSegmentedControl> backForwardControl_;
-
   // The starred button in the touch bar.
   base::scoped_nsobject<NSButton> starredButton_;
 }
@@ -240,9 +280,6 @@
 // Creates and returns a touch bar for tab fullscreen mode.
 - (NSTouchBar*)createTabFullscreenTouchBar;
 
-// Sets up the back and forward segmented control.
-- (void)setupBackForwardControl;
-
 // Updates the starred button in the touch bar.
 - (void)updateStarredButton;
 
@@ -255,35 +292,10 @@
 
 @synthesize isPageLoading = isPageLoading_;
 @synthesize isStarred = isStarred_;
-
-- (instancetype)initWithBrowser:(Browser*)browser
-                     controller:(BrowserWindowTouchBarController*)controller {
-  if ((self = [super init])) {
-    DCHECK(browser);
-    browser_ = browser;
-    controller_ = controller;
-
-    notificationBridge_.reset(new TouchBarNotificationBridge(self, browser));
-
-    commandUpdater_ = browser->command_controller();
-    commandUpdater_->AddCommandObserver(IDC_BACK, notificationBridge_.get());
-    commandUpdater_->AddCommandObserver(IDC_FORWARD, notificationBridge_.get());
-
-    PrefService* prefs = browser->profile()->GetPrefs();
-    showHomeButton_.Init(
-        prefs::kShowHomeButton, prefs,
-        base::BindRepeating(&TouchBarNotificationBridge::UpdateTouchBar,
-                            base::Unretained(notificationBridge_.get())));
-
-    profilePrefRegistrar_.Init(prefs);
-    profilePrefRegistrar_.Add(
-        DefaultSearchManager::kDefaultSearchProviderDataPrefName,
-        base::BindRepeating(&TouchBarNotificationBridge::UpdateTouchBar,
-                            base::Unretained(notificationBridge_.get())));
-  }
-
-  return self;
-}
+@synthesize canGoBack = canGoBack_;
+@synthesize canGoForward = canGoForward_;
+@synthesize controller = controller_;
+@synthesize browser = browser_;
 
 - (NSTouchBar*)makeTouchBar {
   // When in tab or extension fullscreen, we should show a touch bar containing
@@ -301,12 +313,12 @@
       setCustomizationIdentifier:ui::GetTouchBarId(kBrowserWindowTouchBarId)];
   [touchBar setDelegate:self];
 
-  NSMutableArray* customIdentifiers = [NSMutableArray arrayWithCapacity:7];
-  NSMutableArray* defaultIdentifiers = [NSMutableArray arrayWithCapacity:6];
+  NSMutableArray<NSString*>* customIdentifiers = [NSMutableArray array];
+  NSMutableArray<NSString*>* defaultIdentifiers = [NSMutableArray array];
 
-  NSArray* touchBarItems = @[
-    kBackForwardTouchId, kReloadOrStopTouchId, kHomeTouchId, kSearchTouchId,
-    kStarTouchId, kNewTabTouchId
+  NSArray<NSString*>* touchBarItems = @[
+    kBackTouchId, kForwardTouchId, kReloadOrStopTouchId, kHomeTouchId,
+    kSearchTouchId, kStarTouchId, kNewTabTouchId
   ];
 
   for (NSString* item in touchBarItems) {
@@ -315,8 +327,10 @@
     [customIdentifiers addObject:itemIdentifier];
 
     // Don't add the home button if it's not shown in the toolbar.
-    if (showHomeButton_.GetValue() || ![item isEqualTo:kHomeTouchId])
-      [defaultIdentifiers addObject:itemIdentifier];
+    if (item == kHomeTouchId && !notificationBridge_->show_home_button())
+      continue;
+
+    [defaultIdentifiers addObject:itemIdentifier];
   }
 
   [customIdentifiers addObject:NSTouchBarItemIdentifierFlexibleSpace];
@@ -332,14 +346,41 @@
   if (!touchBar)
     return nil;
 
+  if ([identifier hasSuffix:kBackForwardTouchId]) {
+    auto* items = @[
+      [touchBar itemForIdentifier:ui::GetTouchBarItemId(
+                                      kBrowserWindowTouchBarId, kBackTouchId)],
+      [touchBar
+          itemForIdentifier:ui::GetTouchBarItemId(kBrowserWindowTouchBarId,
+                                                  kForwardTouchId)],
+    ];
+    auto groupItem = [NSGroupTouchBarItem groupItemWithIdentifier:identifier
+                                                            items:items];
+    [groupItem setCustomizationLabel:
+                   l10n_util::GetNSString(
+                       IDS_TOUCH_BAR_BACK_FORWARD_CUSTOMIZATION_LABEL)];
+    return groupItem;
+  }
+
   base::scoped_nsobject<NSCustomTouchBarItem> touchBarItem(
       [[ui::NSCustomTouchBarItem() alloc] initWithIdentifier:identifier]);
-  if ([identifier hasSuffix:kBackForwardTouchId]) {
-    [self updateBackForwardControl];
-    [touchBarItem setView:backForwardControl_.get()];
-    [touchBarItem setCustomizationLabel:
-                      l10n_util::GetNSString(
-                          IDS_TOUCH_BAR_BACK_FORWARD_CUSTOMIZATION_LABEL)];
+  if ([identifier hasSuffix:kBackTouchId]) {
+    auto* button = CreateTouchBarButton(vector_icons::kBackArrowIcon, self,
+                                        IDC_BACK, IDS_ACCNAME_BACK);
+    [button bind:@"enabled" toObject:self withKeyPath:@"canGoBack" options:nil];
+    [touchBarItem setView:button];
+    [touchBarItem
+        setCustomizationLabel:l10n_util::GetNSString(IDS_ACCNAME_BACK)];
+  } else if ([identifier hasSuffix:kForwardTouchId]) {
+    auto* button = CreateTouchBarButton(vector_icons::kForwardArrowIcon, self,
+                                        IDC_FORWARD, IDS_ACCNAME_FORWARD);
+    [button bind:@"enabled"
+           toObject:self
+        withKeyPath:@"canGoForward"
+            options:nil];
+    [touchBarItem setView:button];
+    [touchBarItem
+        setCustomizationLabel:l10n_util::GetNSString(IDS_ACCNAME_FORWARD)];
   } else if ([identifier hasSuffix:kReloadOrStopTouchId]) {
     [self updateReloadStopButton];
     [touchBarItem setView:reloadStopButton_.get()];
@@ -398,6 +439,8 @@
 
     [touchBarItem
         setView:[NSTextField labelWithAttributedString:attributedString.get()]];
+  } else {
+    return nil;
   }
 
   return touchBarItem.autorelease();
@@ -412,61 +455,12 @@
   return touchBar.autorelease();
 }
 
-- (void)setupBackForwardControl {
-  NSMutableArray* images = [NSMutableArray arrayWithArray:@[
-    CreateNSImageFromIcon(vector_icons::kBackArrowIcon),
-    CreateNSImageFromIcon(vector_icons::kForwardArrowIcon)
-  ]];
-
-  // Offset the icons so that it matches the height of the other Touch Bar
-  // items.
-  const int kIconYOffset = 2;
-  for (NSUInteger i = 0; i < [images count]; i++) {
-    NSImage* image = [images objectAtIndex:i];
-    NSSize size = [image size];
-    size.height += kIconYOffset;
-
-    NSImage* offsettedImage = [[[NSImage alloc] initWithSize:size] autorelease];
-    [offsettedImage lockFocus];
-    [image drawInRect:NSMakeRect(0, 0, size.width, size.height - kIconYOffset)];
-    [offsettedImage unlockFocus];
-    [images replaceObjectAtIndex:i withObject:offsettedImage];
-  }
-
-  NSSegmentedControl* control = [NSSegmentedControl
-      segmentedControlWithImages:images
-                    trackingMode:NSSegmentSwitchTrackingMomentary
-                          target:self
-                          action:@selector(backOrForward:)];
-
-  // Use the accessibility protocol to get the children.
-  // Use NSAccessibilityUnignoredDescendant to be sure we start with
-  // the correct object.
-  id<NSAccessibility> segmentElement =
-      ToNSAccessibility(NSAccessibilityUnignoredDescendant(control));
-  DCHECK(segmentElement);
-  NSArray<id<NSAccessibility>>* segments = segmentElement.accessibilityChildren;
-  ToNSAccessibility(segments[0]).accessibilityTitle =
-      l10n_util::GetNSString(IDS_ACCNAME_BACK);
-  ToNSAccessibility(segments[1]).accessibilityTitle =
-      l10n_util::GetNSString(IDS_ACCNAME_FORWARD);
-
-  backForwardControl_.reset([control retain]);
-}
-
-- (void)updateWebContents:(content::WebContents*)contents {
-  notificationBridge_->UpdateWebContents(contents);
-}
-
-- (void)updateBackForwardControl {
-  if (!backForwardControl_)
-    [self setupBackForwardControl];
-
-  [backForwardControl_ setSegmentStyle:NSSegmentStyleSeparated];
-  [backForwardControl_ setEnabled:commandUpdater_->IsCommandEnabled(IDC_BACK)
-                       forSegment:kBackSegmentIndex];
-  [backForwardControl_ setEnabled:commandUpdater_->IsCommandEnabled(IDC_FORWARD)
-                       forSegment:kForwardSegmentIndex];
+- (void)setBrowser:(Browser*)browser {
+  if (browser_ == browser)
+    return;
+  browser_ = browser;
+  notificationBridge_.reset(
+      browser_ ? new TouchBarNotificationBridge(self, browser_) : nullptr);
 }
 
 - (void)updateStarredButton {
@@ -485,10 +479,6 @@
   [starredButton_ setAccessibilityLabel:l10n_util::GetNSString(tooltipId)];
 }
 
-- (BrowserWindowTouchBarController*)controller {
-  return controller_;
-}
-
 - (NSView*)searchTouchBarView {
   TemplateURLService* templateUrlService =
       TemplateURLServiceFactory::GetForProfile(browser_->profile());
@@ -532,18 +522,10 @@
   return searchButton;
 }
 
-- (void)backOrForward:(id)sender {
-  NSSegmentedControl* control = sender;
-  int command =
-      [control selectedSegment] == kBackSegmentIndex ? IDC_BACK : IDC_FORWARD;
-  LogTouchBarUMA(TouchBarActionFromCommand(command));
-  commandUpdater_->ExecuteCommand(command);
-}
-
 - (void)executeCommand:(id)sender {
   int command = [sender tag];
   ui::LogTouchBarUMA(TouchBarActionFromCommand(command));
-  commandUpdater_->ExecuteCommand(command);
+  browser_->command_controller()->ExecuteCommand(command);
 }
 
 - (void)setIsPageLoading:(BOOL)isPageLoading {
@@ -561,6 +543,23 @@
 // Private methods exposed for testing.
 @implementation BrowserWindowDefaultTouchBar (ExposedForTesting)
 
++ (NSString*)reloadOrStopItemIdentifier {
+  return ui::GetTouchBarItemId(kBrowserWindowTouchBarId, kReloadOrStopTouchId);
+}
+
++ (NSString*)backItemIdentifier {
+  return ui::GetTouchBarItemId(kBrowserWindowTouchBarId, kBackTouchId);
+}
+
++ (NSString*)forwardItemIdentifier {
+  return ui::GetTouchBarItemId(kBrowserWindowTouchBarId, kForwardTouchId);
+}
+
++ (NSString*)fullscreenOriginItemIdentifier {
+  return ui::GetTouchBarItemId(kTabFullscreenTouchBarId,
+                               kFullscreenOriginLabelTouchId);
+}
+
 - (void)updateReloadStopButton {
   const gfx::VectorIcon& icon =
       isPageLoading_ ? kNavigateStopIcon : vector_icons::kReloadIcon;
@@ -586,13 +585,6 @@
   return reloadStopButton_.get();
 }
 
-- (NSSegmentedControl*)backForwardControl {
-  if (!backForwardControl_)
-    [self updateBackForwardControl];
-
-  return backForwardControl_.get();
-}
-
 - (BookmarkTabHelperObserver*)bookmarkTabObserver {
   return notificationBridge_.get();
 }
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm
index ec36da0..9c93039a 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm
@@ -18,33 +18,14 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "ui/base/cocoa/touch_bar_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
-namespace {
-
-// Touch bar identifiers.
-NSString* const kBrowserWindowTouchBarId = @"browser-window";
-NSString* const kTabFullscreenTouchBarId = @"tab-fullscreen";
-
-// Touch bar items identifiers.
-NSString* const kBackForwardTouchId = @"BACK-FWD";
-NSString* const kReloadOrStopTouchId = @"RELOAD-STOP";
-NSString* const kHomeTouchId = @"HOME";
-NSString* const kSearchTouchId = @"SEARCH";
-NSString* const kStarTouchId = @"BOOKMARK";
-NSString* const kNewTabTouchId = @"NEW-TAB";
-NSString* const kFullscreenOriginLabelTouchId = @"FULLSCREEN-ORIGIN-LABEL";
-
-// The button indexes in the back and forward segment control.
-const int kBackSegmentIndex = 0;
-const int kForwardSegmentIndex = 1;
-
-}  // namespace
-
 class BrowserWindowDefaultTouchBarUnitTest : public CocoaProfileTest {
  public:
   void SetUp() override {
@@ -53,75 +34,117 @@
 
     command_updater_ = browser()->command_controller();
 
+    browser()->tab_strip_model()->AppendWebContents(
+        content::WebContentsTester::CreateTestWebContents(profile(), nullptr),
+        true);
+
     if (@available(macOS 10.12.2, *)) {
-      touch_bar_.reset([[BrowserWindowDefaultTouchBar alloc]
-          initWithBrowser:browser()
-               controller:nil]);
+      touch_bar_.reset([[BrowserWindowDefaultTouchBar alloc] init]);
+      touch_bar_.get().browser = browser();
     }
   }
 
-  NSString* GetFullscreenTouchBarItemId(NSString* id) {
-    return ui::GetTouchBarItemId(kTabFullscreenTouchBarId, id);
-  }
-
-  NSString* GetBrowserTouchBarItemId(NSString* id) {
-    return ui::GetTouchBarItemId(kBrowserWindowTouchBarId, id);
-  }
-
   void UpdateCommandEnabled(int id, bool enabled) {
     command_updater_->UpdateCommandEnabled(id, enabled);
   }
 
   void TearDown() override {
-    if (@available(macOS 10.12.2, *))
+    if (@available(macOS 10.12.2, *)) {
+      touch_bar_.get().browser = nullptr;
       touch_bar_.reset();
+    }
     CocoaProfileTest::TearDown();
   }
 
   CommandUpdater* command_updater_;  // Weak, owned by Browser.
+  content::RenderViewHostTestEnabler rvh_test_enabler_;
 
   API_AVAILABLE(macos(10.12.2))
   base::scoped_nsobject<BrowserWindowDefaultTouchBar> touch_bar_;
 };
 
-// Tests to check if the touch bar contains the correct items.
+// Test if any known identifiers no longer work. See the message in the test;
+// these identifiers may be written out to disk on users' computers if they
+// customize the Touch Bar, and the corresponding items will disappear if they
+// can no longer be created.
+TEST_F(BrowserWindowDefaultTouchBarUnitTest, HistoricTouchBarItems) {
+  if (@available(macOS 10.12.2, *)) {
+    NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
+    for (NSString* item_identifier : {
+             @"BACK-FWD",
+             @"BACK",
+             @"FORWARD",
+             @"RELOAD-STOP",
+             @"HOME",
+             @"SEARCH",
+             @"BOOKMARK",
+             @"NEW-TAB",
+         }) {
+      auto identifier =
+          ui::GetTouchBarItemId(@"browser-window", item_identifier);
+      EXPECT_NE(nil, [touch_bar itemForIdentifier:identifier])
+          << "BrowserWindowDefaultTouchBar didn't return a Touch Bar item for "
+             "an identifier that was once available ("
+          << identifier.UTF8String
+          << "). If a user's customized Touch Bar includes this item, it will "
+             "disappear! Do not update or remove entries in this list just to "
+             "make the test pass; keep supporting old identifiers when "
+             "possible, even if they're no longer part of the set of "
+             "default/customizable items.";
+    }
+  }
+}
+
+// Tests if BrowserWindowDefaultTouchBar can produce the items it says it can
+// and, for each kind of bar, also verify that the advertised/customizable lists
+// include some representative items (if not, the lists might be wrong.)
 TEST_F(BrowserWindowDefaultTouchBarUnitTest, TouchBarItems) {
   if (@available(macOS 10.12.2, *)) {
+    auto test_default_identifiers =
+        [&](NSSet* expected_identifiers) API_AVAILABLE(macos(10.12.2)) {
+          NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
+          NSMutableSet<NSString*>* advertised_identifiers = [NSMutableSet set];
+          [advertised_identifiers
+              addObjectsFromArray:touch_bar.defaultItemIdentifiers];
+          [advertised_identifiers
+              addObjectsFromArray:touch_bar
+                                      .customizationAllowedItemIdentifiers];
+          [advertised_identifiers
+              addObjectsFromArray:touch_bar
+                                      .customizationRequiredItemIdentifiers];
+          EXPECT_TRUE(
+              [expected_identifiers isSubsetOfSet:advertised_identifiers])
+              << "Didn't find the expected identifiers "
+              << expected_identifiers.description.UTF8String
+              << " in the set of advertised identifiers "
+              << advertised_identifiers.description.UTF8String << ".";
+          for (NSString* identifier in advertised_identifiers) {
+            EXPECT_NE(nil, [touch_bar itemForIdentifier:identifier])
+                << "Didn't get a touch bar item for " << identifier.UTF8String;
+          }
+        };
+
     // Set to tab fullscreen.
     FullscreenController* fullscreen_controller =
         browser()->exclusive_access_manager()->fullscreen_controller();
     fullscreen_controller->set_is_tab_fullscreen_for_testing(true);
     EXPECT_TRUE(fullscreen_controller->IsTabFullscreen());
 
-    // The touch bar should only contain an item that displays the origin of the
-    // tab content fullscreen.
-    NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
-    NSArray* touch_bar_items = [touch_bar itemIdentifiers];
-    EXPECT_TRUE(
-        [touch_bar_items containsObject:GetFullscreenTouchBarItemId(
-                                            kFullscreenOriginLabelTouchId)]);
-    EXPECT_EQ(1u, [touch_bar_items count]);
+    // The fullscreen Touch Bar should include *at least* these items.
+    test_default_identifiers([NSSet setWithArray:@[
+      BrowserWindowDefaultTouchBar.fullscreenOriginItemIdentifier,
+    ]]);
 
     // Exit fullscreen.
     fullscreen_controller->set_is_tab_fullscreen_for_testing(false);
     EXPECT_FALSE(fullscreen_controller->IsTabFullscreen());
 
-    PrefService* prefs = profile()->GetPrefs();
-    DCHECK(prefs);
-    prefs->SetBoolean(prefs::kShowHomeButton, true);
-    touch_bar_items = [[touch_bar_ makeTouchBar] itemIdentifiers];
-    EXPECT_TRUE([touch_bar_items
-        containsObject:GetBrowserTouchBarItemId(kBackForwardTouchId)]);
-    EXPECT_TRUE([touch_bar_items
-        containsObject:GetBrowserTouchBarItemId(kReloadOrStopTouchId)]);
-    EXPECT_TRUE([touch_bar_items
-        containsObject:GetBrowserTouchBarItemId(kHomeTouchId)]);
-    EXPECT_TRUE([touch_bar_items
-        containsObject:GetBrowserTouchBarItemId(kSearchTouchId)]);
-    EXPECT_TRUE([touch_bar_items
-        containsObject:GetBrowserTouchBarItemId(kStarTouchId)]);
-    EXPECT_TRUE([touch_bar_items
-        containsObject:GetBrowserTouchBarItemId(kNewTabTouchId)]);
+    // The default Touch Bar should include *at least* these items.
+    test_default_identifiers([NSSet setWithArray:@[
+      BrowserWindowDefaultTouchBar.backItemIdentifier,
+      BrowserWindowDefaultTouchBar.forwardItemIdentifier,
+      BrowserWindowDefaultTouchBar.reloadOrStopItemIdentifier,
+    ]]);
   }
 }
 
@@ -131,56 +154,69 @@
     NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
     [touch_bar_ setIsPageLoading:NO];
 
-    NSTouchBarItem* item = [touch_bar_
-                     touchBar:touch_bar
-        makeItemForIdentifier:GetBrowserTouchBarItemId(kReloadOrStopTouchId)];
+    NSTouchBarItem* item =
+        [touch_bar itemForIdentifier:BrowserWindowDefaultTouchBar
+                                         .reloadOrStopItemIdentifier];
     EXPECT_EQ(IDC_RELOAD, [[item view] tag]);
 
     [touch_bar_ setIsPageLoading:YES];
-    item = [touch_bar_ touchBar:touch_bar
-          makeItemForIdentifier:GetBrowserTouchBarItemId(kReloadOrStopTouchId)];
+    item = [touch_bar itemForIdentifier:BrowserWindowDefaultTouchBar
+                                            .reloadOrStopItemIdentifier];
     EXPECT_EQ(IDC_STOP, [[item view] tag]);
   }
 }
 
-// Tests to see if the back/forward items on the touch bar is in sync with the
-// back and forward commands.
-TEST_F(BrowserWindowDefaultTouchBarUnitTest, BackForwardCommandUpdate) {
+// Tests if the back button on the touch bar is in sync with the back command.
+TEST_F(BrowserWindowDefaultTouchBarUnitTest, BackCommandUpdate) {
   if (@available(macOS 10.12.2, *)) {
-    NSSegmentedControl* back_forward_control = [touch_bar_ backForwardControl];
+    NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
+    NSTouchBarItem* item = [touch_bar
+        itemForIdentifier:BrowserWindowDefaultTouchBar.backItemIdentifier];
+    NSButton* button = base::mac::ObjCCast<NSButton>(item.view);
 
     UpdateCommandEnabled(IDC_BACK, true);
-    UpdateCommandEnabled(IDC_FORWARD, true);
-    EXPECT_TRUE([back_forward_control isEnabledForSegment:kBackSegmentIndex]);
-    EXPECT_TRUE(
-        [back_forward_control isEnabledForSegment:kForwardSegmentIndex]);
-
+    EXPECT_TRUE(button.enabled);
     UpdateCommandEnabled(IDC_BACK, false);
-    EXPECT_FALSE([back_forward_control isEnabledForSegment:kBackSegmentIndex]);
-    EXPECT_TRUE(
-        [back_forward_control isEnabledForSegment:kForwardSegmentIndex]);
-
-    UpdateCommandEnabled(IDC_FORWARD, false);
-    EXPECT_FALSE([back_forward_control isEnabledForSegment:kBackSegmentIndex]);
-    EXPECT_FALSE(
-        [back_forward_control isEnabledForSegment:kForwardSegmentIndex]);
+    EXPECT_FALSE(button.enabled);
   }
 }
 
-TEST_F(BrowserWindowDefaultTouchBarUnitTest, BackForwardAccessibilityLabels) {
+// Tests if the forward button on the touch bar is in sync with the forward
+// command.
+TEST_F(BrowserWindowDefaultTouchBarUnitTest, ForwardCommandUpdate) {
   if (@available(macOS 10.12.2, *)) {
-    NSSegmentedControl* control = touch_bar_.get().backForwardControl;
-    id<NSAccessibility> cell = NSAccessibilityUnignoredDescendant(control);
-    ASSERT_TRUE([cell conformsToProtocol:@protocol(NSAccessibility)]);
+    NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
+    NSTouchBarItem* item = [touch_bar
+        itemForIdentifier:BrowserWindowDefaultTouchBar.forwardItemIdentifier];
+    NSButton* button = base::mac::ObjCCast<NSButton>(item.view);
 
-    id<NSAccessibility> back = cell.accessibilityChildren[0];
-    EXPECT_TRUE([back conformsToProtocol:@protocol(NSAccessibility)]);
-    EXPECT_NSEQ(back.accessibilityTitle,
+    UpdateCommandEnabled(IDC_FORWARD, true);
+    EXPECT_TRUE(button.enabled);
+    UpdateCommandEnabled(IDC_FORWARD, false);
+    EXPECT_FALSE(button.enabled);
+  }
+}
+
+TEST_F(BrowserWindowDefaultTouchBarUnitTest, BackAccessibilityLabel) {
+  if (@available(macOS 10.12.2, *)) {
+    NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
+    NSTouchBarItem* item = [touch_bar
+        itemForIdentifier:BrowserWindowDefaultTouchBar.backItemIdentifier];
+    id<NSAccessibility> view = item.view;
+    ASSERT_TRUE([view conformsToProtocol:@protocol(NSAccessibility)]);
+    EXPECT_NSEQ(view.accessibilityTitle,
                 l10n_util::GetNSString(IDS_ACCNAME_BACK));
+  }
+}
 
-    id<NSAccessibility> forward = cell.accessibilityChildren[1];
-    EXPECT_TRUE([forward conformsToProtocol:@protocol(NSAccessibility)]);
-    EXPECT_NSEQ(forward.accessibilityTitle,
+TEST_F(BrowserWindowDefaultTouchBarUnitTest, ForwardAccessibilityLabel) {
+  if (@available(macOS 10.12.2, *)) {
+    NSTouchBar* touch_bar = [touch_bar_ makeTouchBar];
+    NSTouchBarItem* item = [touch_bar
+        itemForIdentifier:BrowserWindowDefaultTouchBar.forwardItemIdentifier];
+    id<NSAccessibility> view = item.view;
+    ASSERT_TRUE([view conformsToProtocol:@protocol(NSAccessibility)]);
+    EXPECT_NSEQ(view.accessibilityTitle,
                 l10n_util::GetNSString(IDS_ACCNAME_FORWARD));
   }
 }
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
index f5443e06..147775a 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
@@ -32,9 +32,6 @@
 // nil.
 - (void)invalidateTouchBar;
 
-- (void)updateWebContents:(content::WebContents*)contents;
-
-- (content::WebContents*)webContents;
 @end
 
 @interface BrowserWindowTouchBarController (ExposedForTesting)
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
index 28d60d0..94bea88 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
@@ -19,66 +19,9 @@
 #include "content/public/browser/web_contents_observer.h"
 #import "ui/base/cocoa/touch_bar_util.h"
 
-class API_AVAILABLE(macos(10.12.2)) WebContentsNotificationBridge
-    : public TabStripModelObserver,
-      public content::WebContentsObserver {
- public:
-  WebContentsNotificationBridge(BrowserWindowTouchBarController* owner,
-                                Browser* browser)
-      : owner_(owner), browser_(browser), contents_(nullptr) {
-    TabStripModel* model = browser_->tab_strip_model();
-    DCHECK(model);
-    model->AddObserver(this);
-
-    UpdateWebContents(model->GetActiveWebContents());
-  }
-
-  ~WebContentsNotificationBridge() override {
-    TabStripModel* model = browser_->tab_strip_model();
-    if (model)
-      model->RemoveObserver(this);
-  }
-
-  void UpdateWebContents(content::WebContents* new_contents) {
-    contents_ = new_contents;
-    Observe(contents_);
-
-    [owner_ updateWebContents:contents_];
-  }
-
-  // TabStripModelObserver:
-  void OnTabStripModelChanged(
-      TabStripModel* tab_strip_model,
-      const TabStripModelChange& change,
-      const TabStripSelectionChange& selection) override {
-    if (tab_strip_model->empty() || !selection.active_tab_changed())
-      return;
-
-    UpdateWebContents(selection.new_contents);
-    contents_ = selection.new_contents;
-  }
-
-  content::WebContents* contents() const { return contents_; }
-
- protected:
-  // WebContentsObserver:
-  void WebContentsDestroyed() override {
-    // Clean up if the web contents is being destroyed.
-    UpdateWebContents(nullptr);
-  }
-
- private:
-  BrowserWindowTouchBarController* owner_;  // Weak.
-  Browser* browser_;                        // Weak.
-  content::WebContents* contents_;          // Weak.
-};
-
 @interface BrowserWindowTouchBarController () {
   NSWindow* window_;  // Weak.
 
-  // Used to receive and handle notifications.
-  std::unique_ptr<WebContentsNotificationBridge> notificationBridge_;
-
   base::scoped_nsobject<BrowserWindowDefaultTouchBar> defaultTouchBar_;
 
   base::scoped_nsobject<WebTextfieldTouchBarController> webTextfieldTouchBar_;
@@ -92,12 +35,9 @@
     DCHECK(browser);
     window_ = window;
 
-    notificationBridge_ =
-        std::make_unique<WebContentsNotificationBridge>(self, browser);
-
-    defaultTouchBar_.reset([[BrowserWindowDefaultTouchBar alloc]
-        initWithBrowser:browser
-             controller:self]);
+    defaultTouchBar_.reset([[BrowserWindowDefaultTouchBar alloc] init]);
+    defaultTouchBar_.get().controller = self;
+    defaultTouchBar_.get().browser = browser;
     webTextfieldTouchBar_.reset(
         [[WebTextfieldTouchBarController alloc] initWithController:self]);
   }
@@ -105,6 +45,11 @@
   return self;
 }
 
+- (void)dealloc {
+  defaultTouchBar_.get().browser = nullptr;
+  [super dealloc];
+}
+
 - (void)invalidateTouchBar {
   DCHECK([window_ respondsToSelector:@selector(setTouchBar:)]);
   [window_ performSelector:@selector(setTouchBar:) withObject:nil];
@@ -118,15 +63,6 @@
   return [defaultTouchBar_ makeTouchBar];
 }
 
-- (void)updateWebContents:(content::WebContents*)contents {
-  [defaultTouchBar_ updateWebContents:contents];
-  [self invalidateTouchBar];
-}
-
-- (content::WebContents*)webContents {
-  return notificationBridge_->web_contents();
-}
-
 @end
 
 @implementation BrowserWindowTouchBarController (ExposedForTesting)
diff --git a/chrome/browser/ui/search/local_ntp_test_utils.cc b/chrome/browser/ui/search/local_ntp_test_utils.cc
index f0ee8b3..0325aea 100644
--- a/chrome/browser/ui/search/local_ntp_test_utils.cc
+++ b/chrome/browser/ui/search/local_ntp_test_utils.cc
@@ -27,72 +27,8 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "ui/base/resource/resource_bundle.h"
-// #include "ui/native_theme/test_native_theme.h"
-
-// namespace {
-
-// // Delimiter in the Most Visited icon URL that indicates a dark icon. Keep
-// value
-// // in sync with NtpIconSource.
-// const char kMVIconDarkParameter[] = "/dark/";
-
-// }  // namespace
-
 namespace local_ntp_test_utils {
 
-// // Tests that dark mode styling is properly applied to the local NTP.
-// class BaseDarkModeTest {
-//  public:
-//   BaseDarkModeTest() {}
-
-//   ui::TestNativeTheme* theme() { return &theme_; }
-
-//   // Returns true if dark mode is applied on the |frame|.
-//   bool GetIsDarkModeApplied(const content::ToRenderFrameHost& frame) {
-//     bool dark_mode_applied = false;
-//     if (instant_test_utils::GetBoolFromJS(
-//             frame,
-//             "document.documentElement.getAttribute('darkmode') === 'true'",
-//             &dark_mode_applied)) {
-//       return dark_mode_applied;
-//     }
-//     return false;
-//   }
-
-//   // Returns true if dark mode is applied on the |frame|.
-//   bool GetIsDarkModeChipApplied(const content::ToRenderFrameHost& frame) {
-//     bool dark_mode_chip_applied = false;
-//     if (!instant_test_utils::GetBoolFromJS(
-//             frame,
-//             "document.documentElement.getAttribute('darkmode') === 'true' &&
-//             "
-//             "!document.body.classList.contains('light-chip')",
-//             &dark_mode_chip_applied)) {
-//       return dark_mode_chip_applied;
-//     }
-//     return false;
-//   }
-
-//   // Returns true if dark mode is applied to the Most Visited icon at |index|
-//   // (i.e. the icon URL contains the |kMVIconDarkParameter|).
-//   bool GetIsDarkTile(const content::ToRenderFrameHost& frame, int index) {
-//     bool dark_tile = false;
-//     if (instant_test_utils::GetBoolFromJS(
-//             frame,
-//             base::StringPrintf(
-//                 "document.querySelectorAll('#mv-tiles .md-icon img')[%d]"
-//                 ".src.includes('%s')",
-//                 index, kMVIconDarkParameter),
-//             &dark_tile)) {
-//       return dark_tile;
-//     }
-//     return false;
-//   }
-
-//  private:
-//   ui::TestNativeTheme theme_;
-// };
-
 content::WebContents* OpenNewTab(Browser* browser, const GURL& url) {
   ui_test_utils::NavigateToURLWithDisposition(
       browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_button.cc b/chrome/browser/ui/views/extensions/extensions_menu_button.cc
index 898988d..de143fe 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_button.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_button.cc
@@ -4,23 +4,42 @@
 
 #include "chrome/browser/ui/views/extensions/extensions_menu_button.h"
 
+#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_view.h"
 #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/menu_button.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
+#include "ui/views/view_class_properties.h"
 
 const char ExtensionsMenuButton::kClassName[] = "ExtensionsMenuButton";
 
+namespace {
+
+constexpr int EXTENSION_CONTEXT_MENU = 13;
+
+}  // namespace
+
 ExtensionsMenuButton::ExtensionsMenuButton(
     Browser* browser,
     std::unique_ptr<ToolbarActionViewController> controller)
     : HoverButton(this,
                   ExtensionsMenuView::CreateFixedSizeIconView(),
                   base::string16(),
-                  base::string16()),
+                  base::string16(),
+                  std::make_unique<views::View>(),
+                  true,
+                  true),
       browser_(browser),
       controller_(std::move(controller)) {
+  ConfigureSecondaryView();
   set_auto_compute_tooltip(false);
   set_context_menu_controller(this);
   controller_->SetDelegate(this);
@@ -35,6 +54,11 @@
 
 void ExtensionsMenuButton::ButtonPressed(Button* sender,
                                          const ui::Event& event) {
+  if (sender->id() == EXTENSION_CONTEXT_MENU) {
+    ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE);
+    return;
+  }
+  DCHECK_EQ(this, sender);
   controller_->ExecuteAction(true);
 }
 
@@ -70,8 +94,7 @@
 }
 
 bool ExtensionsMenuButton::IsMenuRunning() const {
-  // TODO(pbos): Implement when able to show context menus inside this bubble.
-  return false;
+  return menu_runner_ && menu_runner_->IsRunning();
 }
 
 // views::ContextMenuController:
@@ -79,6 +102,64 @@
     views::View* source,
     const gfx::Point& point,
     ui::MenuSourceType source_type) {
-  // TODO(pbos): Implement this. This is a no-op implementation as it prevents
-  // crashing actions that don't have a popup action.
+  ui::MenuModel* model = controller_->GetContextMenu();
+  if (!model)
+    return;
+
+  // Unretained() is safe here as ExtensionsMenuButton will always outlive the
+  // menu. Any action that would lead to the deletion of |this| first triggers
+  // the closing of the menu through lost capture.
+  menu_adapter_ = std::make_unique<views::MenuModelAdapter>(
+      model, base::BindRepeating(&ExtensionsMenuButton::OnMenuClosed,
+                                 base::Unretained(this)));
+
+  menu_runner_ = std::make_unique<views::MenuRunner>(
+      model, views::MenuRunner::HAS_MNEMONICS);
+  menu_runner_->RunMenuAt(GetWidget(), context_menu_button_,
+                          context_menu_button_->GetAnchorBoundsInScreen(),
+                          views::MenuAnchorPosition::kTopRight, source_type);
+}
+
+void ExtensionsMenuButton::OnMenuClosed() {
+  menu_runner_.reset();
+  controller_->OnContextMenuClosed();
+  menu_adapter_.reset();
+}
+
+void ExtensionsMenuButton::ConfigureSecondaryView() {
+  views::View* container = secondary_view();
+  DCHECK(container->children().empty());
+  container->SetLayoutManager(
+      std::make_unique<views::BoxLayout>(views::BoxLayout::kHorizontal));
+
+  const SkColor icon_color =
+      ui::NativeTheme::GetInstanceForNativeUi()->SystemDarkModeEnabled()
+          ? gfx::kGoogleGrey500
+          : gfx::kChromeIconGrey;
+
+  auto context_menu_button =
+      std::make_unique<views::MenuButton>(base::string16(), this);
+  context_menu_button->set_id(EXTENSION_CONTEXT_MENU);
+  context_menu_button->SetTooltipText(
+      l10n_util::GetStringUTF16(IDS_EXTENSIONS_MENU_CONTEXT_MENU_TOOLTIP));
+
+  context_menu_button->SetImage(
+      views::Button::STATE_NORMAL,
+      gfx::CreateVectorIcon(kBrowserToolsIcon, 16, icon_color));
+  context_menu_button->set_ink_drop_base_color(icon_color);
+  context_menu_button->SetBorder(
+      views::CreateEmptyBorder(views::LayoutProvider::Get()->GetInsetsMetric(
+          views::INSETS_VECTOR_IMAGE_BUTTON)));
+  context_menu_button->SizeToPreferredSize();
+
+  context_menu_button->SetInkDropMode(InkDropMode::ON);
+  context_menu_button->set_has_ink_drop_action_on_click(true);
+  auto highlight_path = std::make_unique<SkPath>();
+  highlight_path->addOval(
+      gfx::RectToSkRect(gfx::Rect(context_menu_button->size())));
+  context_menu_button->SetProperty(views::kHighlightPathKey,
+                                   highlight_path.release());
+
+  context_menu_button_ = context_menu_button.get();
+  container->AddChildView(std::move(context_menu_button));
 }
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_button.h b/chrome/browser/ui/views/extensions/extensions_menu_button.h
index e059f0a..2531dfd 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_button.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_button.h
@@ -14,7 +14,9 @@
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 
 namespace views {
-class View;
+class MenuButton;
+class MenuModelAdapter;
+class MenuRunner;
 }  // namespace views
 
 class ExtensionsMenuButton : public HoverButton,
@@ -46,9 +48,27 @@
                                   const gfx::Point& point,
                                   ui::MenuSourceType source_type) override;
 
+  // Callback for MenuModelAdapter.
+  void OnMenuClosed();
+
+  // Configures the secondary (right-hand-side) view of this HoverButton.
+  void ConfigureSecondaryView();
+
   Browser* const browser_;
   const std::unique_ptr<ToolbarActionViewController> controller_;
 
+  // TODO(pbos): There's complicated configuration code in place since menus
+  // can't be triggered from ImageButtons. When MenuRunner::RunMenuAt accepts
+  // views::Buttons, turn this into a views::ImageButton and use
+  // image_button_factory.h methods to configure it.
+  views::MenuButton* context_menu_button_ = nullptr;
+
+  // Responsible for converting the context menu model into |menu_|.
+  std::unique_ptr<views::MenuModelAdapter> menu_adapter_;
+
+  // Responsible for running the menu.
+  std::unique_ptr<views::MenuRunner> menu_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionsMenuButton);
 };
 
diff --git a/chrome/browser/ui/views/hover_button.cc b/chrome/browser/ui/views/hover_button.cc
index 05a37ae..1ae6618 100644
--- a/chrome/browser/ui/views/hover_button.cc
+++ b/chrome/browser/ui/views/hover_button.cc
@@ -338,9 +338,14 @@
   if (secondary_view_) {
     gfx::Point point_in_secondary_view(point);
     ConvertPointToTarget(this, secondary_view_, &point_in_secondary_view);
-    if (secondary_view_->HitTestPoint(point_in_secondary_view) &&
-        !secondary_view_->GetTooltipText(point_in_secondary_view).empty()) {
-      return secondary_view_;
+    View* handler =
+        secondary_view_->GetTooltipHandlerForPoint(point_in_secondary_view);
+    if (handler) {
+      gfx::Point point_in_handler_view(point);
+      ConvertPointToTarget(this, handler, &point_in_handler_view);
+      if (!handler->GetTooltipText(point_in_secondary_view).empty()) {
+        return handler;
+      }
     }
   }
 
diff --git a/chrome/browser/ui/views/hover_button.h b/chrome/browser/ui/views/hover_button.h
index 21d0b91..fe69553 100644
--- a/chrome/browser/ui/views/hover_button.h
+++ b/chrome/browser/ui/views/hover_button.h
@@ -111,6 +111,7 @@
   views::StyledLabel* title() const { return title_; }
   views::Label* subtitle() const { return subtitle_; }
   views::View* icon_view() const { return icon_view_; }
+  views::View* secondary_view() const { return secondary_view_; }
 
  private:
   FRIEND_TEST_ALL_PREFIXES(media_router::CastDialogSinkButtonTest,
diff --git a/chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.cc b/chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.cc
index 3dcc59b..38cfba5 100644
--- a/chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.cc
@@ -21,13 +21,14 @@
 
 namespace {
 
-constexpr int kBluetoothPairingDialogHeight = 350;
+constexpr int kBluetoothPairingDialogHeight = 375;
 
 void AddBluetoothStrings(content::WebUIDataSource* html_source) {
   struct {
     const char* name;
     int id;
   } localized_strings[] = {
+      {"bluetoothPairDeviceTitle", IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE_TITLE},
       {"ok", IDS_OK},
       {"cancel", IDS_CANCEL},
       {"close", IDS_CLOSE},
@@ -68,9 +69,8 @@
     const base::string16& name_for_display,
     bool paired,
     bool connected)
-    : SystemWebDialogDelegate(
-          GURL(chrome::kChromeUIBluetoothPairingURL),
-          l10n_util::GetStringUTF16(IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE_TITLE)),
+    : SystemWebDialogDelegate(GURL(chrome::kChromeUIBluetoothPairingURL),
+                              base::string16() /* title */),
       address_(address) {
   device_data_.SetString("address", address);
   device_data_.SetString("name", name_for_display);
diff --git a/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc b/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
index cf11f3c..cc28e91 100644
--- a/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
@@ -34,6 +34,7 @@
     {"controlledSettingShared", IDS_CONTROLLED_SETTING_SHARED},
     {"controlledSettingWithOwner", IDS_CONTROLLED_SETTING_WITH_OWNER},
     {"controlledSettingNoOwner", IDS_CONTROLLED_SETTING_NO_OWNER},
+    {"controlledSettingParent", IDS_CONTROLLED_SETTING_PARENT},
 #endif
   };
   AddLocalizedStringsBulk(html_source, localized_strings,
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
index 3f642cb..e77572a 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -83,12 +83,15 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   PrinterBasicInfo basic_info = ToBasicInfo(*printer);
+  bool has_secure_protocol = !printer->HasNetworkProtocol() ||
+                             printer->GetProtocol() == chromeos::Printer::kIpps;
 
   // USER_VISIBLE because the result is displayed in the print preview dialog.
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
       base::BindOnce(&GetSettingsOnBlockingPool, printer->id(), basic_info,
-                     PrinterSemanticCapsAndDefaults::Papers(), nullptr),
+                     PrinterSemanticCapsAndDefaults::Papers(),
+                     has_secure_protocol, nullptr),
       base::BindOnce(&CapabilitiesFetched, std::move(policies), std::move(cb)));
 }
 
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
index 8ddb28e..c4ea832 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
@@ -63,6 +63,7 @@
     return base::Value();
 
   return GetSettingsOnBlockingPool(device_name, basic_info, additional_papers,
+                                   /* has_secure_protocol */ false,
                                    print_backend);
 }
 
diff --git a/chrome/common/extensions/api/_features.md b/chrome/common/extensions/api/_features.md
index 5c05b24..11e5917 100644
--- a/chrome/common/extensions/api/_features.md
+++ b/chrome/common/extensions/api/_features.md
@@ -286,8 +286,8 @@
 allowed to access a feature. Extensions with a lesser manifest version cannot
 access the feature.
 
-The only accepted value is `2`, as this is currently the highest possible
-manifest version.
+Accepted values are `2` and `3`, as 3 is currently the highest possible manifest
+version.
 
 ### noparent
 
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl
index 324d430..3f167a4 100644
--- a/chrome/common/extensions/api/automation.idl
+++ b/chrome/common/extensions/api/automation.idl
@@ -718,6 +718,19 @@
     // The affinity of the tree selection focus, if any.
     DOMString? focusAffinity;
 
+    // The selection start node of the tree selection, if any.
+    AutomationNode? selectionStartObject;
+    // The selection start offset of the tree selection, if any.
+    long? selectionStartOffset;
+    // The affinity of the tree selection start, if any.
+    DOMString? selectionStartAffinity;
+    // The selection end node of the tree selection, if any.
+    AutomationNode? selectionEndObject;
+    // The selection end offset of the tree selection, if any.
+    long? selectionEndOffset;
+    // The affinity of the tree selection end, if any.
+    DOMString? selectionEndAffinity;
+
     //
     // Range attributes.
     //
@@ -912,6 +925,12 @@
     // Indicates whether this node is selected, unselected, or neither.
     boolean? selected;
 
+    // Indicates the font size of this node.
+    long? fontSize;
+
+    // Indicates the font family.
+    DOMString fontFamily;
+
     //
     // Walking the tree.
     //
diff --git a/chrome/common/extensions/api/devtools/inspected_window.json b/chrome/common/extensions/api/devtools/inspected_window.json
index 5ccdc23..17fcc398 100644
--- a/chrome/common/extensions/api/devtools/inspected_window.json
+++ b/chrome/common/extensions/api/devtools/inspected_window.json
@@ -37,7 +37,7 @@
                   {
                     "name": "encoding",
                     "type": "string",
-                    "description": "Empty if content is not encoded, encoding name otherwise. Currently, only base64 is supported."
+                    "description": "Empty if the content is not encoded, encoding name otherwise. Currently, only base64 is supported."
                   }
                 ]
               }
diff --git a/chrome/common/extensions/api/settings_private.idl b/chrome/common/extensions/api/settings_private.idl
index 1e2996c..5a036e8 100644
--- a/chrome/common/extensions/api/settings_private.idl
+++ b/chrome/common/extensions/api/settings_private.idl
@@ -13,7 +13,8 @@
     USER_POLICY,
     OWNER,
     PRIMARY_USER,
-    EXTENSION
+    EXTENSION,
+    PARENT
   };
 
   enum Enforcement { ENFORCED, RECOMMENDED };
diff --git a/chrome/common/extensions/api/top_sites.json b/chrome/common/extensions/api/top_sites.json
index b1bd3cf3..1119a06 100644
--- a/chrome/common/extensions/api/top_sites.json
+++ b/chrome/common/extensions/api/top_sites.json
@@ -5,7 +5,7 @@
 [
   {
     "namespace": "topSites",
-    "description": "Use the <code>chrome.topSites</code> API to access the top sites (i.e. most visited) that are displayed on the new tab page. These do not include shortcuts customized by the user.",
+    "description": "Use the <code>chrome.topSites</code> API to access the top sites (i.e. most visited sites) that are displayed on the new tab page. These do not include shortcuts customized by the user.",
     "types": [
       {
         "id": "MostVisitedURL",
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
index d6cd935..fa1de5d 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
@@ -72,6 +72,8 @@
       Testcase("init_invalid_files_css_item_invalid.json", errors::kInvalidCss),
       Testcase("init_invalid_permissions_invalid.json",
                errors::kInvalidPermissions),
+      Testcase("init_invalid_host_permissions_invalid.json",
+               errors::kInvalidHostPermissions),
       Testcase("init_invalid_permissions_item_invalid.json",
                errors::kInvalidPermission),
       Testcase("init_invalid_options_url_invalid.json",
diff --git a/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc b/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc
index ef3a58a..a87649b 100644
--- a/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc
@@ -11,6 +11,15 @@
 
 namespace extensions {
 
+namespace {
+
+// Install warning for tests running Manifest v3. The current highest
+// supported manifest version is 2.
+constexpr char kManifestVersionWarning[] =
+    "The maximum currently-supported manifest version is 2, but this is 3.  "
+    "Certain features may not work as expected.";
+}  // namespace
+
 using PermissionsParserTest = ChromeManifestTest;
 
 TEST_F(PermissionsParserTest, RemoveOverlappingAPIPermissions) {
@@ -97,4 +106,33 @@
               testing::UnorderedElementsAre("*://*/*"));
 }
 
+TEST_F(PermissionsParserTest, HostPermissionsKey) {
+  std::vector<std::string> expected_warnings;
+  expected_warnings.push_back(ErrorUtils::FormatErrorMessage(
+      manifest_errors::kPermissionUnknownOrMalformed, "https://google.com/*"));
+
+  expected_warnings.push_back(kManifestVersionWarning);
+
+  scoped_refptr<Extension> extension(
+      LoadAndExpectWarnings("host_permissions_key.json", expected_warnings));
+
+  // Expect that the host specified in |host_permissions| is parsed.
+  const URLPatternSet& required_hosts =
+      PermissionsParser::GetRequiredPermissions(extension.get())
+          .explicit_hosts();
+
+  EXPECT_THAT(*required_hosts.ToStringVector(),
+              testing::UnorderedElementsAre("https://example.com/*"));
+}
+
+TEST_F(PermissionsParserTest, HostPermissionsKeyInvalidHosts) {
+  std::vector<std::string> expected_warnings;
+  expected_warnings.push_back(ErrorUtils::FormatErrorMessage(
+      manifest_errors::kPermissionUnknownOrMalformed, "malformed_host"));
+
+  expected_warnings.push_back(kManifestVersionWarning);
+
+  scoped_refptr<Extension> extension(LoadAndExpectWarnings(
+      "host_permissions_key_invalid_hosts.json", expected_warnings));
+}
 }  // namespace extensions
diff --git a/chrome/common/thread_profiler.cc b/chrome/common/thread_profiler.cc
index f77b3f2..db16b3b 100644
--- a/chrome/common/thread_profiler.cc
+++ b/chrome/common/thread_profiler.cc
@@ -159,6 +159,9 @@
 }
 
 void ThreadProfiler::AddAuxUnwinder(std::unique_ptr<base::Unwinder> unwinder) {
+  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+    return;
+
   aux_unwinder_ = std::move(unwinder);
   startup_profiler_->AddAuxUnwinder(aux_unwinder_.get());
   if (periodic_profiler_)
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index 04dc719..b1b07bd 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -110,6 +110,8 @@
     "tts_dispatcher.h",
     "url_loader_throttle_provider_impl.cc",
     "url_loader_throttle_provider_impl.h",
+    "v8_unwinder.cc",
+    "v8_unwinder.h",
     "web_apps.cc",
     "web_apps.h",
     "websocket_handshake_throttle_provider_impl.cc",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 4938ded..5216250 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -64,6 +64,7 @@
 #include "chrome/renderer/prerender/prerenderer_client.h"
 #include "chrome/renderer/tts_dispatcher.h"
 #include "chrome/renderer/url_loader_throttle_provider_impl.h"
+#include "chrome/renderer/v8_unwinder.h"
 #include "chrome/renderer/websocket_handshake_throttle_provider_impl.h"
 #include "chrome/renderer/worker_content_settings_client.h"
 #include "components/autofill/content/renderer/autofill_agent.h"
diff --git a/chrome/renderer/v8_unwinder.cc b/chrome/renderer/v8_unwinder.cc
new file mode 100644
index 0000000..b107564
--- /dev/null
+++ b/chrome/renderer/v8_unwinder.cc
@@ -0,0 +1,112 @@
+// Copyright 2019 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/renderer/v8_unwinder.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/strcat.h"
+
+namespace {
+
+// Synthetic build ids to use for V8 modules. The difference is in the digit
+// after the leading 5's.
+// clang-format off
+const char kV8EmbeddedCodeRangeBuildId[] =
+    "5555555507284E1E874EFA4EB754964B999";
+const char kV8CodeRangeBuildId[] =
+    "5555555517284E1E874EFA4EB754964B999";
+// clang-format on
+
+class V8Module : public base::ModuleCache::Module {
+ public:
+  V8Module(const v8::MemoryRange& memory_range,
+           const std::string& build_id,
+           const std::string& descriptor)
+      : memory_range_(memory_range),
+        build_id_(build_id),
+        descriptor_(descriptor) {}
+
+  V8Module(const V8Module&) = delete;
+  V8Module& operator=(const V8Module&) = delete;
+
+  // ModuleCache::Module
+  uintptr_t GetBaseAddress() const override {
+    return reinterpret_cast<uintptr_t>(memory_range_.start);
+  }
+
+  std::string GetId() const override { return build_id_; }
+
+  base::FilePath GetDebugBasename() const override {
+    return base::FilePath().AppendASCII(base::StrCat({"V8 ", descriptor_}));
+  }
+
+  size_t GetSize() const override { return memory_range_.length_in_bytes; }
+
+  bool IsNative() const override { return false; }
+
+ private:
+  const v8::MemoryRange memory_range_;
+  const std::string build_id_;
+  const std::string descriptor_;
+};
+
+}  // namespace
+
+V8Unwinder::V8Unwinder(const v8::UnwindState& unwind_state)
+    : unwind_state_(unwind_state) {}
+
+V8Unwinder::~V8Unwinder() = default;
+
+void V8Unwinder::AddNonNativeModules(base::ModuleCache* module_cache) {
+  std::vector<std::unique_ptr<base::ModuleCache::Module>> modules;
+  modules.emplace_back(std::make_unique<V8Module>(
+      unwind_state_.embedded_code_range, kV8EmbeddedCodeRangeBuildId,
+      "Embedded Code Range"));
+  modules.emplace_back(std::make_unique<V8Module>(
+      unwind_state_.code_range, kV8CodeRangeBuildId, "Code Range"));
+  for (auto& module : modules) {
+    v8_modules_.insert(module.get());
+    module_cache->AddNonNativeModule(std::move(module));
+  }
+}
+
+bool V8Unwinder::CanUnwindFrom(const base::Frame* current_frame) const {
+  return v8_modules_.find(current_frame->module) != v8_modules_.end();
+}
+
+base::UnwindResult V8Unwinder::TryUnwind(
+    base::RegisterContext* thread_context,
+    uintptr_t stack_top,
+    base::ModuleCache* module_cache,
+    std::vector<base::Frame>* stack) const {
+  v8::RegisterState register_state;
+  register_state.pc = reinterpret_cast<void*>(
+      base::RegisterContextInstructionPointer(thread_context));
+  register_state.sp = reinterpret_cast<void*>(
+      base::RegisterContextStackPointer(thread_context));
+  register_state.fp = reinterpret_cast<void*>(
+      base::RegisterContextFramePointer(thread_context));
+
+  if (!v8::Unwinder::TryUnwindV8Frames(
+          unwind_state_, &register_state,
+          reinterpret_cast<const void*>(stack_top))) {
+    return base::UnwindResult::ABORTED;
+  }
+
+  base::RegisterContextInstructionPointer(thread_context) =
+      reinterpret_cast<uintptr_t>(register_state.pc);
+  base::RegisterContextStackPointer(thread_context) =
+      reinterpret_cast<uintptr_t>(register_state.sp);
+  base::RegisterContextFramePointer(thread_context) =
+      reinterpret_cast<uintptr_t>(register_state.fp);
+
+  stack->emplace_back(
+      base::RegisterContextInstructionPointer(thread_context),
+      module_cache->GetModuleForAddress(
+          base::RegisterContextInstructionPointer(thread_context)));
+
+  return base::UnwindResult::UNRECOGNIZED_FRAME;
+}
diff --git a/chrome/renderer/v8_unwinder.h b/chrome/renderer/v8_unwinder.h
new file mode 100644
index 0000000..57f13fc
--- /dev/null
+++ b/chrome/renderer/v8_unwinder.h
@@ -0,0 +1,35 @@
+// Copyright 2019 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_RENDERER_V8_UNWINDER_H_
+#define CHROME_RENDERER_V8_UNWINDER_H_
+
+#include "base/containers/flat_set.h"
+#include "base/profiler/unwinder.h"
+#include "v8/include/v8.h"
+
+// Implements stack frame unwinding for V8 generated code frames, for use with
+// the StackSamplingProfiler.
+class V8Unwinder : public base::Unwinder {
+ public:
+  explicit V8Unwinder(const v8::UnwindState& unwind_state);
+  ~V8Unwinder() override;
+
+  V8Unwinder(const V8Unwinder&) = delete;
+  V8Unwinder& operator=(const V8Unwinder&) = delete;
+
+  // Unwinder:
+  void AddNonNativeModules(base::ModuleCache* module_cache) override;
+  bool CanUnwindFrom(const base::Frame* current_frame) const override;
+  base::UnwindResult TryUnwind(base::RegisterContext* thread_context,
+                               uintptr_t stack_top,
+                               base::ModuleCache* module_cache,
+                               std::vector<base::Frame>* stack) const override;
+
+ private:
+  const v8::UnwindState unwind_state_;
+  base::flat_set<const base::ModuleCache::Module*> v8_modules_;
+};
+
+#endif  // CHROME_RENDERER_V8_UNWINDER_H_
diff --git a/chrome/test/chromedriver/element_util.cc b/chrome/test/chromedriver/element_util.cc
index 33a4c7b..4f13ca5 100644
--- a/chrome/test/chromedriver/element_util.cc
+++ b/chrome/test/chromedriver/element_util.cc
@@ -402,11 +402,17 @@
                         WebView* web_view,
                         std::unique_ptr<base::Value>* value) {
   base::ListValue args;
-  return web_view->CallFunction(
+  Status status = web_view->CallFunction(
       session->GetCurrentFrameId(),
-      "function() { return document.activeElement || document.body }",
-      args,
+      "function() { return document.activeElement || document.body }", args,
       value);
+  if (status.IsError()) {
+    return status;
+  }
+  if (value->get()->is_none()) {
+    return Status(kNoSuchElement);
+  }
+  return status;
 }
 
 Status IsElementFocused(
diff --git a/chrome/test/data/extensions/manifest_tests/host_permissions_key.json b/chrome/test/data/extensions/manifest_tests/host_permissions_key.json
new file mode 100644
index 0000000..c4e8870
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/host_permissions_key.json
@@ -0,0 +1,12 @@
+{
+  "name": "Host permissions manifest key",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description": "extension with hosts in both |permissions| and |host_permissions|",
+  "permissions": [
+    "https://google.com/*"
+  ],
+  "host_permissions": [
+    "https://example.com/*"
+  ]
+}
diff --git a/chrome/test/data/extensions/manifest_tests/host_permissions_key_invalid_hosts.json b/chrome/test/data/extensions/manifest_tests/host_permissions_key_invalid_hosts.json
new file mode 100644
index 0000000..8414431
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/host_permissions_key_invalid_hosts.json
@@ -0,0 +1,9 @@
+{
+  "name": "Host permissions with malformed host",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description": "Extension with an invalid host in host_permissions",
+  "host_permissions": [
+    "malformed_host"
+  ]
+}
diff --git a/chrome/test/data/extensions/manifest_tests/init_invalid_host_permissions_invalid.json b/chrome/test/data/extensions/manifest_tests/init_invalid_host_permissions_invalid.json
new file mode 100644
index 0000000..f065b4f
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/init_invalid_host_permissions_invalid.json
@@ -0,0 +1,6 @@
+{
+  "name": "Host permissions not a list",
+  "version": "0.1",
+  "manifest_version": 3,
+  "host_permissions": "Why wont this work?!"
+}
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_strings.js b/chrome/test/data/webui/cr_elements/cr_policy_strings.js
index 5c1c966..8a4583b 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_strings.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_strings.js
@@ -13,4 +13,5 @@
   controlledSettingNoOwner: 'owner',
   controlledSettingExtension: 'extension: $1',
   controlledSettingExtensionWithoutName: 'extension',
+  controlledSettingParent: 'parent',
 };
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_inline_identity_available.html b/chrome/test/data/xr/e2e_test_files/html/test_inline_identity_available.html
index c2ef483..58559d4 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_inline_identity_available.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_inline_identity_available.html
@@ -33,7 +33,7 @@
       navigator.xr.supportsSessionMode('inline')
       .then(()=> {
         step = "requestSession";
-        return navigator.xr.requestSession();
+        return navigator.xr.requestSession('inline');
       })
       .then((xrSession) => {
         session = xrSession;
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_stationary_reference_space_rejects.html b/chrome/test/data/xr/e2e_test_files/html/test_stationary_reference_space_rejects.html
index 12cf99a..85a8ec4a 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_stationary_reference_space_rejects.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_stationary_reference_space_rejects.html
@@ -11,7 +11,7 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script>
       let session_ = null;
-      navigator.xr.requestSession()
+      navigator.xr.requestSession('inline')
       .then((xrSession) => {
         session_ = xrSession;
         return xrSession.requestReferenceSpace({ type: 'stationary', subtype: 'floor-level'});
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html
index 9b061e9..f0514cc 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html
@@ -14,7 +14,7 @@
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
       function onImmersiveRequestWithDon() {
-        navigator.xr.requestSession({mode: 'immersive-vr'}).then( (session) => {
+        navigator.xr.requestSession('immersive-vr').then( (session) => {
           assert_unreached("requestPresent promise resolved");
         }, () => {
           // Do nothing when the promise is rejected
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html
index 58b0882..a6e1566 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html
@@ -14,7 +14,7 @@
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
       function onImmersiveRequestWithDon() {
-        navigator.xr.requestSession({mode: 'immersive-vr'}).then( (session) => {
+        navigator.xr.requestSession('immersive-vr').then( (session) => {
           assert_unreached("requestSession promise resolved");
         }, () => {
           assert_unreached("requestSession promise rejected");
diff --git a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
index d599e2e..f7f2fc0 100644
--- a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
+++ b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
@@ -85,7 +85,7 @@
   switch (sessionTypeToRequest) {
     case sessionTypes.IMMERSIVE:
       console.info('Requesting immersive VR session');
-      navigator.xr.requestSession({mode: 'immersive-vr'}).then( (session) => {
+      navigator.xr.requestSession('immersive-vr').then( (session) => {
         console.info('Immersive VR session request succeeded');
         sessionInfos[sessionTypes.IMMERSIVE].currentSession = session;
         onSessionStarted(session);
@@ -95,17 +95,14 @@
       break;
     case sessionTypes.AR:
       console.info('Requesting Immersive AR session');
-      navigator.xr.requestSession({mode: 'immersive-ar'}).then((session) => {
+      navigator.xr.requestSession('immersive-ar').then((session) => {
         console.info('Immersive AR session request succeeded');
         sessionInfos[sessionTypes.AR].currentSession = session;
         onSessionStarted(session);
       }, (error) => {
         console.info('Immersive AR session request rejected with: ' + error);
         console.info('Attempting to fall back to legacy AR mode');
-        let sessionOptions = {
-          mode: 'legacy-inline-ar'
-        }
-        navigator.xr.requestSession(sessionOptions).then(
+        navigator.xr.requestSession('legacy-inline-ar').then(
             (session) => {
           session.updateRenderState({
               outputContext: webglCanvas.getContext('xrpresent')
@@ -198,7 +195,7 @@
   // Set up an inline session (magic window) drawing into the full screen canvas
   // on the page
   let ctx = webglCanvas.getContext('xrpresent');
-  navigator.xr.requestSession()
+  navigator.xr.requestSession('inline')
   .then((session) => {
     session.updateRenderState({
       outputContext: ctx
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index db9ef80..8dc9ba6 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -1055,25 +1055,12 @@
   return chromecast::shell::GetUserAgent();
 }
 
-void CastContentBrowserClient::RegisterOutOfProcessServices(
-    OutOfProcessServiceMap* services) {
-#if !defined(OS_FUCHSIA)
-  if (!heap_profiling::IsInProcessModeEnabled()) {
-    services->emplace(
-        heap_profiling::mojom::kServiceName,
-        base::BindRepeating(&base::ASCIIToUTF16, "Profiling Service"));
-  }
-#endif  // !defined(OS_FUCHSIA)
-}
-
 void CastContentBrowserClient::RegisterIOThreadServiceHandlers(
     content::ServiceManagerConnection* connection) {
 #if !defined(OS_FUCHSIA)
-  if (heap_profiling::IsInProcessModeEnabled()) {
-    connection->AddServiceRequestHandler(
-        heap_profiling::mojom::kServiceName,
-        heap_profiling::HeapProfilingService::GetServiceFactory());
-  }
+  connection->AddServiceRequestHandler(
+      heap_profiling::mojom::kServiceName,
+      heap_profiling::HeapProfilingService::GetServiceFactory());
 #endif  // !defined(OS_FUCHSIA)
 }
 
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 9d0d443..6c96f35 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -218,7 +218,6 @@
       bool in_memory,
       const base::FilePath& relative_partition_path) override;
   std::string GetUserAgent() const override;
-  void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override;
   void RegisterIOThreadServiceHandlers(
       content::ServiceManagerConnection* connection) override;
   bool DoesSiteRequireDedicatedProcess(
diff --git a/components/autofill/core/browser/label_formatter_utils.cc b/components/autofill/core/browser/label_formatter_utils.cc
index 69e51e7..aaaf9ef 100644
--- a/components/autofill/core/browser/label_formatter_utils.cc
+++ b/components/autofill/core/browser/label_formatter_utils.cc
@@ -245,4 +245,48 @@
                    data_util::GetCountryCodeWithFallback(profile, app_locale)));
 }
 
+bool HaveSameEmailAddresses(const std::vector<AutofillProfile*>& profiles,
+                            const std::string& app_locale) {
+  bool first_email_found = false;
+  base::string16 first_email;
+
+  for (const AutofillProfile* profile : profiles) {
+    base::string16 email_from_profile = GetLabelEmail(*profile, app_locale);
+
+    if (!first_email_found) {
+      // Store the first email address whether it's empty or not because we
+      // consider "" and "hao.le@aol.com" to be different email addresses.
+      first_email_found = true;
+      first_email = email_from_profile;
+    } else if (email_from_profile != first_email) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool HaveSamePhoneNumbers(const std::vector<AutofillProfile*>& profiles,
+                          const std::string& app_locale) {
+  bool first_phone_found = false;
+  base::string16 first_phone;
+
+  for (const AutofillProfile* profile : profiles) {
+    base::string16 phone_from_profile = GetLabelPhone(*profile, app_locale);
+
+    if (!first_phone_found) {
+      // Store the first phone number whether it's empty or not because we
+      // consider "" and "(514) 873-1100" to be different phone numbers.
+      first_phone_found = true;
+      first_phone = phone_from_profile;
+    } else if (!(first_phone.empty() && phone_from_profile.empty()) &&
+               !i18n::PhoneNumbersMatch(first_phone, phone_from_profile,
+                                        base::UTF16ToASCII(profile->GetInfo(
+                                            ADDRESS_HOME_COUNTRY, app_locale)),
+                                        app_locale)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/label_formatter_utils.h b/components/autofill/core/browser/label_formatter_utils.h
index 3ded23b..f9d523c 100644
--- a/components/autofill/core/browser/label_formatter_utils.h
+++ b/components/autofill/core/browser/label_formatter_utils.h
@@ -103,8 +103,9 @@
 // |profile|. If |focused_field_type| is a street address field, then returns
 // non-street-address data, e.g. Lowell, MA 01852.
 //
-// If the focused type is not a street address field and if |form_has_street_
-// address| is true, then returns street-address data, e.g. 375 Merrimack St.
+// If the focused type is not a street address field and if
+// |form_has_street_address| is true, then returns street-address data, e.g. 375
+// Merrimack St.
 //
 // If the focused type is not a street address field and if the form does not
 // have a street address, then returns the parts of the address in the form
@@ -163,6 +164,18 @@
 base::string16 GetLabelPhone(const AutofillProfile& profile,
                              const std::string& app_locale);
 
+// Returns true if all |profiles| have the same email address. Note that the
+// absence of an email address and an actual email address, e.g.
+// joe.bray@aol.com, are considered different email addresses.
+bool HaveSameEmailAddresses(const std::vector<AutofillProfile*>& profiles,
+                            const std::string& app_locale);
+
+// Returns true if all |profiles| have the same phone number after
+// normalization. Note that the absence of a phone number and an actual phone
+// number, e.g. (401) 847-8720, are considered different phone numbers.
+bool HaveSamePhoneNumbers(const std::vector<AutofillProfile*>& profiles,
+                          const std::string& app_locale);
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_UTILS_H_
diff --git a/components/autofill/core/browser/label_formatter_utils_unittest.cc b/components/autofill/core/browser/label_formatter_utils_unittest.cc
index c0383ae..806aac0 100644
--- a/components/autofill/core/browser/label_formatter_utils_unittest.cc
+++ b/components/autofill/core/browser/label_formatter_utils_unittest.cc
@@ -4,8 +4,12 @@
 
 #include "components/autofill/core/browser/label_formatter_utils.h"
 
+#include "base/guid.h"
+#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -92,4 +96,150 @@
             ConstructLabelLine({name, phone, email}));
 }
 
-}  // namespace autofill
\ No newline at end of file
+TEST(LabelFormatterUtilsTest,
+     HaveSameEmailAddressesWithOneProfileAndNoEmailAddress) {
+  AutofillProfile profile =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch",
+                       "mmkirch@gmx.de", "", "", "", "", "", "", "DE", "");
+  EXPECT_TRUE(HaveSameEmailAddresses({&profile}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSameEmailAddressesWithOneProfileAndEmailAddress) {
+  AutofillProfile profile =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", "", "", "", "",
+                       "", "", "", "DE", "");
+  EXPECT_TRUE(HaveSameEmailAddresses({&profile}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSameEmailAddressesWithProfilesAndNoEmailAddresses) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "",
+                       "", "", "", "", "DE", "");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "");
+  EXPECT_TRUE(HaveSameEmailAddresses({&profile1, &profile2}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSameEmailAddressesWithProfilesAndSameEmailAddresses) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch",
+                       "mmkirch@gmx.de", "", "", "", "", "", "", "DE", "");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann",
+                       "mmkirch@gmx.de", "", "", "", "", "", "", "DE", "");
+  EXPECT_TRUE(HaveSameEmailAddresses({&profile1, &profile2}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSameEmailAddressesWithProfilesAndDifferentNonEmptyEmailAddresses) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch",
+                       "mmkirch@gmx.de", "", "", "", "", "", "", "DE", "");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann",
+                       "mmw@gmail.com", "", "", "", "", "", "", "DE", "");
+  EXPECT_FALSE(HaveSameEmailAddresses({&profile1, &profile2}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSameEmailAddressesWithProfilesAndNonEmptyAndEmptyEmailAddresses) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch",
+                       "mmkirch@gmx.de", "", "", "", "", "", "", "DE", "");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "");
+  EXPECT_FALSE(HaveSameEmailAddresses({&profile1, &profile2}, "de"));
+  EXPECT_FALSE(HaveSameEmailAddresses({&profile2, &profile1}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSamePhoneNumbersWithOneProfileAndNoPhoneNumber) {
+  AutofillProfile profile =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", "", "", "", "",
+                       "", "", "", "DE", "");
+  EXPECT_TRUE(HaveSamePhoneNumbers({&profile}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSamePhoneNumbersWithOneProfileAndPhoneNumber) {
+  AutofillProfile profile =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", "", "", "", "",
+                       "", "", "", "DE", "+49 30 4504-2823");
+  EXPECT_TRUE(HaveSamePhoneNumbers({&profile}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSamePhoneNumbersWithProfilesAndNoPhoneNumber) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "",
+                       "", "", "", "", "DE", "");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "");
+  EXPECT_TRUE(HaveSamePhoneNumbers({&profile1, &profile2}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSamePhoneNumbersWithProfilesAndSamePhoneNumbers) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "",
+                       "", "", "", "", "DE", "+49 30 4504-2823");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "4903045042823");
+  AutofillProfile profile3 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile3, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "03045042823");
+  EXPECT_TRUE(HaveSamePhoneNumbers({&profile1, &profile2, &profile3}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSamePhoneNumbersWithProfilesAndDifferentNonEmptyPhoneNumbers) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "",
+                       "", "", "", "", "DE", "+49 30 4504-2823");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "+49 221 22123828");
+  EXPECT_FALSE(HaveSamePhoneNumbers({&profile1, &profile2}, "de"));
+}
+
+TEST(LabelFormatterUtilsTest,
+     HaveSamePhoneNumbersWithProfilesAndNonEmptyAndEmptyPhoneNumbers) {
+  AutofillProfile profile1 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "",
+                       "", "", "", "", "DE", "+49 30 4504-2823");
+  AutofillProfile profile2 =
+      AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "",
+                       "", "", "", "", "", "DE", "");
+  EXPECT_FALSE(HaveSamePhoneNumbers({&profile1, &profile2}, "de"));
+  EXPECT_FALSE(HaveSamePhoneNumbers({&profile2, &profile1}, "de"));
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/phone_number_i18n.cc b/components/autofill/core/browser/phone_number_i18n.cc
index 956eed00..ecfbe9a 100644
--- a/components/autofill/core/browser/phone_number_i18n.cc
+++ b/components/autofill/core/browser/phone_number_i18n.cc
@@ -265,6 +265,8 @@
                        const base::string16& number_b,
                        const std::string& raw_region,
                        const std::string& app_locale) {
+  // TODO(crbug.com/953678): Maybe return true if two empty strings are given.
+
   // Sanitize the provided |raw_region| before trying to use it for parsing.
   const std::string region = SanitizeRegion(raw_region, app_locale);
 
diff --git a/components/heap_profiling/heap_profiling_test_shim.cc b/components/heap_profiling/heap_profiling_test_shim.cc
index bae0523..5c952f0 100644
--- a/components/heap_profiling/heap_profiling_test_shim.cc
+++ b/components/heap_profiling/heap_profiling_test_shim.cc
@@ -32,7 +32,6 @@
     const base::android::JavaParamRef<jstring>& mode,
     jboolean dynamically_start_profiling,
     const base::android::JavaParamRef<jstring>& stack_mode,
-    jboolean stream_samples,
     jboolean should_sample,
     jboolean sample_everything) {
   heap_profiling::TestDriver driver;
@@ -42,7 +41,6 @@
   options.stack_mode = heap_profiling::ConvertStringToStackMode(
       base::android::ConvertJavaStringToUTF8(stack_mode));
   options.profiling_already_started = !dynamically_start_profiling;
-  options.stream_samples = stream_samples;
   options.should_sample = should_sample;
   options.sample_everything = sample_everything;
   return driver.RunTest(options);
diff --git a/components/heap_profiling/heap_profiling_test_shim.h b/components/heap_profiling/heap_profiling_test_shim.h
index 558933c..134d548 100644
--- a/components/heap_profiling/heap_profiling_test_shim.h
+++ b/components/heap_profiling/heap_profiling_test_shim.h
@@ -23,7 +23,6 @@
       const base::android::JavaParamRef<jstring>& mode,
       jboolean dynamically_start_profiling,
       const base::android::JavaParamRef<jstring>& stack_mode,
-      jboolean stream_samples,
       jboolean should_sample,
       jboolean sample_everything);
 
diff --git a/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java b/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java
index c7f788e..f55ceaf 100644
--- a/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java
+++ b/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java
@@ -23,9 +23,9 @@
      *  rather than native stacks.
      */
     public boolean runTestForMode(String mode, boolean dynamicallyStartProfiling, String stackMode,
-            boolean streamSamples, boolean shouldSample, boolean sampleEverything) {
+            boolean shouldSample, boolean sampleEverything) {
         return nativeRunTestForMode(mNativeHeapProfilingTestShim, mode, dynamicallyStartProfiling,
-                stackMode, streamSamples, shouldSample, sampleEverything);
+                stackMode, shouldSample, sampleEverything);
     }
 
     /**
@@ -43,6 +43,6 @@
     private native long nativeInit();
     private native void nativeDestroy(long nativeHeapProfilingTestShim);
     private native boolean nativeRunTestForMode(long nativeHeapProfilingTestShim, String mode,
-            boolean dynamicallyStartProfiling, String stackMode, boolean streamSamples,
-            boolean shouldSample, boolean sampleEverything);
+            boolean dynamicallyStartProfiling, String stackMode, boolean shouldSample,
+            boolean sampleEverything);
 }
diff --git a/components/heap_profiling/supervisor.cc b/components/heap_profiling/supervisor.cc
index 57609f1..8406aa7 100644
--- a/components/heap_profiling/supervisor.cc
+++ b/components/heap_profiling/supervisor.cc
@@ -60,26 +60,24 @@
 
 void Supervisor::Start(content::ServiceManagerConnection* connection,
                        base::OnceClosure closure) {
-  bool stream_samples = !IsInProcessModeEnabled();
   Start(connection, GetModeForStartup(), GetStackModeForStartup(),
-        stream_samples, GetSamplingRateForStartup(), std::move(closure));
+        GetSamplingRateForStartup(), std::move(closure));
 }
 
 void Supervisor::Start(content::ServiceManagerConnection* connection,
                        Mode mode,
                        mojom::StackMode stack_mode,
-                       bool stream_samples,
                        uint32_t sampling_rate,
                        base::OnceClosure closure) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(!started_);
 
   base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})
-      ->PostTask(FROM_HERE, base::BindOnce(&Supervisor::StartServiceOnIOThread,
-                                           base::Unretained(this),
-                                           connection->GetConnector()->Clone(),
-                                           mode, stack_mode, stream_samples,
-                                           sampling_rate, std::move(closure)));
+      ->PostTask(FROM_HERE,
+                 base::BindOnce(&Supervisor::StartServiceOnIOThread,
+                                base::Unretained(this),
+                                connection->GetConnector()->Clone(), mode,
+                                stack_mode, sampling_rate, std::move(closure)));
 }
 
 Mode Supervisor::GetMode() {
@@ -171,13 +169,12 @@
     std::unique_ptr<service_manager::Connector> connector,
     Mode mode,
     mojom::StackMode stack_mode,
-    bool stream_samples,
     uint32_t sampling_rate,
     base::OnceClosure closure) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
 
-  controller_.reset(new Controller(std::move(connector), stack_mode,
-                                   stream_samples, sampling_rate));
+  controller_.reset(
+      new Controller(std::move(connector), stack_mode, sampling_rate));
   base::WeakPtr<Controller> controller_weak_ptr = controller_->GetWeakPtr();
 
   base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI})
diff --git a/components/heap_profiling/supervisor.h b/components/heap_profiling/supervisor.h
index fdaf4abb..4bd167c 100644
--- a/components/heap_profiling/supervisor.h
+++ b/components/heap_profiling/supervisor.h
@@ -72,7 +72,6 @@
   void Start(content::ServiceManagerConnection* connection,
              Mode mode,
              mojom::StackMode stack_mode,
-             bool stream_samples,
              uint32_t sampling_rate,
              base::OnceClosure callback);
 
@@ -113,7 +112,6 @@
       std::unique_ptr<service_manager::Connector> connector,
       Mode mode,
       mojom::StackMode stack_mode,
-      bool stream_samples,
       uint32_t sampling_rate,
       base::OnceClosure callback);
 
diff --git a/components/heap_profiling/test_driver.cc b/components/heap_profiling/test_driver.cc
index d9f6ed9..1bcedae 100644
--- a/components/heap_profiling/test_driver.cc
+++ b/components/heap_profiling/test_driver.cc
@@ -711,8 +711,8 @@
                                ? (options_.sample_everything ? 2 : kSampleRate)
                                : 1;
   Supervisor::GetInstance()->Start(connection, options_.mode,
-                                   options_.stack_mode, options_.stream_samples,
-                                   sampling_rate, std::move(start_callback));
+                                   options_.stack_mode, sampling_rate,
+                                   std::move(start_callback));
 
   return true;
 }
@@ -764,8 +764,8 @@
                                ? (options_.sample_everything ? 2 : kSampleRate)
                                : 1;
   Supervisor::GetInstance()->Start(connection, options_.mode,
-                                   options_.stack_mode, options_.stream_samples,
-                                   sampling_rate, std::move(start_callback));
+                                   options_.stack_mode, sampling_rate,
+                                   std::move(start_callback));
 
   run_loop->Run();
 
diff --git a/components/heap_profiling/test_driver.h b/components/heap_profiling/test_driver.h
index 2cc761b..ebf1363 100644
--- a/components/heap_profiling/test_driver.h
+++ b/components/heap_profiling/test_driver.h
@@ -49,11 +49,6 @@
     // The stack profiling mode to test.
     mojom::StackMode stack_mode = mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES;
 
-    // Whether the client should stream samples as they are collected through
-    // the provided pipe. When false the samples are accumulated on the client
-    // side and can be retrieved later.
-    bool stream_samples = true;
-
     // Whether the caller has already started profiling with the given mode.
     // When false, the test driver is responsible for starting profiling.
     bool profiling_already_started = false;
diff --git a/components/mirroring/service/mirror_settings.cc b/components/mirroring/service/mirror_settings.cc
index 3c51c1e..14f337d 100644
--- a/components/mirroring/service/mirror_settings.cc
+++ b/components/mirroring/service/mirror_settings.cc
@@ -21,17 +21,16 @@
 constexpr base::TimeDelta kAnimatedPlayoutDelay =
     base::TimeDelta::FromMilliseconds(400);
 
-// Minimum end-to-end latency. This allows cast streaming to adaptively lower
-// latency in interactive streaming scenarios.
-// TODO(miu): This was 120 before stable launch, but we got user feedback that
-// this was causing audio drop-outs. So, we need to fix the Cast Streaming
-// implementation before lowering this setting.
+// Minimum end-to-end latency.
 constexpr base::TimeDelta kMinPlayoutDelay =
     base::TimeDelta::FromMilliseconds(400);
 
-// Maximum end-to-end latency.
+// Maximum end-to-end latency.  Currently, this is kMinPlayoutDelay, effectively
+// disabling adaptive latency control, because of audio playout regressions
+// (b/32876644).
+// TODO(https://crbug.com/openscreen/44): Re-enable in port to Open Screen.
 constexpr base::TimeDelta kMaxPlayoutDelay =
-    base::TimeDelta::FromMilliseconds(800);
+    base::TimeDelta::FromMilliseconds(400);
 
 constexpr int kAudioTimebase = 48000;
 constexpr int kVidoTimebase = 90000;
diff --git a/components/neterror/resources/offline.js b/components/neterror/resources/offline.js
index de4b80dd..99c112b 100644
--- a/components/neterror/resources/offline.js
+++ b/components/neterror/resources/offline.js
@@ -118,7 +118,7 @@
   GRAVITY: 0.6,
   INITIAL_JUMP_VELOCITY: 12,
   INVERT_FADE_DURATION: 12000,
-  INVERT_DISTANCE: 100,
+  INVERT_DISTANCE: 700,
   MAX_BLINK_COUNT: 3,
   MAX_CLOUDS: 6,
   MAX_OBSTACLE_LENGTH: 3,
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index eb722502..c1e692d 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -664,7 +664,9 @@
       i->description.clear();
       i->description_class.clear();
       DCHECK(!i->keyword.empty());
-      if (i->keyword != last_keyword || show_suffix_on_all_search_suggestions) {
+      if (show_suffix_on_all_search_suggestions ||
+          (i->keyword != last_keyword &&
+           !ShouldCurbKeywordDescriptions(i->keyword))) {
         const TemplateURL* template_url =
             i->GetTemplateURL(template_url_service_, false);
         if (template_url) {
@@ -790,6 +792,12 @@
   }
 }
 
+bool AutocompleteController::ShouldCurbKeywordDescriptions(
+    const base::string16& keyword) {
+  return AutocompleteProvider::InExplicitExperimentalKeywordMode(input_,
+                                                                 keyword);
+}
+
 bool AutocompleteController::OnMemoryDump(
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* process_memory_dump) {
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 56899b6..bd0192d 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -204,6 +204,11 @@
   void StopHelper(bool clear_result,
                   bool due_to_user_inactivity);
 
+  // Helper for UpdateKeywordDescriptions(). Returns whether curbing the keyword
+  // descriptions is enabled, and whether there is enough input to guarantee
+  // that the Omnibox is in keyword mode.
+  bool ShouldCurbKeywordDescriptions(const base::string16& keyword);
+
   // MemoryDumpProvider:
   bool OnMemoryDump(
       const base::trace_event::MemoryDumpArgs& args,
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 0053538..1f7d33e 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -229,7 +229,6 @@
       return omnibox::kPageIcon;
 
     case Type::SEARCH_WHAT_YOU_TYPED:
-    case Type::SEARCH_HISTORY:
     case Type::SEARCH_SUGGEST:
     case Type::SEARCH_SUGGEST_ENTITY:
     case Type::SEARCH_SUGGEST_PERSONALIZED:
@@ -241,6 +240,14 @@
     case Type::CLIPBOARD_IMAGE:
       return vector_icons::kSearchIcon;
 
+    case Type::SEARCH_HISTORY: {
+      if (base::FeatureList::IsEnabled(
+              omnibox::kOmniboxSuggestionTransparencyOptions)) {
+        return omnibox::kClockIcon;
+      }
+      return vector_icons::kSearchIcon;
+    }
+
     case Type::EXTENSION_APP_DEPRECATED:
       return omnibox::kExtensionAppIcon;
 
diff --git a/components/omnibox/browser/autocomplete_provider.cc b/components/omnibox/browser/autocomplete_provider.cc
index ebdf86b..854de5e 100644
--- a/components/omnibox/browser/autocomplete_provider.cc
+++ b/components/omnibox/browser/autocomplete_provider.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
@@ -240,3 +241,24 @@
   url->erase(scheme_pos, prefix_end - scheme_pos);
   return (scheme_pos == 0) ? prefix_end : 0;
 }
+
+// static
+bool AutocompleteProvider::InExplicitExperimentalKeywordMode(
+    const AutocompleteInput& input,
+    const base::string16& keyword) {
+  // It is important to this method that we determine if the user entered
+  // keyword mode intentionally, as we use this routine to e.g. filter
+  // all but keyword results. Currently we assume that the user entered
+  // keyword mode intentionally with all entry methods except with a
+  // space. However, if the user has typed a char past the space, we
+  // again assume keyword mode.
+  return OmniboxFieldTrial::IsExperimentalKeywordModeEnabled() &&
+         input.prefer_keyword() &&
+         base::StartsWith(input.text(), keyword,
+                          base::CompareCase::SENSITIVE) &&
+         ((input.keyword_mode_entry_method() !=
+               metrics::OmniboxEventProto::SPACE_AT_END &&
+           input.keyword_mode_entry_method() !=
+               metrics::OmniboxEventProto::SPACE_IN_MIDDLE) ||
+          input.text().size() > keyword.size() + 1);
+}
diff --git a/components/omnibox/browser/autocomplete_provider.h b/components/omnibox/browser/autocomplete_provider.h
index ee5d54a..ed0aa38 100644
--- a/components/omnibox/browser/autocomplete_provider.h
+++ b/components/omnibox/browser/autocomplete_provider.h
@@ -279,6 +279,13 @@
   // culling.
   static const size_t kMaxMatches;
 
+  // Used to determine if we're in keyword mode, if experimental keyword
+  // mode is enabled, and if we're confident that the user is intentionally
+  // (not accidentally) in keyword mode. Combined, this method returns
+  // whether the caller should perform steps that are only valid in this state.
+  static bool InExplicitExperimentalKeywordMode(const AutocompleteInput& input,
+                                                const base::string16& keyword);
+
  protected:
   friend class base::RefCountedThreadSafe<AutocompleteProvider>;
   FRIEND_TEST_ALL_PREFIXES(BookmarkProviderTest, InlineAutocompletion);
diff --git a/components/omnibox/browser/builtin_provider.cc b/components/omnibox/browser/builtin_provider.cc
index 6a35f7b..db7b32a 100644
--- a/components/omnibox/browser/builtin_provider.cc
+++ b/components/omnibox/browser/builtin_provider.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match_classification.h"
 #include "components/omnibox/browser/autocomplete_provider_client.h"
 #include "components/omnibox/browser/history_provider.h"
 #include "components/url_formatter/url_fixer.h"
@@ -49,18 +50,20 @@
                                          base::CompareCase::INSENSITIVE_ASCII);
   if (starting_about ||
       base::StartsWith(kAbout, text, base::CompareCase::INSENSITIVE_ASCII)) {
-    ACMatchClassifications styles;
     // Highlight the input portion matching |embedderAbout|; or if the user has
     // input "about:" (with optional slashes), highlight the whole
     // |embedderAbout|.
-    bool highlight = starting_about || text.length() > kAboutSchemeLength;
-    styles.push_back(ACMatchClassification(0, highlight ? kMatch : kUrl));
-    size_t offset = starting_about ? text.length() : embedderAbout.length();
-    if (highlight)
-      styles.push_back(ACMatchClassification(offset, kUrl));
+    TermMatches style_matches;
+    if (starting_about)
+      style_matches.emplace_back(0, 0, text.length());
+    else if (text.length() > kAboutSchemeLength)
+      style_matches.emplace_back(0, 0, embedderAbout.length());
+    ACMatchClassifications styles =
+        ClassifyTermMatches(style_matches, std::string::npos, kMatch, kUrl);
     // Include some common builtin URLs as the user types the scheme.
     for (base::string16 url : client_->GetBuiltinsToProvideAsUserTypes())
       AddMatch(url, base::string16(), styles);
+
   } else {
     // Match input about: or |embedderAbout| URL input against builtin URLs.
     GURL url = url_formatter::FixupURL(base::UTF16ToUTF8(text), std::string());
@@ -80,13 +83,11 @@
           base::StartsWith(blank_host, host,
                            base::CompareCase::INSENSITIVE_ASCII) &&
           (url.path().length() <= 1) && !text_ends_with_slash) {
-        ACMatchClassifications styles;
-        styles.push_back(ACMatchClassification(0, kMatch));
         base::string16 match = base::ASCIIToUTF16(url::kAboutBlankURL);
-        // Measure the length of the matching host after the "about:" scheme.
         const size_t corrected_length = kAboutSchemeLength + 1 + host.length();
-        if (blank_host.length() > host.length())
-          styles.push_back(ACMatchClassification(corrected_length, kUrl));
+        TermMatches style_matches = {{0, 0, corrected_length}};
+        ACMatchClassifications styles =
+            ClassifyTermMatches(style_matches, match.length(), kMatch, kUrl);
         AddMatch(match, match.substr(corrected_length), styles);
       }
 
@@ -98,12 +99,10 @@
           (i != builtins_.end()) && (matches_.size() < kMaxMatches); ++i) {
         if (base::StartsWith(*i, host_and_path,
                              base::CompareCase::INSENSITIVE_ASCII)) {
-          ACMatchClassifications styles;
-          // Highlight |embedderAbout|, even for input "about:foo".
-          styles.push_back(ACMatchClassification(0, kMatch));
           base::string16 match_string = embedderAbout + *i;
-          if (match_string.length() > match_length)
-            styles.push_back(ACMatchClassification(match_length, kUrl));
+          TermMatches style_matches = {{0, 0, match_length}};
+          ACMatchClassifications styles = ClassifyTermMatches(
+              style_matches, match_string.length(), kMatch, kUrl);
           // FixupURL() may have dropped a trailing slash on the user's input.
           // Ensure that in that case, we don't inline autocomplete unless the
           // autocompletion restores the slash.  This prevents us from e.g.
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc
index 1259510a..1f2a805 100644
--- a/components/omnibox/browser/search_provider.cc
+++ b/components/omnibox/browser/search_provider.cc
@@ -1366,17 +1366,12 @@
 
 bool SearchProvider::ShouldCurbDefaultSuggestions() const {
   // Only curb if the global experimental keyword feature is enabled, we're
-  // in keyword mode and the user selected the mode explicitly. For now, we
-  // consider entering keyword mode with spaces to be unintentional and all
-  // other methods as intentional. In this experimental mode, we don't want
-  // non-keyword suggestions if we're not confident that the user entered
-  // keyword mode explicitly.
-  return OmniboxFieldTrial::IsExperimentalKeywordModeEnabled() &&
-         keyword_input_.prefer_keyword() &&
-         keyword_input_.keyword_mode_entry_method() !=
-             OmniboxEventProto::SPACE_AT_END &&
-         keyword_input_.keyword_mode_entry_method() !=
-             OmniboxEventProto::SPACE_IN_MIDDLE;
+  // in keyword mode and we believe the user selected the mode explicitly.
+  if (providers_.has_keyword_provider())
+    return InExplicitExperimentalKeywordMode(input_,
+                                             providers_.keyword_provider());
+  else
+    return false;
 }
 
 int SearchProvider::CalculateRelevanceForVerbatim() const {
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index fb70e47..0d23ec6 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -2006,7 +2006,7 @@
       'id': 525,
       'caption': '''Restrict PIN printing mode''',
       'tags': [],
-      'desc': '''Restricts PIN printing mode. Unset policy is treated as no restriction. If the mode is unavailable this policy is ignored.''',
+      'desc': '''Restricts PIN printing mode. Unset policy is treated as no restriction. If the mode is unavailable this policy is ignored. Note that PIN printing feature is enabled only for printers that use one of IPPS, USB or IPP-over-USB protocols ''',
     },
     {
       'name': 'PrintingAllowedPageSizes',
diff --git a/components/printing/browser/printer_capabilities.cc b/components/printing/browser/printer_capabilities.cc
index 4f79764..d3f1706 100644
--- a/components/printing/browser/printer_capabilities.cc
+++ b/components/printing/browser/printer_capabilities.cc
@@ -58,6 +58,7 @@
 base::Value GetPrinterCapabilitiesOnBlockingPoolThread(
     const std::string& device_name,
     const PrinterSemanticCapsAndDefaults::Papers& additional_papers,
+    bool has_secure_protocol,
     scoped_refptr<PrintBackend> print_backend) {
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
@@ -86,6 +87,11 @@
 #endif
   info.papers.insert(info.papers.end(), additional_papers.begin(),
                      additional_papers.end());
+#if defined(CHROMEOS)
+  if (!has_secure_protocol)
+    info.pin_supported = false;
+#endif  // defined(CHROMEOS)
+
   return cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info);
 }
 
@@ -136,6 +142,7 @@
     const std::string& device_name,
     const PrinterBasicInfo& basic_info,
     const PrinterSemanticCapsAndDefaults::Papers& additional_papers,
+    bool has_secure_protocol,
     scoped_refptr<PrintBackend> print_backend) {
   SCOPED_UMA_HISTOGRAM_TIMER("Printing.PrinterCapabilities");
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
@@ -159,8 +166,9 @@
   base::Value printer_info_capabilities(base::Value::Type::DICTIONARY);
   printer_info_capabilities.SetKey(kPrinter, std::move(printer_info));
   printer_info_capabilities.SetKey(
-      kSettingCapabilities, GetPrinterCapabilitiesOnBlockingPoolThread(
-                                device_name, additional_papers, print_backend));
+      kSettingCapabilities,
+      GetPrinterCapabilitiesOnBlockingPoolThread(
+          device_name, additional_papers, has_secure_protocol, print_backend));
   return printer_info_capabilities;
 }
 
diff --git a/components/printing/browser/printer_capabilities.h b/components/printing/browser/printer_capabilities.h
index 698af12..d64566fa 100644
--- a/components/printing/browser/printer_capabilities.h
+++ b/components/printing/browser/printer_capabilities.h
@@ -29,12 +29,13 @@
 // for passage to the WebUI. The settings are obtained using |print_backend| if
 // it is provided. If |print_backend| is null, uses a new PrintBackend instance
 // with default settings.
-// Data from |basic_info| and |additional_papers| are incorporated into the
-// returned dictionary.
+// Data from |basic_info|, |additional_papers| and |has_secure_protocol| are
+// incorporated into the returned dictionary.
 base::Value GetSettingsOnBlockingPool(
     const std::string& device_name,
     const PrinterBasicInfo& basic_info,
     const PrinterSemanticCapsAndDefaults::Papers& additional_papers,
+    bool has_secure_protocol,
     scoped_refptr<PrintBackend> print_backend);
 
 }  // namespace printing
diff --git a/components/printing/browser/printer_capabilities_unittest.cc b/components/printing/browser/printer_capabilities_unittest.cc
index ec5b23a..446f8d5 100644
--- a/components/printing/browser/printer_capabilities_unittest.cc
+++ b/components/printing/browser/printer_capabilities_unittest.cc
@@ -52,8 +52,9 @@
   PrinterBasicInfo basic_info;
   PrinterSemanticCapsAndDefaults::Papers no_additional_papers;
 
-  base::Value settings_dictionary = GetSettingsOnBlockingPool(
-      printer_name, basic_info, no_additional_papers, nullptr);
+  base::Value settings_dictionary =
+      GetSettingsOnBlockingPool(printer_name, basic_info, no_additional_papers,
+                                /* has_secure_protocol */ false, nullptr);
 
   ASSERT_FALSE(settings_dictionary.DictEmpty());
 }
@@ -69,7 +70,8 @@
   print_backend()->AddValidPrinter(printer_name, std::move(caps));
 
   base::Value settings_dictionary = GetSettingsOnBlockingPool(
-      printer_name, basic_info, no_additional_papers, print_backend());
+      printer_name, basic_info, no_additional_papers,
+      /* has_secure_protocol */ false, print_backend());
 
   // Verify settings were created.
   ASSERT_FALSE(settings_dictionary.DictEmpty());
@@ -98,7 +100,8 @@
   print_backend()->AddValidPrinter(printer_name, nullptr);
 
   base::Value settings_dictionary = GetSettingsOnBlockingPool(
-      printer_name, basic_info, no_additional_papers, print_backend());
+      printer_name, basic_info, no_additional_papers,
+      /* has_secure_protocol */ false, print_backend());
 
   // Verify settings were created.
   ASSERT_FALSE(settings_dictionary.DictEmpty());
@@ -125,7 +128,8 @@
   additional_papers.push_back({"bar", "vendor", {600, 600}});
 
   base::Value settings_dictionary = GetSettingsOnBlockingPool(
-      printer_name, basic_info, additional_papers, print_backend());
+      printer_name, basic_info, additional_papers,
+      /* has_secure_protocol */ false, print_backend());
 
   // Verify settings were created.
   ASSERT_FALSE(settings_dictionary.DictEmpty());
@@ -182,4 +186,39 @@
   EXPECT_EQ(600, height->GetInt());
 }
 
+#if defined(CHROMEOS)
+TEST_F(PrinterCapabilitiesTest, HasNotSecureProtocol) {
+  std::string printer_name = "test_printer";
+  PrinterBasicInfo basic_info;
+  PrinterSemanticCapsAndDefaults::Papers no_additional_papers;
+  bool has_secure_protocol = false;
+
+  // Set a capability and add a valid printer.
+  auto caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
+  caps->pin_supported = true;
+  print_backend()->AddValidPrinter(printer_name, std::move(caps));
+
+  base::Value settings_dictionary =
+      GetSettingsOnBlockingPool(printer_name, basic_info, no_additional_papers,
+                                has_secure_protocol, print_backend());
+
+  // Verify settings were created.
+  ASSERT_FALSE(settings_dictionary.DictEmpty());
+
+  // Verify there is a CDD with a printer entry.
+  const Value* cdd = settings_dictionary.FindKeyOfType(kSettingCapabilities,
+                                                       Value::Type::DICTIONARY);
+  ASSERT_TRUE(cdd);
+  const Value* printer = cdd->FindKeyOfType(kPrinter, Value::Type::DICTIONARY);
+  ASSERT_TRUE(printer);
+
+  // Verify that pin is not supported.
+  const Value* pin = printer->FindKeyOfType("pin", Value::Type::DICTIONARY);
+  ASSERT_TRUE(pin);
+  base::Optional<bool> pin_supported = pin->FindBoolKey("supported");
+  ASSERT_TRUE(pin_supported.has_value());
+  ASSERT_FALSE(pin_supported.value());
+}
+#endif  // defined(CHROMEOS)
+
 }  // namespace printing
diff --git a/components/services/heap_profiling/BUILD.gn b/components/services/heap_profiling/BUILD.gn
index a319417..1856fba 100644
--- a/components/services/heap_profiling/BUILD.gn
+++ b/components/services/heap_profiling/BUILD.gn
@@ -2,15 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//testing/libfuzzer/fuzzer_test.gni")
-
 static_library("heap_profiling") {
   sources = [
     "address.h",
     "allocation_event.cc",
     "allocation_event.h",
-    "allocation_tracker.cc",
-    "allocation_tracker.h",
     "backtrace.cc",
     "backtrace.h",
     "backtrace_storage.cc",
@@ -21,29 +17,13 @@
     "heap_profiling_service.h",
     "json_exporter.cc",
     "json_exporter.h",
-    "receiver.h",
-    "receiver_pipe.cc",
-    "receiver_pipe.h",
-    "receiver_pipe_win.cc",
-    "receiver_pipe_win.h",
-    "stream_parser.cc",
-    "stream_parser.h",
-    "stream_receiver.h",
   ]
 
   deps = [
     "//base",
     "//components/services/heap_profiling/public/cpp",
     "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
-    "//third_party/zlib",
   ]
-
-  if (is_posix) {
-    sources += [
-      "receiver_pipe_posix.cc",
-      "receiver_pipe_posix.h",
-    ]
-  }
 }
 
 source_set("unit_tests") {
@@ -51,7 +31,6 @@
   sources = [
     "backtrace_storage_unittest.cc",
     "json_exporter_unittest.cc",
-    "stream_parser_unittest.cc",
   ]
   deps = [
     ":heap_profiling",
@@ -60,15 +39,3 @@
     "//testing/gtest",
   ]
 }
-
-fuzzer_test("profiling_fuzzer") {
-  sources = [
-    "stream_fuzzer.cc",
-  ]
-  deps = [
-    ":heap_profiling",
-    "//base",
-  ]
-  libfuzzer_options = [ "max_len = 64000" ]
-  dict = "stream_fuzzer.dict"
-}
diff --git a/components/services/heap_profiling/DEPS b/components/services/heap_profiling/DEPS
index dc1e98b..180644f 100644
--- a/components/services/heap_profiling/DEPS
+++ b/components/services/heap_profiling/DEPS
@@ -2,5 +2,4 @@
   "+components/services/heap_profiling/public",
   "+services/resource_coordinator/public",
   "+services/service_manager",
-  "+third_party/zlib/zlib.h",
 ]
diff --git a/components/services/heap_profiling/allocation_event.h b/components/services/heap_profiling/allocation_event.h
index 3d3726a..bf5c17f 100644
--- a/components/services/heap_profiling/allocation_event.h
+++ b/components/services/heap_profiling/allocation_event.h
@@ -11,10 +11,12 @@
 
 #include "components/services/heap_profiling/address.h"
 #include "components/services/heap_profiling/backtrace_storage.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
+#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
 
 namespace heap_profiling {
 
+using mojom::AllocatorType;
+
 // This class is copyable and assignable.
 //
 // AllocationEvents can be uniquely identified by their address. Caveat: This is
diff --git a/components/services/heap_profiling/allocation_tracker.cc b/components/services/heap_profiling/allocation_tracker.cc
deleted file mode 100644
index 01fe57c..0000000
--- a/components/services/heap_profiling/allocation_tracker.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/allocation_tracker.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/json/string_escape.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/services/heap_profiling/backtrace_storage.h"
-
-namespace heap_profiling {
-
-AllocationTracker::AllocationTracker(CompleteCallback complete_cb,
-                                     BacktraceStorage* backtrace_storage)
-    : complete_callback_(std::move(complete_cb)),
-      backtrace_storage_(backtrace_storage) {}
-
-AllocationTracker::~AllocationTracker() {
-  for (auto& pair : registered_snapshot_callbacks_) {
-    RunnerSnapshotCallbackPair& rsc_pair = pair.second;
-    rsc_pair.first->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(rsc_pair.second), false, AllocationCountMap(),
-                       ContextMap(), AddressToStringMap()));
-  }
-
-  std::vector<const Backtrace*> to_free;
-  to_free.reserve(live_allocs_.size());
-  for (const auto& cur : live_allocs_)
-    to_free.push_back(cur.backtrace());
-  backtrace_storage_->Free(to_free);
-}
-
-void AllocationTracker::OnHeader(const StreamHeader& header) {}
-
-void AllocationTracker::OnAlloc(const AllocPacket& alloc_packet,
-                                std::vector<Address>&& bt,
-                                std::string&& context) {
-  // Compute the context ID for this allocation, 0 means no context.
-  int context_id = 0;
-  if (!context.empty()) {
-    // Escape the strings before saving them, to simplify exporting a heap dump.
-    std::string escaped_context;
-    base::EscapeJSONString(context, false /* put_in_quotes */,
-                           &escaped_context);
-
-    auto inserted_record =
-        context_.emplace(std::piecewise_construct,
-                         std::forward_as_tuple(std::move(escaped_context)),
-                         std::forward_as_tuple(next_context_id_));
-    context_id = inserted_record.first->second;
-    if (inserted_record.second)
-      next_context_id_++;
-  }
-
-  const Backtrace* backtrace = backtrace_storage_->Insert(std::move(bt));
-  live_allocs_.emplace(alloc_packet.allocator, Address(alloc_packet.address),
-                       alloc_packet.size, backtrace, context_id);
-}
-
-void AllocationTracker::OnFree(const FreePacket& free_packet) {
-  AllocationEvent find_me(Address(free_packet.address));
-  auto found = live_allocs_.find(find_me);
-  if (found != live_allocs_.end()) {
-    backtrace_storage_->Free(found->backtrace());
-    live_allocs_.erase(found);
-  }
-}
-
-void AllocationTracker::OnBarrier(const BarrierPacket& barrier_packet) {
-  RunnerSnapshotCallbackPair pair;
-  {
-    base::AutoLock lock(snapshot_lock_);
-    auto found = registered_snapshot_callbacks_.find(barrier_packet.barrier_id);
-    if (found == registered_snapshot_callbacks_.end()) {
-      DLOG(WARNING) << "Unexpected barrier";
-      return;
-    }
-    pair = std::move(found->second);
-    registered_snapshot_callbacks_.erase(found);
-  }
-
-  // Execute the callback outside of the lock. The arguments here must be
-  // copied.
-  pair.first->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          [](SnapshotCallback cb, AllocationCountMap counts, ContextMap context,
-             AddressToStringMap mapped_strings) {
-            std::move(cb).Run(true, std::move(counts), std::move(context),
-                              mapped_strings);
-          },
-          std::move(pair.second), AllocationEventSetToCountMap(live_allocs_),
-          context_, mapped_strings_));
-}
-
-void AllocationTracker::OnStringMapping(
-    const StringMappingPacket& string_mapping_packet,
-    const std::string& str) {
-  std::string dest;
-
-  // Escape the strings before saving them, to simplify exporting a heap dump.
-  base::EscapeJSONString(str, false /* put_in_quotes */, &dest);
-  mapped_strings_[string_mapping_packet.address] = std::move(dest);
-}
-
-void AllocationTracker::OnComplete() {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                std::move(complete_callback_));
-}
-
-void AllocationTracker::SnapshotOnBarrier(
-    uint32_t barrier_id,
-    scoped_refptr<base::SequencedTaskRunner> callback_runner,
-    SnapshotCallback callback) {
-  base::AutoLock lock(snapshot_lock_);
-  registered_snapshot_callbacks_[barrier_id] =
-      std::make_pair(std::move(callback_runner), std::move(callback));
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/allocation_tracker.h b/components/services/heap_profiling/allocation_tracker.h
deleted file mode 100644
index a479dbe..0000000
--- a/components/services/heap_profiling/allocation_tracker.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_ALLOCATION_TRACKER_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_ALLOCATION_TRACKER_H_
-
-#include <map>
-#include <unordered_map>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/sequenced_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "components/services/heap_profiling/allocation_event.h"
-#include "components/services/heap_profiling/backtrace_storage.h"
-#include "components/services/heap_profiling/receiver.h"
-
-namespace heap_profiling {
-
-// Tracks live allocations in one process. This is an analogue to memory-infra
-// allocation register and needs to be merged/deduped.
-//
-// This class is not threadsafe except as noted.
-class AllocationTracker : public Receiver {
- public:
-  using CompleteCallback = base::OnceClosure;
-  using ContextMap = std::map<std::string, int>;
-  using AddressToStringMap = std::unordered_map<uint64_t, std::string>;
-
-  // Callback for taking an asynchronous snapshot. The first parameter is a
-  // success parameter. This class will always set it to true, but this is
-  // useful for calling code that must handle failure.
-  using SnapshotCallback = base::OnceCallback<
-      void(bool, AllocationCountMap, ContextMap, AddressToStringMap)>;
-
-  AllocationTracker(CompleteCallback complete_cb,
-                    BacktraceStorage* backtrace_storage);
-  ~AllocationTracker() override;
-
-  void OnHeader(const StreamHeader& header) override;
-  void OnAlloc(const AllocPacket& alloc_packet,
-               std::vector<Address>&& bt,
-               std::string&& context) override;
-  void OnFree(const FreePacket& free_packet) override;
-  void OnBarrier(const BarrierPacket& barrier_packet) override;
-  void OnStringMapping(const StringMappingPacket& string_mapping_packet,
-                       const std::string& str) override;
-  void OnComplete() override;
-
-  // Registers the given snapshot closure to be executed when the given barrier
-  // ID is received from the process. This will only trigger for a barrier
-  // received after registration.
-  //
-  // This function is threadsafe. The callback will be executed on the given
-  // task runner.
-  void SnapshotOnBarrier(
-      uint32_t barrier_id,
-      scoped_refptr<base::SequencedTaskRunner> callback_runner,
-      SnapshotCallback callback);
-
- private:
-  CompleteCallback complete_callback_;
-
-  // The snapshot callbacks are threadsafe and are protected by the lock.
-  base::Lock snapshot_lock_;
-  using RunnerSnapshotCallbackPair =
-      std::pair<scoped_refptr<base::SequencedTaskRunner>, SnapshotCallback>;
-  std::map<uint32_t, RunnerSnapshotCallbackPair> registered_snapshot_callbacks_;
-
-  BacktraceStorage* backtrace_storage_;
-
-  AddressToStringMap mapped_strings_;
-
-  // Need to track all live objects. Since the free information doesn't have
-  // the metadata, we can't keep a map of counts indexed by just the metadata
-  // (which is all the trace JSON needs), but need to keep an index by address.
-  //
-  // This could be a two-level index, where one set of metadata is kept and
-  // addresses index into that. But a full copy of the metadata is about the
-  // same size as the internal map node required for this second index, with
-  // additional complexity.
-  AllocationEventSet live_allocs_;
-
-  // The context strings are atoms. Since there are O(100's) of these, we do
-  // not bother to uniquify across all processes. This map contains the unique
-  // context strings for the current process, mapped to the unique ID for that
-  // context. This unique ID is stored in the allocation. This is optimized for
-  // insertion. When querying, a reverse index will need to be generated
-  ContextMap context_;
-  int next_context_id_ = 1;  // 0 means no context.
-
-  DISALLOW_COPY_AND_ASSIGN(AllocationTracker);
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_ALLOCATION_TRACKER_H_
diff --git a/components/services/heap_profiling/connection_manager.cc b/components/services/heap_profiling/connection_manager.cc
index 0fbb4549..59aea38 100644
--- a/components/services/heap_profiling/connection_manager.cc
+++ b/components/services/heap_profiling/connection_manager.cc
@@ -6,24 +6,10 @@
 
 #include "base/bind.h"
 #include "base/json/string_escape.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread.h"
-#include "components/services/heap_profiling/allocation_tracker.h"
 #include "components/services/heap_profiling/json_exporter.h"
 #include "components/services/heap_profiling/public/cpp/client.h"
-#include "components/services/heap_profiling/receiver_pipe.h"
-#include "components/services/heap_profiling/stream_parser.h"
-#include "mojo/public/cpp/system/buffer.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "third_party/zlib/zlib.h"
-
-#if defined(OS_WIN)
-#include <io.h>
-#endif
 
 namespace heap_profiling {
 
@@ -68,29 +54,16 @@
 };
 
 struct ConnectionManager::Connection {
-  Connection(AllocationTracker::CompleteCallback complete_cb,
-             BacktraceStorage* backtrace_storage,
-             base::ProcessId pid,
+  Connection(CompleteCallback complete_cb,
              mojom::ProfilingClientPtr client,
-             scoped_refptr<ReceiverPipe> p,
              mojom::ProcessType process_type,
              uint32_t sampling_rate,
-             mojom::StackMode stack_mode,
-             bool stream_samples)
-      : thread(base::StringPrintf("Sender %lld thread",
-                                  static_cast<long long>(pid))),
-        client(std::move(client)),
-        pipe(p),
+             mojom::StackMode stack_mode)
+      : client(std::move(client)),
         process_type(process_type),
         stack_mode(stack_mode),
-        stream_samples(stream_samples),
-        tracker(std::move(complete_cb), backtrace_storage),
-        sampling_rate(sampling_rate) {}
-
-  ~Connection() {
-    // The parser may outlive this class because it's refcounted, make sure no
-    // callbacks are issued.
-    parser->DisconnectReceivers();
+        sampling_rate(sampling_rate) {
+    this->client.set_connection_error_handler(std::move(complete_cb));
   }
 
   bool HeapDumpNeedsVmRegions() {
@@ -99,18 +72,9 @@
            stack_mode == mojom::StackMode::MIXED;
   }
 
-  base::Thread thread;
-
   mojom::ProfilingClientPtr client;
-  scoped_refptr<ReceiverPipe> pipe;
-  scoped_refptr<StreamParser> parser;
   mojom::ProcessType process_type;
   mojom::StackMode stack_mode;
-  bool stream_samples;
-
-  // Danger: This lives on the |thread| member above. The connection manager
-  // lives on the I/O thread, so accesses to the variable must be synchronized.
-  AllocationTracker tracker;
 
   // When sampling is enabled, allocations are recorded with probability (size /
   // sampling_rate) when size < sampling_rate. When size >= sampling_rate, the
@@ -121,8 +85,7 @@
   uint32_t sampling_rate = 1;
 };
 
-ConnectionManager::ConnectionManager()
-    : blocking_thread_("Blocking thread"), weak_factory_(this) {
+ConnectionManager::ConnectionManager() : blocking_thread_("Blocking thread") {
   blocking_thread_.Start();
   metrics_timer_.Start(
       FROM_HERE, base::TimeDelta::FromHours(24),
@@ -132,7 +95,6 @@
 
 void ConnectionManager::OnNewConnection(base::ProcessId pid,
                                         mojom::ProfilingClientPtr client,
-                                        mojo::ScopedHandle receiver_pipe_end,
                                         mojom::ProcessType process_type,
                                         mojom::ProfilingParamsPtr params) {
   base::AutoLock lock(connections_lock_);
@@ -151,35 +113,15 @@
   // when the user is attempting to manually start profiling for processes, so
   // we ignore this edge case.
 
-  scoped_refptr<ReceiverPipe> new_pipe = base::MakeRefCounted<ReceiverPipe>(
-      mojo::UnwrapPlatformHandle(std::move(receiver_pipe_end)));
-
-  // The allocation tracker will call this on a background thread, so thunk
-  // back to the current thread with weak pointers.
-  AllocationTracker::CompleteCallback complete_cb = base::BindOnce(
-      &ConnectionManager::OnConnectionCompleteThunk,
-      base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr(), pid);
+  CompleteCallback complete_cb =
+      base::BindOnce(&ConnectionManager::OnConnectionComplete,
+                     weak_factory_.GetWeakPtr(), pid);
 
   auto connection = std::make_unique<Connection>(
-      std::move(complete_cb), &backtrace_storage_, pid, std::move(client),
-      new_pipe, process_type, params->sampling_rate, params->stack_mode,
-      params->stream_samples);
-
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_IO;
-  connection->thread.StartWithOptions(options);
-
-  connection->parser = base::MakeRefCounted<StreamParser>(&connection->tracker);
-  new_pipe->SetReceiver(connection->thread.task_runner(), connection->parser);
-
-  connection->thread.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ReceiverPipe::StartReadingOnIOThread, new_pipe));
-
-  // Request the client start sending us data.
+      std::move(complete_cb), std::move(client), process_type,
+      params->sampling_rate, params->stack_mode);
   connection->client->StartProfiling(std::move(params));
-
-  connections_[pid] = std::move(connection);  // Transfers ownership.
+  connections_[pid] = std::move(connection);
 }
 
 std::vector<base::ProcessId> ConnectionManager::GetConnectionPids() {
@@ -219,16 +161,6 @@
   }
 }
 
-// static
-void ConnectionManager::OnConnectionCompleteThunk(
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
-    base::WeakPtr<ConnectionManager> connection_manager,
-    base::ProcessId pid) {
-  task_runner->PostTask(FROM_HERE,
-                        base::BindOnce(&ConnectionManager::OnConnectionComplete,
-                                       connection_manager, pid));
-}
-
 void ConnectionManager::DumpProcessesForTracing(
     bool strip_path_from_mapped_files,
     DumpProcessesForTracingCallback callback,
@@ -253,25 +185,10 @@
   for (auto& it : connections_) {
     base::ProcessId pid = it.first;
     Connection* connection = it.second.get();
-    if (!connection->stream_samples) {
-      connection->client->RetrieveHeapProfile(base::BindOnce(
-          &ConnectionManager::HeapProfileRetrieved, weak_factory_.GetWeakPtr(),
-          tracking, pid, connection->process_type, strip_path_from_mapped_files,
-          connection->sampling_rate));
-      continue;
-    }
-    int barrier_id = next_barrier_id_++;
-
-    // Register for callback before requesting the dump so we don't race for the
-    // signal. The callback will be issued on the allocation tracker thread so
-    // need to thunk back to the I/O thread.
-    connection->tracker.SnapshotOnBarrier(
-        barrier_id, base::ThreadTaskRunnerHandle::Get(),
-        base::BindOnce(&ConnectionManager::DoDumpOneProcessForTracing,
-                       weak_factory_.GetWeakPtr(), tracking, pid,
-                       connection->process_type, strip_path_from_mapped_files,
-                       connection->sampling_rate));
-    connection->client->FlushMemlogPipe(barrier_id);
+    connection->client->RetrieveHeapProfile(base::BindOnce(
+        &ConnectionManager::HeapProfileRetrieved, weak_factory_.GetWeakPtr(),
+        tracking, pid, connection->process_type, strip_path_from_mapped_files,
+        connection->sampling_rate));
   }
 }
 
@@ -283,8 +200,8 @@
     uint32_t sampling_rate,
     mojom::HeapProfilePtr profile) {
   AllocationCountMap counts;
-  AllocationTracker::ContextMap context_map;
-  AllocationTracker::AddressToStringMap string_map;
+  ContextMap context_map;
+  AddressToStringMap string_map;
   BacktraceStorage backtrace_storage;
   BacktraceStorage::Lock backtrace_storage_lock(&backtrace_storage);
 
@@ -309,13 +226,8 @@
     }
     const Backtrace* backtrace = backtrace_storage.Insert(
         std::vector<Address>(sample->stack.begin(), sample->stack.end()));
-    AllocatorType allocator = static_cast<AllocatorType>(sample->allocator);
-    if (allocator >= AllocatorType::kCount) {
-      success = false;
-      break;
-    }
-    AllocationEvent alloc(allocator, Address(0), sample->size, backtrace,
-                          context_id);
+    AllocationEvent alloc(sample->allocator, Address(0), sample->size,
+                          backtrace, context_id);
     ++counts[alloc];
   }
 
@@ -342,8 +254,8 @@
     uint32_t sampling_rate,
     bool success,
     AllocationCountMap counts,
-    AllocationTracker::ContextMap context,
-    AllocationTracker::AddressToStringMap mapped_strings) {
+    ContextMap context,
+    AddressToStringMap mapped_strings) {
   // All code paths through here must issue the callback when waiting_responses
   // is 0 or the browser will wait forever for the dump.
   DCHECK(tracking->waiting_responses > 0);
diff --git a/components/services/heap_profiling/connection_manager.h b/components/services/heap_profiling/connection_manager.h
index 580ccc7..c4baebe 100644
--- a/components/services/heap_profiling/connection_manager.h
+++ b/components/services/heap_profiling/connection_manager.h
@@ -5,31 +5,24 @@
 #ifndef COMPONENTS_SERVICES_HEAP_PROFILING_CONNECTION_MANAGER_H_
 #define COMPONENTS_SERVICES_HEAP_PROFILING_CONNECTION_MANAGER_H_
 
+#include <map>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/process/process_handle.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "base/timer/timer.h"
-#include "base/values.h"
 #include "build/build_config.h"
 #include "components/services/heap_profiling/allocation_event.h"
-#include "components/services/heap_profiling/allocation_tracker.h"
 #include "components/services/heap_profiling/backtrace_storage.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_service.mojom.h"
 #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 
-namespace base {
-
-class SequencedTaskRunner;
-
-}  // namespace base
-
 namespace heap_profiling {
 
 using VmRegions =
@@ -44,6 +37,9 @@
 // This object is constructed on the UI thread, but the rest of the usage
 // (including deletion) is on the IO thread.
 class ConnectionManager {
+  using AddressToStringMap = std::unordered_map<uint64_t, std::string>;
+  using CompleteCallback = base::OnceClosure;
+  using ContextMap = std::map<std::string, int>;
   using DumpProcessesForTracingCallback = memory_instrumentation::mojom::
       HeapProfiler::DumpProcessesForTracingCallback;
 
@@ -76,7 +72,6 @@
 
   void OnNewConnection(base::ProcessId pid,
                        mojom::ProfilingClientPtr client,
-                       mojo::ScopedHandle receiver_pipe_end,
                        mojom::ProcessType process_type,
                        mojom::ProfilingParamsPtr params);
 
@@ -103,8 +98,8 @@
       uint32_t sampling_rate,
       bool success,
       AllocationCountMap counts,
-      AllocationTracker::ContextMap context,
-      AllocationTracker::AddressToStringMap mapped_strings);
+      ContextMap context,
+      AddressToStringMap mapped_strings);
 
   // Notification that a connection is complete. Unlike OnNewConnection which
   // is signaled by the pipe server, this is signaled by the allocation tracker
@@ -115,18 +110,8 @@
   // Reports the ProcessTypes of the processes being profiled.
   void ReportMetrics();
 
-  // These thunks post the request back to the given thread.
-  static void OnConnectionCompleteThunk(
-      scoped_refptr<base::SequencedTaskRunner> main_loop,
-      base::WeakPtr<ConnectionManager> connection_manager,
-      base::ProcessId process_id);
-
   BacktraceStorage backtrace_storage_;
 
-  // Next ID to use for a barrier request. This is incremented for each use
-  // to ensure barrier IDs are unique.
-  uint32_t next_barrier_id_ = 1;
-
   // The next ID to use when exporting a heap dump.
   size_t next_id_ = 1;
 
@@ -144,7 +129,7 @@
   base::Thread blocking_thread_;
 
   // Must be last.
-  base::WeakPtrFactory<ConnectionManager> weak_factory_;
+  base::WeakPtrFactory<ConnectionManager> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ConnectionManager);
 };
diff --git a/components/services/heap_profiling/heap_profiling_service.cc b/components/services/heap_profiling/heap_profiling_service.cc
index af70cfb..8d86ba7 100644
--- a/components/services/heap_profiling/heap_profiling_service.cc
+++ b/components/services/heap_profiling/heap_profiling_service.cc
@@ -77,13 +77,11 @@
 void HeapProfilingService::AddProfilingClient(
     base::ProcessId pid,
     mojom::ProfilingClientPtr client,
-    mojo::ScopedHandle pipe_receiver,
     mojom::ProcessType process_type,
     mojom::ProfilingParamsPtr params) {
   if (params->sampling_rate == 0)
     params->sampling_rate = 1;
-  connection_manager_.OnNewConnection(pid, std::move(client),
-                                      std::move(pipe_receiver), process_type,
+  connection_manager_.OnNewConnection(pid, std::move(client), process_type,
                                       std::move(params));
 }
 
@@ -94,26 +92,25 @@
 void HeapProfilingService::DumpProcessesForTracing(
     bool strip_path_from_mapped_files,
     DumpProcessesForTracingCallback callback) {
-  if (!helper_) {
-    service_binding_.GetConnector()->BindInterface(
-        resource_coordinator::mojom::kServiceName, &helper_);
-  }
-
   std::vector<base::ProcessId> pids =
       connection_manager_.GetConnectionPidsThatNeedVmRegions();
   if (pids.empty()) {
     connection_manager_.DumpProcessesForTracing(
         strip_path_from_mapped_files, std::move(callback), VmRegions());
-  } else {
-    // Need a memory map to make sense of the dump. The dump will be triggered
-    // in the memory map global dump callback.
-    helper_->GetVmRegionsForHeapProfiler(
-        pids,
-        base::BindOnce(&HeapProfilingService::
-                           OnGetVmRegionsCompleteForDumpProcessesForTracing,
-                       weak_factory_.GetWeakPtr(), strip_path_from_mapped_files,
-                       std::move(callback)));
+    return;
   }
+
+  // Need a memory map to make sense of the dump. The dump will be triggered
+  // in the memory map global dump callback.
+  if (!helper_) {
+    service_binding_.GetConnector()->BindInterface(
+        resource_coordinator::mojom::kServiceName, &helper_);
+  }
+  helper_->GetVmRegionsForHeapProfiler(
+      pids, base::BindOnce(&HeapProfilingService::
+                               OnGetVmRegionsCompleteForDumpProcessesForTracing,
+                           weak_factory_.GetWeakPtr(),
+                           strip_path_from_mapped_files, std::move(callback)));
 }
 
 void HeapProfilingService::OnGetVmRegionsCompleteForDumpProcessesForTracing(
diff --git a/components/services/heap_profiling/heap_profiling_service.h b/components/services/heap_profiling/heap_profiling_service.h
index 4d44db6..ea657c0 100644
--- a/components/services/heap_profiling/heap_profiling_service.h
+++ b/components/services/heap_profiling/heap_profiling_service.h
@@ -46,7 +46,6 @@
   // ProfilingService implementation.
   void AddProfilingClient(base::ProcessId pid,
                           mojom::ProfilingClientPtr client,
-                          mojo::ScopedHandle pipe_receiver,
                           mojom::ProcessType process_type,
                           mojom::ProfilingParamsPtr params) override;
   void GetProfiledPids(GetProfiledPidsCallback callback) override;
diff --git a/components/services/heap_profiling/json_exporter.cc b/components/services/heap_profiling/json_exporter.cc
index 8d87039..e9565bb 100644
--- a/components/services/heap_profiling/json_exporter.cc
+++ b/components/services/heap_profiling/json_exporter.cc
@@ -23,7 +23,7 @@
 using StringTable = std::map<std::string, size_t>;
 
 constexpr uint32_t kAllocatorCount =
-    static_cast<uint32_t>(AllocatorType::kCount);
+    static_cast<uint32_t>(AllocatorType::kMaxValue) + 1;
 
 struct BacktraceNode {
   BacktraceNode(size_t string_id, size_t parent)
diff --git a/components/services/heap_profiling/json_exporter.h b/components/services/heap_profiling/json_exporter.h
index 2357862..9b3c58b 100644
--- a/components/services/heap_profiling/json_exporter.h
+++ b/components/services/heap_profiling/json_exporter.h
@@ -10,7 +10,6 @@
 
 #include "base/values.h"
 #include "components/services/heap_profiling/allocation_event.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_service.mojom.h"
 #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 
diff --git a/components/services/heap_profiling/public/cpp/BUILD.gn b/components/services/heap_profiling/public/cpp/BUILD.gn
index 01439b4..cc786f4 100644
--- a/components/services/heap_profiling/public/cpp/BUILD.gn
+++ b/components/services/heap_profiling/public/cpp/BUILD.gn
@@ -10,11 +10,8 @@
     "controller.h",
     "sampling_profiler_wrapper.cc",
     "sampling_profiler_wrapper.h",
-    "sender_pipe.h",
-    "sender_pipe_win.cc",
     "settings.cc",
     "settings.h",
-    "stream.h",
     "switches.cc",
     "switches.h",
   ]
@@ -30,16 +27,11 @@
     "//services/service_manager/public/cpp",
     "//services/service_manager/sandbox",
   ]
-
-  if (is_posix) {
-    sources += [ "sender_pipe_posix.cc" ]
-  }
 }
 
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "sender_pipe_unittest.cc",
     "switches_unittest.cc",
   ]
   deps = [
diff --git a/components/services/heap_profiling/public/cpp/client.cc b/components/services/heap_profiling/public/cpp/client.cc
index 39cd6c1d..704f373 100644
--- a/components/services/heap_profiling/public/cpp/client.cc
+++ b/components/services/heap_profiling/public/cpp/client.cc
@@ -6,20 +6,12 @@
 
 #include "base/allocator/allocator_interception_mac.h"
 #include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/platform_file.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/trace_event/malloc_dump_provider.h"
 #include "build/build_config.h"
 #include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h"
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-#include "components/services/heap_profiling/public/cpp/settings.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "services/service_manager/sandbox/switches.h"
 
 #if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
     defined(OFFICIAL_BUILD)
@@ -29,7 +21,6 @@
 namespace heap_profiling {
 
 namespace {
-const int kTimeoutDurationMs = 10000;
 
 #if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
     defined(OFFICIAL_BUILD)
@@ -46,25 +37,13 @@
 
 }  // namespace
 
-Client::Client()
-    : started_profiling_(false),
-      sampling_profiler_(new SamplingProfilerWrapper()),
-      weak_factory_(this) {}
+Client::Client() : sampling_profiler_(new SamplingProfilerWrapper()) {}
 
 Client::~Client() {
   if (!started_profiling_)
     return;
-
   sampling_profiler_->StopProfiling();
-  SamplingProfilerWrapper::FlushBuffersAndClosePipe();
-
   base::trace_event::MallocDumpProvider::GetInstance()->EnableMetrics();
-
-  // The allocator shim cannot be synchronously, consistently stopped. We leak
-  // the sender_pipe_, with the idea that very few future messages will
-  // be sent to it. This happens at shutdown, so resources will be reclaimed
-  // by the OS after the process is terminated.
-  sender_pipe_.release();
 }
 
 void Client::BindToInterface(mojom::ProfilingClientRequest request) {
@@ -72,29 +51,9 @@
 }
 
 void Client::StartProfiling(mojom::ProfilingParamsPtr params) {
-  // Never allow profiling of the profiling process. That would cause deadlock.
-  std::string sandbox_type =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          service_manager::switches::kServiceSandboxType);
-  if (sandbox_type == service_manager::switches::kProfilingSandbox)
-    return;
-
   if (started_profiling_)
     return;
   started_profiling_ = true;
-
-  sender_pipe_.reset(new SenderPipe(
-      mojo::UnwrapPlatformHandle(std::move(params->sender_pipe))));
-
-  StreamHeader header;
-  header.signature = kStreamSignature;
-  SenderPipe::Result result =
-      sender_pipe_->Send(&header, sizeof(header), kTimeoutDurationMs);
-  if (result != SenderPipe::Result::kSuccess) {
-    sender_pipe_->Close();
-    return;
-  }
-
   base::trace_event::MallocDumpProvider::GetInstance()->DisableMetrics();
 
 #if defined(OS_MACOSX)
@@ -124,16 +83,12 @@
 #endif
 }
 
-void Client::FlushMemlogPipe(uint32_t barrier_id) {
-  SamplingProfilerWrapper::FlushPipe(barrier_id);
-}
-
 void Client::RetrieveHeapProfile(RetrieveHeapProfileCallback callback) {
   std::move(callback).Run(sampling_profiler_->RetrieveHeapProfile());
 }
 
 void Client::StartProfilingInternal(mojom::ProfilingParamsPtr params) {
-  sampling_profiler_->StartProfiling(sender_pipe_.get(), std::move(params));
+  sampling_profiler_->StartProfiling(std::move(params));
 }
 
 }  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/client.h b/components/services/heap_profiling/public/cpp/client.h
index 23abac2..3254857 100644
--- a/components/services/heap_profiling/public/cpp/client.h
+++ b/components/services/heap_profiling/public/cpp/client.h
@@ -8,12 +8,10 @@
 #include "base/memory/weak_ptr.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/system/handle.h"
 
 namespace heap_profiling {
 
 class SamplingProfilerWrapper;
-class SenderPipe;
 
 // The Client listens on the interface for a StartProfiling message. On
 // receiving the message, it begins profiling the current process.
@@ -26,7 +24,6 @@
 
   // mojom::ProfilingClient overrides:
   void StartProfiling(mojom::ProfilingParamsPtr params) override;
-  void FlushMemlogPipe(uint32_t barrier_id) override;
   void RetrieveHeapProfile(RetrieveHeapProfileCallback callback) override;
 
   void BindToInterface(mojom::ProfilingClientRequest request);
@@ -42,12 +39,9 @@
   // has a chance to figure out which one to keep.
   mojo::BindingSet<mojom::ProfilingClient> bindings_;
 
-  bool started_profiling_;
-
+  bool started_profiling_{false};
   std::unique_ptr<SamplingProfilerWrapper> sampling_profiler_;
-  std::unique_ptr<SenderPipe> sender_pipe_;
-
-  base::WeakPtrFactory<Client> weak_factory_;
+  base::WeakPtrFactory<Client> weak_factory_{this};
 };
 
 }  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/controller.cc b/components/services/heap_profiling/public/cpp/controller.cc
index 72cda0f..1b45cc9 100644
--- a/components/services/heap_profiling/public/cpp/controller.cc
+++ b/components/services/heap_profiling/public/cpp/controller.cc
@@ -4,10 +4,8 @@
 
 #include "components/services/heap_profiling/public/cpp/controller.h"
 
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
 #include "components/services/heap_profiling/public/mojom/constants.mojom.h"
-#include "mojo/public/cpp/system/platform_handle.h"
 #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 #include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -16,12 +14,10 @@
 
 Controller::Controller(std::unique_ptr<service_manager::Connector> connector,
                        mojom::StackMode stack_mode,
-                       bool stream_samples,
                        uint32_t sampling_rate)
     : connector_(std::move(connector)),
       sampling_rate_(sampling_rate),
       stack_mode_(stack_mode),
-      stream_samples_(stream_samples),
       weak_factory_(this) {
   DCHECK_NE(sampling_rate, 0u);
 
@@ -45,16 +41,11 @@
                                       mojom::ProcessType process_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  SenderPipe::PipePair pipes;
-
   mojom::ProfilingParamsPtr params = mojom::ProfilingParams::New();
   params->sampling_rate = sampling_rate_;
-  params->stream_samples = stream_samples_;
-  params->sender_pipe = mojo::WrapPlatformHandle(pipes.PassSender());
   params->stack_mode = stack_mode_;
-  heap_profiling_service_->AddProfilingClient(
-      pid, std::move(client), mojo::WrapPlatformHandle(pipes.PassReceiver()),
-      process_type, std::move(params));
+  heap_profiling_service_->AddProfilingClient(pid, std::move(client),
+                                              process_type, std::move(params));
 }
 
 void Controller::GetProfiledPids(GetProfiledPidsCallback callback) {
diff --git a/components/services/heap_profiling/public/cpp/controller.h b/components/services/heap_profiling/public/cpp/controller.h
index 6ea12588..4e9ba62 100644
--- a/components/services/heap_profiling/public/cpp/controller.h
+++ b/components/services/heap_profiling/public/cpp/controller.h
@@ -42,7 +42,6 @@
   // named |sampling_interval|.
   Controller(std::unique_ptr<service_manager::Connector> connector,
              mojom::StackMode stack_mode,
-             bool stream_samples,
              uint32_t sampling_rate);
   ~Controller();
 
@@ -71,7 +70,6 @@
   // The same sampling rate and stack mode is used for each client.
   const uint32_t sampling_rate_ = 1;
   const mojom::StackMode stack_mode_;
-  const bool stream_samples_;
 
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<Controller> weak_factory_;
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
index 01885d7a..3d7e99a 100644
--- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
+++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
@@ -7,18 +7,12 @@
 #include <unordered_set>
 #include <utility>
 
-#include "base/atomicops.h"
 #include "base/debug/stack_trace.h"
 #include "base/lazy_instance.h"
-#include "base/no_destructor.h"
-#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "base/synchronization/lock.h"
-#include "base/threading/thread_local_storage.h"
 #include "base/trace_event/heap_profiler_event_filter.h"
 #include "base/trace_event/memory_dump_manager.h"
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
 
 using base::trace_event::AllocationContext;
 using base::trace_event::AllocationContextTracker;
@@ -26,17 +20,6 @@
 
 namespace heap_profiling {
 
-// Allocation logging also requires use of base TLS, so we must also check that
-// that is available. This means that allocations that occur after base TLS has
-// been torn down will not be logged.
-// TODO(alph): Get rid of the class. crbug.com/917476
-class ScopedAllowAlloc {
- public:
-  static inline bool HasTLSBeenDestroyed() {
-    return UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed());
-  }
-};
-
 namespace {
 
 bool g_initialized_ = false;
@@ -45,236 +28,13 @@
 base::LazyInstance<scoped_refptr<base::TaskRunner>>::Leaky
     g_on_init_allocator_shim_task_runner_;
 
-SenderPipe* g_sender_pipe = nullptr;
-
 // In NATIVE stack mode, whether to insert stack names into the backtraces.
 bool g_include_thread_names = false;
 
-// Prime since this is used like a hash table. Numbers of this magnitude seemed
-// to provide sufficient parallelism to avoid lock overhead in ad-hoc testing.
-constexpr int kNumSendBuffers = 17;
-
-// If writing to the SenderPipe ever takes longer than 10s, just give up.
-constexpr int kTimeoutMs = 10000;
-
-// The allocator shim needs to retain some additional state for each thread.
-struct ShimState {
-  // If we are using pseudo stacks, we need to inform the profiling service of
-  // the address to string mapping. To avoid a global lock, we keep a
-  // thread-local unordered_set of every address that has been sent from the
-  // thread in question.
-  std::unordered_set<const void*> sent_strings;
-};
-
-// Technically, this code could be called after Thread destruction and we would
-// need to guard this with ThreadLocalStorage::HasBeenDestroyed(), but all calls
-// to this are guarded behind ScopedAllowAlloc, which already makes the check.
-base::ThreadLocalStorage::Slot& ShimStateTLS() {
-  static base::NoDestructor<base::ThreadLocalStorage::Slot> shim_state_tls(
-      [](void* shim_state) { delete static_cast<ShimState*>(shim_state); });
-  return *shim_state_tls;
-}
-
-// We don't need to worry about re-entrancy because PoissonAllocationSampler
-// already guards against that.
-ShimState* GetShimState() {
-  ShimState* state = static_cast<ShimState*>(ShimStateTLS().Get());
-  if (!state) {
-    state = new ShimState();
-    ShimStateTLS().Set(state);
-  }
-  return state;
-}
-
-class SendBuffer {
- public:
-  SendBuffer() : buffer_(new char[SenderPipe::kPipeSize]) {}
-  ~SendBuffer() { delete[] buffer_; }
-
-  void Send(const void* data, size_t sz) {
-    base::AutoLock lock(lock_);
-
-    if (used_ + sz > SenderPipe::kPipeSize)
-      SendCurrentBuffer();
-
-    memcpy(&buffer_[used_], data, sz);
-    used_ += sz;
-  }
-
-  void Flush() {
-    base::AutoLock lock(lock_);
-    if (used_ > 0)
-      SendCurrentBuffer();
-  }
-
- private:
-  void SendCurrentBuffer() {
-    SenderPipe::Result result = g_sender_pipe->Send(buffer_, used_, kTimeoutMs);
-    used_ = 0;
-    if (result == SenderPipe::Result::kError) {
-      SamplingProfilerWrapper::FlushBuffersAndClosePipe();
-    }
-    if (result == SenderPipe::Result::kTimeout) {
-      SamplingProfilerWrapper::FlushBuffersAndClosePipe();
-      // TODO(erikchen): Emit a histogram. https://crbug.com/777546.
-    }
-  }
-
-  base::Lock lock_;
-
-  char* buffer_;
-  size_t used_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(SendBuffer);
-};
-
-// It's safe to call Read() before Write(). Read() will either return nullptr or
-// a valid SendBuffer.
-class AtomicallyConsistentSendBufferArray {
- public:
-  void Write(SendBuffer* buffer) {
-    base::subtle::Release_Store(
-        &send_buffers, reinterpret_cast<base::subtle::AtomicWord>(buffer));
-  }
-
-  SendBuffer* Read() {
-    return reinterpret_cast<SendBuffer*>(
-        base::subtle::Acquire_Load(&send_buffers));
-  }
-
- private:
-  // This class is used as a static global. This will be linker-initialized to
-  // 0.
-  base::subtle::AtomicWord send_buffers;
-};
-
-// The API guarantees that Read() will either return a valid object or a
-// nullptr.
-AtomicallyConsistentSendBufferArray g_send_buffers;
-
-size_t HashAddress(const void* address) {
-  // The multiplicative hashing scheme from [Knuth 1998].
-  // |a| is the first prime after 2^17.
-  const uintptr_t key = reinterpret_cast<uintptr_t>(address);
-  const uintptr_t a = 131101;
-  const uintptr_t shift = 15;
-  const uintptr_t h = (key * a) >> shift;
-  return h;
-}
-
-// "address" is the address in question, which is used to select which send
-// buffer to use.
-void DoSend(const void* address,
-            const void* data,
-            size_t size,
-            SendBuffer* send_buffers) {
-  int bin_to_use = HashAddress(address) % kNumSendBuffers;
-  send_buffers[bin_to_use].Send(data, size);
-}
-
-// Updates an existing in_memory buffer with frame data. If a frame contains a
-// pointer to a cstring rather than an instruction pointer, and the profiling
-// service has not yet been informed of that pointer -> cstring mapping, sends a
-// StringMappingPacket.
-class FrameSerializer {
- public:
-  FrameSerializer(uint64_t* stack,
-                  const void* address,
-                  size_t initial_buffer_size,
-                  SendBuffer* send_buffers)
-      : stack_(stack),
-        address_(address),
-        remaining_buffer_size_(initial_buffer_size),
-        send_buffers_(send_buffers) {}
-
-  void AddAllFrames(const base::trace_event::Backtrace& backtrace) {
-    CHECK_LE(backtrace.frame_count, kMaxStackEntries);
-    size_t required_capacity = backtrace.frame_count * sizeof(uint64_t);
-    CHECK_LE(required_capacity, remaining_buffer_size_);
-    remaining_buffer_size_ -= required_capacity;
-    for (int i = base::checked_cast<int>(backtrace.frame_count) - 1; i >= 0;
-         --i) {
-      AddFrame(backtrace.frames[i]);
-    }
-  }
-
-  void AddAllInstructionPointers(size_t frame_count,
-                                 const void* const* frames) {
-    CHECK_LE(frame_count, kMaxStackEntries);
-    size_t required_capacity = frame_count * sizeof(uint64_t);
-    CHECK_LE(required_capacity, remaining_buffer_size_);
-    remaining_buffer_size_ -= required_capacity;
-    // If there are too many frames, keep the ones furthest from main().
-    for (size_t i = 0; i < frame_count; i++)
-      AddInstructionPointer(frames[i]);
-  }
-
-  void AddCString(const char* c_string) {
-    // Using a TLS cache of sent_strings avoids lock contention on malloc, which
-    // would kill performance.
-    std::unordered_set<const void*>* sent_strings =
-        &GetShimState()->sent_strings;
-
-    if (sent_strings->find(c_string) == sent_strings->end()) {
-      // No point in allowing arbitrarily long c-strings, which might cause pipe
-      // max length issues. Pick a reasonable length like 255.
-      static const size_t kMaxCStringLen = 255;
-
-      // length does not include the null terminator.
-      size_t length = strnlen(c_string, kMaxCStringLen);
-
-      char message[sizeof(StringMappingPacket) + kMaxCStringLen];
-      StringMappingPacket* string_mapping_packet =
-          new (&message) StringMappingPacket();
-      string_mapping_packet->address = reinterpret_cast<uint64_t>(c_string);
-      string_mapping_packet->string_len = length;
-      memcpy(message + sizeof(StringMappingPacket), c_string, length);
-      DoSend(address_, message, sizeof(StringMappingPacket) + length,
-             send_buffers_);
-      sent_strings->insert(c_string);
-    }
-
-    AddInstructionPointer(c_string);
-  }
-
-  size_t count() { return count_; }
-
- private:
-  void AddFrame(const base::trace_event::StackFrame& frame) {
-    if (frame.type == base::trace_event::StackFrame::Type::PROGRAM_COUNTER) {
-      AddInstructionPointer(frame.value);
-      return;
-    }
-
-    AddCString(static_cast<const char*>(frame.value));
-  }
-
-  void AddInstructionPointer(const void* value) {
-    *stack_ = reinterpret_cast<uint64_t>(value);
-    ++stack_;
-    ++count_;
-  }
-
-  // The next frame should be written to this memory location. There are both
-  // static and runtime checks to prevent buffer overrun.
-  static_assert(
-      base::trace_event::Backtrace::kMaxFrameCount < kMaxStackEntries,
-      "Ensure that pseudo-stack frame count won't exceed OOP HP frame buffer.");
-  uint64_t* stack_;
-
-  // The number of frames that have been written to the stack.
-  size_t count_ = 0;
-
-  const void* address_;
-  size_t remaining_buffer_size_;
-  SendBuffer* send_buffers_;
-};
-
 }  // namespace
 
 void InitTLSSlot() {
   base::SamplingHeapProfiler::Init();
-  ignore_result(ShimStateTLS());
 }
 
 // In order for pseudo stacks to work, trace event filtering must be enabled.
@@ -299,8 +59,7 @@
       filtering_trace_config, base::trace_event::TraceLog::FILTERING_MODE);
 }
 
-void InitAllocationRecorder(SenderPipe* sender_pipe,
-                            mojom::ProfilingParamsPtr params) {
+void InitAllocationRecorder(mojom::ProfilingParamsPtr params) {
   // Must be done before hooking any functions that make stack traces.
   base::debug::EnableInProcessStackDumping();
 
@@ -324,57 +83,10 @@
       AllocationContextTracker::SetCaptureMode(CaptureMode::NATIVE_STACK);
       break;
   }
-
-  g_send_buffers.Write(new SendBuffer[kNumSendBuffers]);
-  g_sender_pipe = sender_pipe;
-}
-
-void SamplingProfilerWrapper::FlushBuffersAndClosePipe() {
-  // This ShareBuffer array is leaked on purpose to avoid races on Stop.
-  g_send_buffers.Write(nullptr);
-  if (g_sender_pipe)
-    g_sender_pipe->Close();
 }
 
 namespace {
 
-void SerializeFramesFromAllocationContext(FrameSerializer* serializer,
-                                          const char** context) {
-  auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread();
-  if (!tracker)
-    return;
-
-  AllocationContext allocation_context;
-  if (!tracker->GetContextSnapshot(&allocation_context))
-    return;
-
-  serializer->AddAllFrames(allocation_context.backtrace);
-  if (!*context)
-    *context = allocation_context.type_name;
-}
-
-void SerializeFramesFromBacktrace(FrameSerializer* serializer,
-                                  const char** context) {
-  void* frames[kMaxStackEntries];
-  size_t frames_count;
-  const void** first_frame =
-      const_cast<const void**>(base::SamplingHeapProfiler::CaptureStackTrace(
-          frames, kMaxStackEntries - 1, &frames_count));
-  serializer->AddAllInstructionPointers(frames_count, first_frame);
-
-  if (g_include_thread_names) {
-    const char* thread_name = base::SamplingHeapProfiler::CachedThreadName();
-    serializer->AddCString(thread_name);
-  }
-
-  if (!*context) {
-    const auto* tracker =
-        AllocationContextTracker::GetInstanceForCurrentThread();
-    if (tracker)
-      *context = tracker->TaskContext();
-  }
-}
-
 // Notifies the test clients that allocation hooks have been initialized.
 void AllocatorHooksHaveBeenInitialized() {
   base::AutoLock lock(g_on_init_allocator_shim_lock_.Get());
@@ -385,121 +97,20 @@
       FROM_HERE, std::move(*g_on_init_allocator_shim_callback_.Pointer()));
 }
 
-AllocatorType ConvertType(base::PoissonAllocationSampler::AllocatorType type) {
-  static_assert(static_cast<uint32_t>(
-                    base::PoissonAllocationSampler::AllocatorType::kMax) ==
-                    static_cast<uint32_t>(AllocatorType::kCount),
-                "AllocatorType lengths do not match.");
+mojom::AllocatorType ConvertType(
+    base::PoissonAllocationSampler::AllocatorType type) {
   switch (type) {
     case base::PoissonAllocationSampler::AllocatorType::kMalloc:
-      return AllocatorType::kMalloc;
+      return mojom::AllocatorType::kMalloc;
     case base::PoissonAllocationSampler::AllocatorType::kPartitionAlloc:
-      return AllocatorType::kPartitionAlloc;
+      return mojom::AllocatorType::kPartitionAlloc;
     case base::PoissonAllocationSampler::AllocatorType::kBlinkGC:
-      return AllocatorType::kOilpan;
-    default:
-      NOTREACHED();
-      return AllocatorType::kMalloc;
+      return mojom::AllocatorType::kOilpan;
   }
 }
 
 }  // namespace
 
-// Creates allocation info record, populates it with current call stack,
-// thread name, allocator type and sends out to the client. Safe to call this
-// method after TLS is destroyed.
-void SamplingProfilerWrapper::SampleAdded(
-    void* address,
-    size_t size,
-    size_t total,
-    base::PoissonAllocationSampler::AllocatorType type,
-    const char* context) {
-  // CaptureStack (on Android) and AllocationContext (all OSes) may use TLS.
-  // Bail out if it has been destroyed.
-  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
-    return;
-
-  // The PoissonAllocationSampler that invokes this method guarantees
-  // non-reentrancy, i.e. no allocations made within the scope of SampleAdded
-  // will produce a sample.
-  DCHECK(base::PoissonAllocationSampler::ScopedMuteThreadSamples::IsMuted());
-  SendBuffer* send_buffers = g_send_buffers.Read();
-  if (!send_buffers)
-    return;
-
-  constexpr size_t max_message_size = sizeof(AllocPacket) +
-                                      kMaxStackEntries * sizeof(uint64_t) +
-                                      kMaxContextLen;
-  static_assert(max_message_size < SenderPipe::kPipeSize,
-                "We can't have a message size that exceeds the pipe write "
-                "buffer size.");
-  char message[max_message_size];
-  // TODO(ajwong) check that this is technically valid.
-  AllocPacket* alloc_packet = reinterpret_cast<AllocPacket*>(message);
-
-  uint64_t* stack = reinterpret_cast<uint64_t*>(&message[sizeof(AllocPacket)]);
-
-  FrameSerializer serializer(
-      stack, address, max_message_size - sizeof(AllocPacket), send_buffers);
-
-  CaptureMode capture_mode = AllocationContextTracker::capture_mode();
-  if (capture_mode == CaptureMode::PSEUDO_STACK ||
-      capture_mode == CaptureMode::MIXED_STACK) {
-    SerializeFramesFromAllocationContext(&serializer, &context);
-  } else {
-    SerializeFramesFromBacktrace(&serializer, &context);
-  }
-
-  size_t context_len = context ? strnlen(context, kMaxContextLen) : 0;
-
-  alloc_packet->op = kAllocPacketType;
-  alloc_packet->allocator = ConvertType(type);
-  alloc_packet->address = (uint64_t)address;
-  alloc_packet->size = size;
-  alloc_packet->stack_len = static_cast<uint32_t>(serializer.count());
-  alloc_packet->context_byte_len = static_cast<uint32_t>(context_len);
-
-  char* message_end = message + sizeof(AllocPacket) +
-                      alloc_packet->stack_len * sizeof(uint64_t);
-  if (context_len > 0) {
-    memcpy(message_end, context, context_len);
-    message_end += context_len;
-  }
-  DoSend(address, message, message_end - message, send_buffers);
-}
-
-// Creates the record for free operation and sends it out to the client. Safe
-// to call this method after TLS is destroyed.
-void SamplingProfilerWrapper::SampleRemoved(void* address) {
-  DCHECK(base::PoissonAllocationSampler::ScopedMuteThreadSamples::IsMuted());
-  SendBuffer* send_buffers = g_send_buffers.Read();
-  if (!send_buffers)
-    return;
-
-  FreePacket free_packet;
-  free_packet.op = kFreePacketType;
-  free_packet.address = (uint64_t)address;
-
-  DoSend(address, &free_packet, sizeof(FreePacket), send_buffers);
-}
-
-void SamplingProfilerWrapper::FlushPipe(uint32_t barrier_id) {
-  SendBuffer* send_buffers = g_send_buffers.Read();
-  if (!send_buffers)
-    return;
-  for (int i = 0; i < kNumSendBuffers; i++)
-    send_buffers[i].Flush();
-
-  BarrierPacket barrier;
-  barrier.barrier_id = barrier_id;
-  SenderPipe::Result result =
-      g_sender_pipe->Send(&barrier, sizeof(barrier), kTimeoutMs);
-  if (result != SenderPipe::Result::kSuccess) {
-    FlushBuffersAndClosePipe();
-    // TODO(erikchen): Emit a histogram. https://crbug.com/777546.
-  }
-}
-
 bool SetOnInitAllocatorShimCallbackForTesting(
     base::OnceClosure callback,
     scoped_refptr<base::TaskRunner> task_runner) {
@@ -511,32 +122,20 @@
   return false;
 }
 
-void SamplingProfilerWrapper::StartProfiling(SenderPipe* sender_pipe,
-                                             mojom::ProfilingParamsPtr params) {
+void SamplingProfilerWrapper::StartProfiling(mojom::ProfilingParamsPtr params) {
   size_t sampling_rate = params->sampling_rate;
-  stream_samples_ = params->stream_samples;
-  InitAllocationRecorder(sender_pipe, std::move(params));
-  if (stream_samples_) {
-    auto* sampler = base::PoissonAllocationSampler::Get();
-    sampler->SetSamplingInterval(sampling_rate);
-    sampler->AddSamplesObserver(this);
-  } else {
-    auto* profiler = base::SamplingHeapProfiler::Get();
-    profiler->SetSamplingInterval(sampling_rate);
-    profiler->Start();
-  }
+  InitAllocationRecorder(std::move(params));
+  auto* profiler = base::SamplingHeapProfiler::Get();
+  profiler->SetSamplingInterval(sampling_rate);
+  profiler->Start();
   AllocatorHooksHaveBeenInitialized();
 }
 
 void SamplingProfilerWrapper::StopProfiling() {
-  if (stream_samples_)
-    base::PoissonAllocationSampler::Get()->RemoveSamplesObserver(this);
-  else
-    base::SamplingHeapProfiler::Get()->Stop();
+  base::SamplingHeapProfiler::Get()->Stop();
 }
 
 mojom::HeapProfilePtr SamplingProfilerWrapper::RetrieveHeapProfile() {
-  DCHECK(!stream_samples_);
   auto* profiler = base::SamplingHeapProfiler::Get();
   std::vector<base::SamplingHeapProfiler::Sample> samples =
       profiler->GetSamples(/*profile_id=*/0);
@@ -548,8 +147,7 @@
   std::unordered_set<const char*> thread_names;
   for (const auto& sample : samples) {
     auto mojo_sample = mojom::HeapProfileSample::New();
-    mojo_sample->allocator =
-        static_cast<uint32_t>(ConvertType(sample.allocator));
+    mojo_sample->allocator = ConvertType(sample.allocator);
     mojo_sample->size = sample.size;
     mojo_sample->context_id = reinterpret_cast<uintptr_t>(sample.context);
     mojo_sample->stack.reserve(sample.stack.size() +
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
index d6bff9c..cf21721 100644
--- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
+++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
@@ -5,15 +5,10 @@
 #ifndef COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SAMPLING_PROFILER_WRAPPER_H_
 #define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SAMPLING_PROFILER_WRAPPER_H_
 
-#include <vector>
-
-#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
 
 namespace heap_profiling {
 
-class SenderPipe;
-
 // Initializes the TLS slot globally. This will be called early in Chrome's
 // lifecycle to prevent re-entrancy from occurring while trying to set up the
 // TLS slot, which is the entity that's supposed to prevent re-entrancy.
@@ -29,32 +24,12 @@
 
 // The class listens for allocation samples records the necessary attributes
 // and passes allocations down the pipeline.
-class SamplingProfilerWrapper
-    : private base::PoissonAllocationSampler::SamplesObserver {
+class SamplingProfilerWrapper {
  public:
-  void StartProfiling(SenderPipe* sender_pipe,
-                      mojom::ProfilingParamsPtr params);
+  void StartProfiling(mojom::ProfilingParamsPtr params);
   void StopProfiling();
 
-  // This method closes sender pipe.
-  static void FlushBuffersAndClosePipe();
-
-  // Ensures all send buffers are flushed. The given barrier ID is sent to the
-  // logging process so it knows when this operation is complete.
-  static void FlushPipe(uint32_t barrier_id);
-
   mojom::HeapProfilePtr RetrieveHeapProfile();
-
- private:
-  // base::PoissonAllocationSampler::SamplesObserver
-  void SampleAdded(void* address,
-                   size_t size,
-                   size_t total,
-                   base::PoissonAllocationSampler::AllocatorType,
-                   const char* context) override;
-  void SampleRemoved(void* address) override;
-
-  bool stream_samples_ = false;
 };
 
 }  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/sender_pipe.h b/components/services/heap_profiling/public/cpp/sender_pipe.h
deleted file mode 100644
index a84e837..0000000
--- a/components/services/heap_profiling/public/cpp/sender_pipe.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SENDER_PIPE_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SENDER_PIPE_H_
-
-#include "build/build_config.h"
-
-#include "base/files/platform_file.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "mojo/public/cpp/platform/platform_handle.h"
-
-namespace heap_profiling {
-
-class SenderPipe {
- public:
-  // 64k is a convenient pipe buffer size.
-  // On macOS, the default pipe buffer size is 16 * 1024, but grows to 64 * 1024
-  // for large writes. See BIG_PIPE_SIZE.
-  // https://opensource.apple.com/source/xnu/xnu-1504.9.37/bsd/sys/pipe.h
-  // On Linux [since 2.6.11], the default pipe buffer size is 64 * 1024. See
-  // https://linux.die.net/man/7/pipe
-  // On Windows, the pipe buffer size is configurable.
-  static constexpr size_t kPipeSize = 64 * 1024;
-
-  class PipePair {
-   public:
-    // Returns a pair of newly created pipes. Must be called from a privileged
-    // process. The sender-pipe is non-blocking and has a buffer size of
-    // |kPipeSize|.
-    PipePair();
-    PipePair(PipePair&&);
-    mojo::PlatformHandle PassSender() { return std::move(sender_); }
-    mojo::PlatformHandle PassReceiver() { return std::move(receiver_); }
-
-   private:
-    mojo::PlatformHandle sender_;
-    mojo::PlatformHandle receiver_;
-    DISALLOW_COPY_AND_ASSIGN(PipePair);
-  };
-
-  explicit SenderPipe(mojo::PlatformHandle handle);
-  ~SenderPipe();
-
-  enum class Result { kSuccess, kTimeout, kError };
-
-  // Attempts to atomically write all the |data| into the pipe. kError is
-  // returned on failure, kTimeout after |timeout_ms| milliseconds.
-  Result Send(const void* data, size_t sz, int timeout_ms);
-
-  // Closes the underlying pipe.
-  void Close();
-
- private:
-  base::ScopedPlatformFile file_;
-
-  // All calls to Send() are wrapped in a Lock, since the size of the data might
-  // be larger than the maximum atomic write size of a pipe on Posix [PIPE_BUF].
-  // On Windows, ::WriteFile() is not thread-safe.
-  base::Lock lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(SenderPipe);
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SENDER_PIPE_H_
diff --git a/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc b/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc
deleted file mode 100644
index a6bb324..0000000
--- a/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-
-#include <fcntl.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/strings/string_number_conversions.h"
-#include "build/build_config.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
-
-namespace heap_profiling {
-
-SenderPipe::PipePair::PipePair() {
-  // We create a pipe() rather than a socketpair(). On macOS, this causes writes
-  // to be much more performant. On Linux, this causes slight improvements.
-  // https://bugs.chromium.org/p/chromium/issues/detail?id=776435
-  int fds[2];
-  PCHECK(0 == pipe(fds));
-  PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
-  PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0);
-#if defined(OS_MACOSX)
-  // On macOS, suppress SIGPIPE. On Linux, we must rely on the assumption that
-  // the SIGPIPE signal is ignored [which it is].
-  PCHECK(fcntl(fds[0], F_SETNOSIGPIPE, 1) == 0);
-  PCHECK(fcntl(fds[1], F_SETNOSIGPIPE, 1) == 0);
-#endif
-  receiver_ = mojo::PlatformHandle(base::ScopedFD(fds[0]));
-  sender_ = mojo::PlatformHandle(base::ScopedFD(fds[1]));
-}
-
-SenderPipe::PipePair::PipePair(PipePair&& other) = default;
-
-SenderPipe::SenderPipe(mojo::PlatformHandle handle) : file_(handle.TakeFD()) {}
-
-SenderPipe::~SenderPipe() = default;
-
-SenderPipe::Result SenderPipe::Send(const void* data,
-                                    size_t sz,
-                                    int timeout_ms) {
-  base::AutoLock lock(lock_);
-
-  // This can happen if Close() was called on another thread, while this thread
-  // was already waiting to call SenderPipe::Send().
-  if (!file_.is_valid())
-    return Result::kError;
-
-  int size = base::checked_cast<int>(sz);
-  base::TimeTicks start_time;
-  while (size > 0) {
-    int r = HANDLE_EINTR(write(file_.get(), data, size));
-
-    // On success!
-    if (r != -1) {
-      DCHECK_LE(r, size);
-      size -= r;
-      data = static_cast<const char*>(data) + r;
-      continue;
-    }
-
-    // An error is either irrecoverable, or an I/O delay. Wait at most
-    // timeout_ms seconds for the pipe to clear.
-    int cached_errno = errno;
-    if (cached_errno != EAGAIN && cached_errno != EWOULDBLOCK)
-      return Result::kError;
-
-    // Set the start time, if it hasn't already been set.
-    base::TimeTicks now = base::TimeTicks::Now();
-    if (start_time.is_null())
-      start_time = now;
-
-    // Calculate time left.
-    int64_t time_left_ms =
-        ((start_time + base::TimeDelta::FromMilliseconds(timeout_ms)) - now)
-            .InMilliseconds();
-    if (time_left_ms <= 0)
-      return Result::kTimeout;
-
-    // Wait for the pipe to be writeable.
-    struct pollfd pfd = {file_.get(), POLLOUT, 0};
-    int poll_result =
-        HANDLE_EINTR(poll(&pfd, 1, static_cast<int>(time_left_ms)));
-    if (poll_result == 0)
-      return Result::kTimeout;
-    if (poll_result == -1)
-      return Result::kError;
-
-    // If POLLOUT isn't returned, the pipe isn't writeable.
-    DCHECK_EQ(poll_result, 1);
-    if (!(pfd.revents & POLLOUT))
-      return Result::kError;
-  }
-  return Result::kSuccess;
-}
-
-void SenderPipe::Close() {
-  base::AutoLock lock(lock_);
-  file_.reset();
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc b/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc
deleted file mode 100644
index b9ef5dc..0000000
--- a/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-
-#include <vector>
-
-#include "build/build_config.h"
-#include "mojo/public/cpp/platform/platform_handle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-namespace heap_profiling {
-namespace {
-
-using Result = SenderPipe::Result;
-
-class SenderPipeTest : public testing::Test {
- public:
-  void SetUp() override {
-    SenderPipe::PipePair pipes;
-    read_handle_ = pipes.PassReceiver();
-
-    sender_pipe_.reset(new SenderPipe(pipes.PassSender()));
-
-    // A large buffer for both writing and reading.
-    buffer_.resize(64 * 1024);
-  }
-
-  Result Write(int size) { return sender_pipe_->Send(buffer_.data(), size, 1); }
-
-  void Read(int size) {
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
-    ssize_t bytes_read = read(read_handle_.GetFD().get(), buffer_.data(), size);
-    ASSERT_EQ(size, bytes_read);
-#else
-    OVERLAPPED overlapped;
-    DWORD bytes_read = 0;
-    memset(&overlapped, 0, sizeof(OVERLAPPED));
-    BOOL result = ::ReadFile(read_handle_.GetHandle().Get(), buffer_.data(),
-                             size, &bytes_read, &overlapped);
-    ASSERT_TRUE(result);
-    ASSERT_EQ(static_cast<DWORD>(size), bytes_read);
-#endif
-  }
-
- private:
-  mojo::PlatformHandle read_handle_;
-  std::unique_ptr<SenderPipe> sender_pipe_;
-  std::vector<char> buffer_;
-};
-
-TEST_F(SenderPipeTest, TimeoutNoRead) {
-  // Writing 64k should not time out.
-  Result result = Write(64 * 1024);
-  ASSERT_EQ(Result::kSuccess, result);
-
-  // Writing 64k more should time out, since the buffer size is 64k.
-  result = Write(64 * 1024);
-  ASSERT_EQ(Result::kTimeout, result);
-}
-
-TEST_F(SenderPipeTest, TimeoutSmallRead) {
-  // Writing 64k should not time out.
-  Result result = Write(64 * 1024);
-  ASSERT_EQ(Result::kSuccess, result);
-
-  // Read 32k out of the buffer.
-  Read(32 * 1024);
-
-  // Writing 64k more should still time out, since the buffer size should be
-  // 64k.
-  result = Write(64 * 1024);
-  ASSERT_EQ(Result::kTimeout, result);
-}
-
-TEST_F(SenderPipeTest, NoTimeout) {
-  // Writing 64k should not time out.
-  Result result = Write(64 * 1024);
-  ASSERT_EQ(Result::kSuccess, result);
-
-  // Read 64k out of the buffer.
-  Read(64 * 1024);
-
-  // Writing 64k should not time out.
-  result = Write(64 * 1024);
-  ASSERT_EQ(Result::kSuccess, result);
-}
-
-}  // namespace
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/sender_pipe_win.cc b/components/services/heap_profiling/public/cpp/sender_pipe_win.cc
deleted file mode 100644
index 4c137f70..0000000
--- a/components/services/heap_profiling/public/cpp/sender_pipe_win.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-
-#include <windows.h>
-
-#include "base/logging.h"
-#include "base/rand_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
-
-namespace heap_profiling {
-
-namespace {
-
-// The documentation for ::WriteFileEx indicates that the last parameter is an
-// OVERLAPPED*. But OVERLAPPED has no member to hold a void* context for
-// SenderPipe, and without that, the callback must only use global
-// variables. This is problematic. The example
-// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365601(v=vs.85).aspx
-// instead uses a struct whose first member is an OVERLAPPED object, and passes
-// a struct pointer to ::WriteFileEx.
-struct OverlappedWriteContext {
-  OverlappedWriteContext()
-      : waiting_for_write(true), bytes_written(0), error(ERROR_SUCCESS) {
-    memset(&overlap, 0, sizeof(overlap));
-    overlap.Offset = 0xFFFFFFFF;
-    overlap.OffsetHigh = 0xFFFFFFFF;
-  }
-
-  // This must always be the first member.
-  OVERLAPPED overlap;
-  bool waiting_for_write;
-  DWORD bytes_written;
-  DWORD error;
-};
-
-static_assert(offsetof(OverlappedWriteContext, overlap) == 0,
-              "overlap must always be the first member.");
-
-// A global function called by ::WriteFileEx when the write has finished, or
-// errored.
-void WINAPI AsyncWriteFinishedGlobal(DWORD error,
-                                     DWORD bytes_written,
-                                     LPOVERLAPPED overlap) {
-  OverlappedWriteContext* context =
-      reinterpret_cast<OverlappedWriteContext*>(overlap);
-  context->waiting_for_write = false;
-  context->bytes_written = bytes_written;
-  context->error = error;
-}
-
-}  // namespace
-
-SenderPipe::PipePair::PipePair() {
-  std::wstring pipe_name = base::StringPrintf(
-      L"\\\\.\\pipe\\profiling.%u.%u.%I64u", GetCurrentProcessId(),
-      GetCurrentThreadId(), base::RandUint64());
-
-  HANDLE handle = CreateNamedPipe(
-      pipe_name.c_str(),
-      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
-      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
-      1,          // Max instances.
-      kPipeSize,  // Out buffer size.
-      kPipeSize,  // In buffer size.
-      5000,  // Timeout in milliseconds for connecting the receiving pipe. Has
-             // nothing to do with Send() timeout.
-      nullptr);
-  PCHECK(handle != INVALID_HANDLE_VALUE);
-  receiver_ = mojo::PlatformHandle(base::win::ScopedHandle(handle));
-
-  // Allow the handle to be inherited by child processes.
-  SECURITY_ATTRIBUTES security_attributes;
-  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
-  security_attributes.lpSecurityDescriptor = nullptr;
-  security_attributes.bInheritHandle = TRUE;
-
-  handle = CreateFile(
-      pipe_name.c_str(), GENERIC_WRITE,
-      0,  // No sharing.
-      &security_attributes, OPEN_EXISTING,
-      SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | FILE_FLAG_OVERLAPPED,
-      nullptr);
-  PCHECK(handle != INVALID_HANDLE_VALUE);
-  sender_ = mojo::PlatformHandle(base::win::ScopedHandle(handle));
-
-  // Since a client has connected, ConnectNamedPipe() should return zero and
-  // GetLastError() should return ERROR_PIPE_CONNECTED.
-  BOOL result = ConnectNamedPipe(receiver_.GetHandle().Get(), nullptr);
-  DWORD error = GetLastError();
-  CHECK((result == 0) && (error == ERROR_PIPE_CONNECTED));
-}
-
-SenderPipe::PipePair::PipePair(PipePair&& other) = default;
-
-SenderPipe::SenderPipe(mojo::PlatformHandle handle)
-    : file_(handle.TakeHandle()) {}
-
-SenderPipe::~SenderPipe() {}
-
-SenderPipe::Result SenderPipe::Send(const void* data,
-                                    size_t size,
-                                    int timeout_ms) {
-  // The pipe is nonblocking. However, to ensure that messages on different
-  // threads are serialized and in order:
-  //   1) We grab a global lock.
-  //   2) We attempt to synchronously write, but with a timeout. On timeout
-  //   or error, the SenderPipe is shut down.
-  base::AutoLock lock(lock_);
-
-  // This can happen if Close() was called on another thread, while this thread
-  // was already waiting to call SenderPipe::Send().
-  if (!file_.IsValid())
-    return Result::kError;
-
-  // Queue an asynchronous write.
-  OverlappedWriteContext context;
-
-  // It's safe to use a raw pointer to |context|, since it will stay on the
-  // stack until ::SleepEx returns, at which point either the callback has
-  // finished, or will be cancelled.
-  BOOL write_result = ::WriteFileEx(file_.Get(), data, static_cast<DWORD>(size),
-                                    &context.overlap, AsyncWriteFinishedGlobal);
-
-  // Check for errors.
-  if (!write_result)
-    return Result::kError;
-
-  // The documentation for ::WriteFileEx
-  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365748(v=vs.85).aspx
-  // claims that we need to check GetLastError() even on success. This is
-  // incorrect. GetLastError() returns the error from the previous Windows
-  // library call.
-
-  while (true) {
-    // The return code of ::SleepEx has multiple semantics. Do not replace this
-    // with PlatformThread::Sleep.
-    DWORD sleep_result = ::SleepEx(timeout_ms, TRUE);
-
-    // Timeout reached.
-    if (sleep_result == 0) {
-      BOOL r = ::CancelIo(file_.Get());
-      DCHECK_NE(0, r);
-      DWORD r2 = ::WaitForSingleObject(file_.Get(), INFINITE);
-      DCHECK_EQ(WAIT_OBJECT_0, r2);
-      return Result::kTimeout;
-    }
-
-    // Unexpected error.
-    if (sleep_result != WAIT_IO_COMPLETION)
-      return Result::kError;
-
-    // In the very rare case where this function returns from the completion of
-    // another async IO handler, just repeat the sleep duration. This allows us
-    // to avoid a call to base::TimeTicks::Now() in the common case.
-    if (context.waiting_for_write)
-      continue;
-
-    if (context.error != ERROR_SUCCESS)
-      return Result::kError;
-
-    // Partial writes should not be possible.
-    DCHECK_EQ(context.bytes_written, size);
-    return Result::kSuccess;
-  }
-}
-
-void SenderPipe::Close() {
-  base::AutoLock lock(lock_);
-  file_.Close();
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/settings.cc b/components/services/heap_profiling/public/cpp/settings.cc
index 96b3a3c..f569e80 100644
--- a/components/services/heap_profiling/public/cpp/settings.cc
+++ b/components/services/heap_profiling/public/cpp/settings.cc
@@ -145,11 +145,6 @@
       kDefaultSamplingRate);
 }
 
-bool IsInProcessModeEnabled() {
-  return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-             kMemlogInProcess) != kMemlogInProcessDisabled;
-}
-
 bool IsBackgroundHeapProfilingEnabled() {
   return base::FeatureList::IsEnabled(kOOPHeapProfilingFeature);
 }
diff --git a/components/services/heap_profiling/public/cpp/settings.h b/components/services/heap_profiling/public/cpp/settings.h
index 6cb5cdd..1e5e8da 100644
--- a/components/services/heap_profiling/public/cpp/settings.h
+++ b/components/services/heap_profiling/public/cpp/settings.h
@@ -59,7 +59,6 @@
 // recorded every N bytes of allocated objects.
 uint32_t GetSamplingRateForStartup();
 
-bool IsInProcessModeEnabled();
 bool IsBackgroundHeapProfilingEnabled();
 
 // Exposed for testing.
diff --git a/components/services/heap_profiling/public/cpp/stream.h b/components/services/heap_profiling/public/cpp/stream.h
deleted file mode 100644
index 8e01f80..0000000
--- a/components/services/heap_profiling/public/cpp/stream.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// We use a custom stream format for performance, since we're potentially
-// sending a packet for every malloc and free.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_STREAM_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_STREAM_H_
-
-#include <stdint.h>
-
-#include "build/build_config.h"
-
-namespace heap_profiling {
-
-// These values should be kept in sync with
-// chrome/profiling/stream_fuzzer.dict to ensure efficient fuzzer
-// coverage of the stream parser.
-constexpr uint32_t kStreamSignature = 0xF6103B71;
-
-constexpr uint32_t kAllocPacketType = 0xF6103B72;
-constexpr uint32_t kFreePacketType = 0xF6103B73;
-constexpr uint32_t kBarrierPacketType = 0xF6103B74;
-constexpr uint32_t kStringMappingPacketType = 0xF6103B75;
-
-constexpr uint32_t kMaxStackEntries = 256;
-constexpr uint32_t kMaxContextLen = 256;
-
-// This should count up from 0 so it can be used to index into an array.
-enum class AllocatorType : uint32_t {
-  kMalloc = 0,
-  kPartitionAlloc = 1,
-  kOilpan = 2,
-  kCount  // Number of allocator types.
-};
-
-#pragma pack(push, 1)
-struct StreamHeader {
-  uint32_t signature = kStreamSignature;
-};
-
-struct AllocPacket {
-  uint32_t op = kAllocPacketType;
-
-  AllocatorType allocator;
-
-  uint64_t address;
-  uint64_t size;
-
-  // Number of stack entries following this header.
-  uint32_t stack_len;
-
-  // Number of context bytes following the stack;
-  uint32_t context_byte_len;
-
-  // Immediately followed by |stack_len| uint64_t addresses and
-  // |context_byte_len| bytes of context (not null terminated).
-};
-
-struct FreePacket {
-  uint32_t op = kFreePacketType;
-
-  uint64_t address;
-};
-
-// A barrier packet is a way to synchronize with the sender to make sure all
-// events are received up to a certain point. The barrier ID is just a number
-// that can be used to uniquely identify these events.
-struct BarrierPacket {
-  const uint32_t op = kBarrierPacketType;
-
-  uint32_t barrier_id;
-};
-
-// Clients will sometimes use pointers to const strings in place of instruction
-// addresses in AllocPackets. Prior to using such a pointer, the client should
-// send a StringMappingPacket to inform the profiling service.
-struct StringMappingPacket {
-  const uint32_t op = kStringMappingPacketType;
-  uint64_t address;
-  uint32_t string_len;
-
-  // Immediately followed by |string_len| bytes of string (not null
-  // terminated).
-};
-
-#pragma pack(pop)
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_STREAM_H_
diff --git a/components/services/heap_profiling/public/cpp/switches.cc b/components/services/heap_profiling/public/cpp/switches.cc
index 8f4a317..0d5a6e4 100644
--- a/components/services/heap_profiling/public/cpp/switches.cc
+++ b/components/services/heap_profiling/public/cpp/switches.cc
@@ -6,10 +6,6 @@
 
 namespace heap_profiling {
 
-const char kMemlogInProcess[] = "memlog-in-process";
-const char kMemlogInProcessEnabled[] = "on";
-const char kMemlogInProcessDisabled[] = "off";
-
 const char kMemlogMode[] = "memlog";
 const char kMemlogModeAll[] = "all";
 const char kMemlogModeAllRenderers[] = "all-renderers";
diff --git a/components/services/heap_profiling/public/cpp/switches.h b/components/services/heap_profiling/public/cpp/switches.h
index 12d5326..8cf4cea 100644
--- a/components/services/heap_profiling/public/cpp/switches.h
+++ b/components/services/heap_profiling/public/cpp/switches.h
@@ -18,10 +18,6 @@
 extern const char kMemlogModeUtilityAndBrowser[];
 extern const char kMemlogModeUtilitySampling[];
 
-extern const char kMemlogInProcess[];
-extern const char kMemlogInProcessEnabled[];
-extern const char kMemlogInProcessDisabled[];
-
 extern const char kMemlogSamplingRate[];
 extern const char kMemlogSamplingRate10KB[];
 extern const char kMemlogSamplingRate50KB[];
diff --git a/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom b/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom
index 6a96077..33efeeed 100644
--- a/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom
+++ b/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom
@@ -20,18 +20,16 @@
   MIXED
 };
 
+// Type of the allocator responsible for the allocation sample.
+enum AllocatorType {
+  kMalloc,
+  kPartitionAlloc,
+  kOilpan
+};
+
 // A wrapper for parameters that affect each client's implementation of
 // profiling.
 struct ProfilingParams {
-  // When |stream_samples| is true the samples are streamed through the
-  // provided |sender_pipe|. Otherwise, the samples are stored on
-  // the client side during recording and can be retrieved using
-  // |ProfilingClient.RetrieveHeapProfile| method.
-  bool stream_samples;
-
-  // The client should record allocations into |memlog_sender_pipe|.
-  handle sender_pipe;
-
   // |stack_mode| refers to the type of data that should be recorded for each
   // allocation.
   StackMode stack_mode;
@@ -46,7 +44,7 @@
 // A single memory allocation sample.
 struct HeapProfileSample {
   // Allocator type.
-  uint32 allocator;
+  AllocatorType allocator;
 
   // The size in bytes accounted for the sample.
   uint64 size;
@@ -81,10 +79,5 @@
   // There is currently no mechanism to stop recording allocations.
   StartProfiling(ProfilingParams params);
 
-  // Flushes the memlog pipe associated with this client. A barrier packet is
-  // set over the memlog pipe with the given identifier. This allows the
-  // receiver to synchronize with the flush.
-  FlushMemlogPipe(uint32 barrier_id);
-
   RetrieveHeapProfile() => (HeapProfile profile);
 };
diff --git a/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom b/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom
index d349b7f..e8e0ff6 100644
--- a/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom
+++ b/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom
@@ -24,15 +24,8 @@
   //
   // The "client" interface will be for the instrumented process. It allows the
   // profiling process to talk to the new process.
-  //
-  // Both ends of a platform-specific pipe to read memlog trace data from is
-  // passed in. The sender end will be forwarded to the client process.
-  //
-  // |stack_mode| refers to the type of stacks that the client should record for
-  // allocations.
   AddProfilingClient(mojo_base.mojom.ProcessId pid, ProfilingClient client,
-                     handle memlog_pipe_receiver, ProcessType process_type,
-                     ProfilingParams params);
+                     ProcessType process_type, ProfilingParams params);
 
   // Returns the pids of all profiled processes.
   GetProfiledPids() => (array<mojo_base.mojom.ProcessId> pids);
diff --git a/components/services/heap_profiling/receiver.h b/components/services/heap_profiling/receiver.h
deleted file mode 100644
index 332d0d9..0000000
--- a/components/services/heap_profiling/receiver.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_H_
-
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "components/services/heap_profiling/address.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
-
-namespace heap_profiling {
-
-// A log receiver is a sink for parsed allocation events. See also
-// StreamReceiver which is for the unparsed data blocks.
-class Receiver {
- public:
-  virtual ~Receiver() {}
-
-  virtual void OnHeader(const StreamHeader& header) = 0;
-  virtual void OnAlloc(const AllocPacket& alloc_packet,
-                       std::vector<Address>&& stack,
-                       std::string&& context) = 0;
-  virtual void OnFree(const FreePacket& free_packet) = 0;
-  virtual void OnBarrier(const BarrierPacket& barrier_packet) = 0;
-  virtual void OnStringMapping(const StringMappingPacket& string_mapping_packet,
-                               const std::string& str) = 0;
-  virtual void OnComplete() = 0;
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_H_
diff --git a/components/services/heap_profiling/receiver_pipe.cc b/components/services/heap_profiling/receiver_pipe.cc
deleted file mode 100644
index 1d383c5..0000000
--- a/components/services/heap_profiling/receiver_pipe.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/receiver_pipe.h"
-
-#include "base/bind.h"
-#include "base/task_runner.h"
-#include "components/services/heap_profiling/stream_receiver.h"
-
-namespace heap_profiling {
-
-ReceiverPipeBase::ReceiverPipeBase(mojo::PlatformHandle handle)
-    : handle_(std::move(handle)) {}
-
-ReceiverPipeBase::~ReceiverPipeBase() = default;
-
-void ReceiverPipeBase::SetReceiver(scoped_refptr<base::TaskRunner> task_runner,
-                                   scoped_refptr<StreamReceiver> receiver) {
-  receiver_task_runner_ = std::move(task_runner);
-  receiver_ = receiver;
-}
-
-void ReceiverPipeBase::ReportError() {
-  handle_.reset();
-}
-
-void ReceiverPipeBase::OnStreamDataThunk(
-    scoped_refptr<base::TaskRunner> pipe_task_runner,
-    std::unique_ptr<char[]> data,
-    size_t size) {
-  if (!receiver_->OnStreamData(std::move(data), size)) {
-    pipe_task_runner->PostTask(
-        FROM_HERE, base::BindOnce(&ReceiverPipeBase::ReportError, this));
-  }
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/receiver_pipe.h b/components/services/heap_profiling/receiver_pipe.h
deleted file mode 100644
index d0e56150..0000000
--- a/components/services/heap_profiling/receiver_pipe.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_H_
-
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-#include "mojo/public/cpp/platform/platform_handle.h"
-
-namespace base {
-class TaskRunner;
-}
-
-namespace heap_profiling {
-
-class StreamReceiver;
-
-// Base class for the platform-specific receiver pipes. Since there is only
-// ever one actual implementation of this in the system, those implementations
-// are called "ReceiverPipe" and the common functions are not
-// virtual. This class is just for the shared implementation.
-class ReceiverPipeBase : public base::RefCountedThreadSafe<ReceiverPipeBase> {
- public:
-  void SetReceiver(scoped_refptr<base::TaskRunner> task_runner,
-                   scoped_refptr<StreamReceiver> receiver);
-
- protected:
-  friend class base::RefCountedThreadSafe<ReceiverPipeBase>;
-
-  explicit ReceiverPipeBase(mojo::PlatformHandle handle);
-  virtual ~ReceiverPipeBase();
-
-  // Callback that indicates an error has occurred and the connection should
-  // be closed. May be called more than once in an error condition.
-  void ReportError();
-
-  // Called on the receiver task runner's thread to call the OnStreamData
-  // function and post the error back to the pipe on the correct thread if one
-  // occurs.
-  void OnStreamDataThunk(scoped_refptr<base::TaskRunner> pipe_task_runner,
-                         std::unique_ptr<char[]> data,
-                         size_t size);
-
-  scoped_refptr<base::TaskRunner> receiver_task_runner_;
-  scoped_refptr<StreamReceiver> receiver_;
-
-  mojo::PlatformHandle handle_;
-};
-
-}  // namespace heap_profiling
-
-// Define the platform-specific specialization.
-#if defined(OS_WIN)
-#include "components/services/heap_profiling/receiver_pipe_win.h"
-#else
-#include "components/services/heap_profiling/receiver_pipe_posix.h"
-#endif
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_H_
diff --git a/components/services/heap_profiling/receiver_pipe_posix.cc b/components/services/heap_profiling/receiver_pipe_posix.cc
deleted file mode 100644
index c8cb80b..0000000
--- a/components/services/heap_profiling/receiver_pipe_posix.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/receiver_pipe_posix.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-#include "components/services/heap_profiling/receiver_pipe.h"
-#include "components/services/heap_profiling/stream_receiver.h"
-
-namespace heap_profiling {
-
-ReceiverPipe::ReceiverPipe(mojo::PlatformHandle handle)
-    : ReceiverPipeBase(std::move(handle)),
-      controller_(FROM_HERE),
-      read_buffer_(new char[SenderPipe::kPipeSize]) {}
-
-ReceiverPipe::~ReceiverPipe() {}
-
-void ReceiverPipe::StartReadingOnIOThread() {
-  base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
-      handle_.GetFD().get(), true, base::MessagePumpForIO::WATCH_READ,
-      &controller_, this);
-  OnFileCanReadWithoutBlocking(handle_.GetFD().get());
-}
-
-void ReceiverPipe::OnFileCanReadWithoutBlocking(int fd) {
-  ssize_t bytes_read = 0;
-  do {
-    bytes_read = HANDLE_EINTR(
-        read(handle_.GetFD().get(), read_buffer_.get(), SenderPipe::kPipeSize));
-    if (bytes_read > 0) {
-      receiver_task_runner_->PostTask(
-          FROM_HERE,
-          base::BindOnce(&ReceiverPipe::OnStreamDataThunk, this,
-                         base::MessageLoopCurrent::Get()->task_runner(),
-                         std::move(read_buffer_),
-                         static_cast<size_t>(bytes_read)));
-      read_buffer_.reset(new char[SenderPipe::kPipeSize]);
-      return;
-    } else if (bytes_read == 0) {
-      // Other end closed the pipe.
-      controller_.StopWatchingFileDescriptor();
-      DCHECK(receiver_task_runner_);
-      receiver_task_runner_->PostTask(
-          FROM_HERE,
-          base::BindOnce(&StreamReceiver::OnStreamComplete, receiver_));
-      return;
-    } else {
-      if (errno != EAGAIN && errno != EWOULDBLOCK) {
-        controller_.StopWatchingFileDescriptor();
-        PLOG(ERROR) << "Problem reading socket.";
-        DCHECK(receiver_task_runner_);
-        receiver_task_runner_->PostTask(
-            FROM_HERE,
-            base::BindOnce(&StreamReceiver::OnStreamComplete, receiver_));
-      }
-    }
-  } while (bytes_read > 0);
-}
-
-void ReceiverPipe::OnFileCanWriteWithoutBlocking(int fd) {
-  NOTREACHED();
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/receiver_pipe_posix.h b/components/services/heap_profiling/receiver_pipe_posix.h
deleted file mode 100644
index 30f0a2f..0000000
--- a/components/services/heap_profiling/receiver_pipe_posix.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_POSIX_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_POSIX_H_
-
-#include <string>
-
-#include "base/files/platform_file.h"
-#include "base/macros.h"
-#include "base/message_loop/message_pump_for_io.h"
-#include "build/build_config.h"
-#include "components/services/heap_profiling/receiver_pipe.h"
-
-namespace heap_profiling {
-
-class ReceiverPipe : public ReceiverPipeBase,
-                     public base::MessagePumpForIO::FdWatcher {
- public:
-  explicit ReceiverPipe(mojo::PlatformHandle handle);
-
-  // Must be called on the IO thread.
-  void StartReadingOnIOThread();
-
- private:
-  ~ReceiverPipe() override;
-
-  // MessagePumpForIO::FdWatcher implementation.
-  void OnFileCanReadWithoutBlocking(int fd) override;
-  void OnFileCanWriteWithoutBlocking(int fd) override;
-
-  base::MessagePumpForIO::FdWatchController controller_;
-  std::unique_ptr<char[]> read_buffer_;
-
-  DISALLOW_COPY_AND_ASSIGN(ReceiverPipe);
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_POSIX_H_
diff --git a/components/services/heap_profiling/receiver_pipe_win.cc b/components/services/heap_profiling/receiver_pipe_win.cc
deleted file mode 100644
index d2945bd..0000000
--- a/components/services/heap_profiling/receiver_pipe_win.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/receiver_pipe_win.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread.h"
-#include "components/services/heap_profiling/public/cpp/sender_pipe.h"
-#include "components/services/heap_profiling/receiver_pipe.h"
-#include "components/services/heap_profiling/stream_receiver.h"
-
-namespace heap_profiling {
-
-ReceiverPipe::ReceiverPipe(mojo::PlatformHandle handle)
-    : ReceiverPipeBase(std::move(handle)),
-      read_buffer_(new char[SenderPipe::kPipeSize]) {
-  ZeroOverlapped();
-}
-
-ReceiverPipe::~ReceiverPipe() = default;
-
-void ReceiverPipe::StartReadingOnIOThread() {
-  base::MessageLoopCurrentForIO::Get()->RegisterIOHandler(
-      handle_.GetHandle().Get(), this);
-  ReadUntilBlocking();
-}
-
-void ReceiverPipe::ReadUntilBlocking() {
-  // TODO(brettw) note that the IO completion callback will always be issued,
-  // even for sync returns of ReadFile. If there is a lot of data ready to be
-  // read, it would be nice to process them all in this loop rather than having
-  // to go back to the message loop for each block, but that will require
-  // different IOContext structures for each one.
-  DWORD bytes_read = 0;
-  ZeroOverlapped();
-
-  DCHECK(!read_outstanding_);
-  read_outstanding_ = this;
-  if (!::ReadFile(handle_.GetHandle().Get(), read_buffer_.get(),
-                  SenderPipe::kPipeSize, &bytes_read, &context_.overlapped)) {
-    if (GetLastError() == ERROR_IO_PENDING) {
-      return;
-    } else {
-      if (receiver_) {
-        receiver_task_runner_->PostTask(
-            FROM_HERE,
-            base::BindOnce(&StreamReceiver::OnStreamComplete, receiver_));
-      }
-      return;
-    }
-  }
-}
-
-void ReceiverPipe::ZeroOverlapped() {
-  memset(&context_.overlapped, 0, sizeof(OVERLAPPED));
-}
-
-void ReceiverPipe::OnIOCompleted(base::MessagePumpForIO::IOContext* context,
-                                 DWORD bytes_transfered,
-                                 DWORD error) {
-  // Note: any crashes with this on the stack are likely a result of destroying
-  // a relevant class while there is I/O pending.
-  DCHECK(read_outstanding_);
-  // Clear |read_outstanding_| but retain the reference to keep ourself alive
-  // until this function returns.
-  scoped_refptr<ReceiverPipe> self(std::move(read_outstanding_));
-
-  if (bytes_transfered && receiver_) {
-    receiver_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&ReceiverPipe::OnStreamDataThunk, this,
-                       base::MessageLoopCurrent::Get()->task_runner(),
-                       std::move(read_buffer_),
-                       static_cast<size_t>(bytes_transfered)));
-    read_buffer_.reset(new char[SenderPipe::kPipeSize]);
-  }
-  ReadUntilBlocking();
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/receiver_pipe_win.h b/components/services/heap_profiling/receiver_pipe_win.h
deleted file mode 100644
index 603f603..0000000
--- a/components/services/heap_profiling/receiver_pipe_win.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_WIN_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_WIN_H_
-
-#include <windows.h>
-
-#include <string>
-
-#include "base/files/platform_file.h"
-#include "base/macros.h"
-#include "base/message_loop/message_pump_win.h"
-#include "base/strings/string16.h"
-#include "build/build_config.h"
-#include "components/services/heap_profiling/receiver_pipe.h"
-
-namespace heap_profiling {
-
-class ReceiverPipe : public ReceiverPipeBase,
-                     public base::MessagePumpForIO::IOHandler {
- public:
-  explicit ReceiverPipe(mojo::PlatformHandle handle);
-
-  // Must be called on the IO thread.
-  void StartReadingOnIOThread();
-
- private:
-  ~ReceiverPipe() override;
-
-  void ReadUntilBlocking();
-  void ZeroOverlapped();
-
-  // IOHandler implementation.
-  void OnIOCompleted(base::MessagePumpForIO::IOContext* context,
-                     DWORD bytes_transfered,
-                     DWORD error) override;
-
-  base::MessagePumpForIO::IOContext context_;
-
-  // Used to keep |this| live while awaiting IO completion, which is required
-  // to avoid premature destruction during shutdown.
-  scoped_refptr<ReceiverPipe> read_outstanding_;
-
-  std::unique_ptr<char[]> read_buffer_;
-
-  DISALLOW_COPY_AND_ASSIGN(ReceiverPipe);
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_RECEIVER_PIPE_WIN_H_
diff --git a/components/services/heap_profiling/stream_fuzzer.cc b/components/services/heap_profiling/stream_fuzzer.cc
deleted file mode 100644
index cf73ca9a..0000000
--- a/components/services/heap_profiling/stream_fuzzer.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "components/services/heap_profiling/receiver.h"
-#include "components/services/heap_profiling/stream_parser.h"
-
-#include <utility>
-
-struct Environment {
-  Environment() {
-    // Disable noisy logging as per "libFuzzer in Chrome" documentation:
-    // testing/libfuzzer/getting_started.md#Disable-noisy-error-message-logging.
-    logging::SetMinLogLevel(logging::LOG_FATAL);
-  }
-};
-
-namespace heap_profiling {
-namespace {
-
-class DummyReceiver : public Receiver {
-  void OnHeader(const StreamHeader& header) override {}
-  void OnAlloc(const AllocPacket& alloc_packet,
-               std::vector<Address>&& stack,
-               std::string&& context) override {}
-  void OnFree(const FreePacket& free_packet) override {}
-  void OnBarrier(const BarrierPacket& barrier_packet) override {}
-  void OnComplete() override {}
-  void OnStringMapping(const StringMappingPacket& string_mapping_packet,
-                       const std::string& str) override {}
-};
-
-}  // namespace
-}  // namespace heap_profiling
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  // Initialize environment once.
-  static Environment env;
-
-  heap_profiling::DummyReceiver receiver;
-  scoped_refptr<heap_profiling::StreamParser> parser(
-      new heap_profiling::StreamParser(&receiver));
-  std::unique_ptr<char[]> stream_data(new char[size]);
-  memcpy(stream_data.get(), data, size);
-  parser->OnStreamData(std::move(stream_data), size);
-  return 0;
-}
diff --git a/components/services/heap_profiling/stream_fuzzer.dict b/components/services/heap_profiling/stream_fuzzer.dict
deleted file mode 100644
index 7accea7..0000000
--- a/components/services/heap_profiling/stream_fuzzer.dict
+++ /dev/null
@@ -1,6 +0,0 @@
-# These values are obtained from components/services/heap_profiling/stream.h.
-stream_signature="\xF6\x10\x3B\x71"
-alloc_packet="\xF6\x10\x3B\x72"
-free_packet="\xF6\x10\x3B\x73"
-barrier_packet="\xF6\x10\x3B\x74"
-string_mapping_packet="\xF6\x10\x3B\x75"
diff --git a/components/services/heap_profiling/stream_parser.cc b/components/services/heap_profiling/stream_parser.cc
deleted file mode 100644
index 9fc8a42..0000000
--- a/components/services/heap_profiling/stream_parser.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/stream_parser.h"
-
-#include <algorithm>
-
-#include "base/containers/stack_container.h"
-#include "base/strings/stringprintf.h"
-#include "components/services/heap_profiling/address.h"
-#include "components/services/heap_profiling/backtrace.h"
-#include "components/services/heap_profiling/public/cpp/stream.h"
-
-namespace heap_profiling {
-
-StreamParser::Block::Block(std::unique_ptr<char[]> d, size_t s)
-    : data(std::move(d)), size(s) {}
-
-StreamParser::Block::Block(Block&& other) noexcept = default;
-
-StreamParser::Block::~Block() = default;
-
-StreamParser::StreamParser(Receiver* receiver) : receiver_(receiver) {}
-
-StreamParser::~StreamParser() {}
-
-void StreamParser::DisconnectReceivers() {
-  base::AutoLock lock(lock_);
-  receiver_ = nullptr;
-}
-
-bool StreamParser::OnStreamData(std::unique_ptr<char[]> data, size_t sz) {
-  base::AutoLock l(lock_);
-  if (!receiver_ || error_)
-    return false;
-
-  blocks_.emplace_back(std::move(data), sz);
-
-  if (!received_header_) {
-    ReadStatus status = ParseHeader();
-    if (status == READ_NO_DATA)
-      return true;  // Wait for more data.
-    if (status == READ_ERROR) {
-      SetErrorState();
-      return false;
-    }
-    received_header_ = true;
-  }
-
-  while (true) {
-    uint32_t msg_type;
-    if (!PeekBytes(sizeof(msg_type), &msg_type))
-      return true;  // Not enough data for a message type field.
-
-    ReadStatus status;
-    switch (msg_type) {
-      case kAllocPacketType:
-        status = ParseAlloc();
-        break;
-      case kFreePacketType:
-        status = ParseFree();
-        break;
-      case kBarrierPacketType:
-        status = ParseBarrier();
-        break;
-      case kStringMappingPacketType:
-        status = ParseStringMapping();
-        break;
-      default:
-        // Invalid message type.
-        status = READ_ERROR;
-        break;
-    }
-
-    if (status == READ_NO_DATA)
-      return true;  // Wait for more data.
-    if (status == READ_ERROR) {
-      SetErrorState();
-      return false;
-    }
-    // Success, loop around for more data.
-  }
-}
-
-void StreamParser::OnStreamComplete() {
-  base::AutoLock l(lock_);
-  if (receiver_)
-    receiver_->OnComplete();
-}
-
-bool StreamParser::AreBytesAvailable(size_t count) const {
-  size_t used = 0;
-  size_t current_block_offset = block_zero_offset_;
-  for (auto it = blocks_.begin(); it != blocks_.end() && used < count; ++it) {
-    used += it->size - current_block_offset;
-    current_block_offset = 0;
-  }
-  return used >= count;
-}
-
-bool StreamParser::PeekBytes(size_t count, void* dest) const {
-  char* dest_char = static_cast<char*>(dest);
-  size_t used = 0;
-
-  size_t current_block_offset = block_zero_offset_;
-  for (const auto& block : blocks_) {
-    size_t in_current_block = block.size - current_block_offset;
-    size_t to_copy = std::min(count - used, in_current_block);
-
-    memcpy(&dest_char[used], &block.data[current_block_offset], to_copy);
-    used += to_copy;
-
-    // All subsequent blocks start reading at offset 0.
-    current_block_offset = 0;
-  }
-  return used == count;
-}
-
-bool StreamParser::ReadBytes(size_t count, void* dest) {
-  if (!PeekBytes(count, dest))
-    return false;
-  ConsumeBytes(count);
-  return true;
-}
-
-void StreamParser::ConsumeBytes(size_t count) {
-  DCHECK(AreBytesAvailable(count));
-  while (count > 0) {
-    size_t bytes_left_in_block = blocks_.front().size - block_zero_offset_;
-    if (bytes_left_in_block > count) {
-      // Still data left in this block;
-      block_zero_offset_ += count;
-      return;
-    }
-
-    // Current block is consumed.
-    blocks_.pop_front();
-    block_zero_offset_ = 0;
-    count -= bytes_left_in_block;
-  }
-}
-
-StreamParser::ReadStatus StreamParser::ParseHeader() {
-  StreamHeader header;
-  if (!ReadBytes(sizeof(StreamHeader), &header))
-    return READ_NO_DATA;
-
-  if (header.signature != kStreamSignature) {
-    return READ_ERROR;
-  }
-
-  receiver_->OnHeader(header);
-  return READ_OK;
-}
-
-StreamParser::ReadStatus StreamParser::ParseAlloc() {
-  // Read the packet. Can't commit the read until the stack is read and
-  // that has to be done below.
-  AllocPacket alloc_packet;
-  if (!PeekBytes(sizeof(AllocPacket), &alloc_packet))
-    return READ_NO_DATA;
-
-  // Validate data.
-  if (alloc_packet.stack_len > kMaxStackEntries ||
-      alloc_packet.context_byte_len > kMaxContextLen ||
-      alloc_packet.allocator >= AllocatorType::kCount) {
-    return READ_ERROR;
-  }
-
-  std::vector<Address> stack;
-  stack.resize(alloc_packet.stack_len);
-  size_t stack_byte_size = sizeof(Address) * alloc_packet.stack_len;
-
-  if (!AreBytesAvailable(sizeof(AllocPacket) + stack_byte_size +
-                         alloc_packet.context_byte_len))
-    return READ_NO_DATA;
-
-  // Everything will fit, mark header consumed.
-  ConsumeBytes(sizeof(AllocPacket));
-
-  // Read stack.
-  if (!stack.empty())
-    ReadBytes(stack_byte_size, stack.data());
-
-  // Read context.
-  std::string context;
-  context.resize(alloc_packet.context_byte_len);
-  if (alloc_packet.context_byte_len)
-    ReadBytes(alloc_packet.context_byte_len, &context[0]);
-
-  receiver_->OnAlloc(alloc_packet, std::move(stack), std::move(context));
-  return READ_OK;
-}
-
-StreamParser::ReadStatus StreamParser::ParseFree() {
-  FreePacket free_packet;
-  if (!ReadBytes(sizeof(FreePacket), &free_packet))
-    return READ_NO_DATA;
-
-  receiver_->OnFree(free_packet);
-  return READ_OK;
-}
-
-StreamParser::ReadStatus StreamParser::ParseBarrier() {
-  BarrierPacket barrier_packet;
-  if (!ReadBytes(sizeof(BarrierPacket), &barrier_packet))
-    return READ_NO_DATA;
-
-  receiver_->OnBarrier(barrier_packet);
-  return READ_OK;
-}
-
-StreamParser::ReadStatus StreamParser::ParseStringMapping() {
-  StringMappingPacket string_mapping_packet;
-  if (!PeekBytes(sizeof(StringMappingPacket), &string_mapping_packet))
-    return READ_NO_DATA;
-
-  if (!AreBytesAvailable(sizeof(StringMappingPacket) +
-                         string_mapping_packet.string_len))
-    return READ_NO_DATA;
-
-  // Everything will fit, mark header consumed.
-  ConsumeBytes(sizeof(StringMappingPacket));
-
-  // Treat the incoming characters as an opaque blob. It should not contain null
-  // characters but a malicious attacker could change that.
-  std::string str;
-
-  str.resize(string_mapping_packet.string_len);
-  ReadBytes(string_mapping_packet.string_len, &str[0]);
-
-  receiver_->OnStringMapping(string_mapping_packet, str);
-  return READ_OK;
-}
-
-void StreamParser::SetErrorState() {
-  LOG(ERROR) << "StreamParser parsing error";
-  error_ = true;
-  receiver_->OnComplete();
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/stream_parser.h b/components/services/heap_profiling/stream_parser.h
deleted file mode 100644
index 8438b6d..0000000
--- a/components/services/heap_profiling/stream_parser.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_STREAM_PARSER_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_STREAM_PARSER_H_
-
-#include "base/callback.h"
-#include "base/containers/circular_deque.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "components/services/heap_profiling/receiver.h"
-#include "components/services/heap_profiling/stream_receiver.h"
-
-namespace heap_profiling {
-
-// Parses a memory stream. Refcounted via StreamReceiver.
-class StreamParser : public StreamReceiver {
- public:
-  // Both receivers must either outlive this class or live until
-  // DisconnectReceivers is called.
-  explicit StreamParser(Receiver* receiver);
-
-  // For tear-down, resets both receivers so they will not be called.
-  void DisconnectReceivers();
-
-  // StreamReceiver implementation.
-  bool OnStreamData(std::unique_ptr<char[]> data, size_t sz) override;
-  void OnStreamComplete() override;
-
-  base::Lock* GetLock() { return &lock_; }
-
-  // Returns true if this stream has encountered a fatal parse error.
-  bool has_error() const { return error_; }
-
- private:
-  struct Block {
-    Block(std::unique_ptr<char[]> d, size_t s);
-    Block(Block&& other) noexcept;
-    ~Block();
-
-    std::unique_ptr<char[]> data;
-    size_t size;
-  };
-
-  enum ReadStatus {
-    READ_OK,      // Read OK.
-    READ_ERROR,   // Fatal error, don't send more data.
-    READ_NO_DATA  // Not enough data, try again when we get more
-  };
-
-  ~StreamParser() override;
-
-  // Returns true if the given number of bytes are available now.
-  bool AreBytesAvailable(size_t count) const;
-
-  // Returns false if not enough bytes are available. On failure, the dest
-  // buffer will be in an undefined state (it may be written partially).
-  bool PeekBytes(size_t count, void* dest) const;
-  bool ReadBytes(size_t count, void* dest);
-  void ConsumeBytes(size_t count);  // Bytes must be available.
-
-  ReadStatus ParseHeader();
-  ReadStatus ParseAlloc();
-  ReadStatus ParseFree();
-  ReadStatus ParseBarrier();
-  ReadStatus ParseStringMapping();
-
-  void SetErrorState();
-
-  // Not owned by this class.
-  Receiver* receiver_;
-
-  base::circular_deque<Block> blocks_;
-
-  bool received_header_ = false;
-  bool error_ = false;
-
-  // Current offset into blocks_[0] of the next packet to process.
-  size_t block_zero_offset_ = 0;
-
-  // This lock must be acquired anytime the stream is being parsed. This
-  // prevents concurrent access to data structures used by both the parser and
-  // the memory dumper.
-  base::Lock lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(StreamParser);
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_STREAM_PARSER_H_
diff --git a/components/services/heap_profiling/stream_parser_unittest.cc b/components/services/heap_profiling/stream_parser_unittest.cc
deleted file mode 100644
index e2e7f7d..0000000
--- a/components/services/heap_profiling/stream_parser_unittest.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/heap_profiling/stream_parser.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace heap_profiling {
-
-namespace {
-
-void SendData(const scoped_refptr<StreamParser>& parser,
-              const void* data,
-              size_t size) {
-  std::unique_ptr<char[]> heap(new char[size]);
-  memcpy(heap.get(), data, size);
-  parser->OnStreamData(std::move(heap), size);
-}
-
-void SendHeader(scoped_refptr<StreamParser>& parser) {
-  StreamHeader header;
-  SendData(parser, &header, sizeof(StreamHeader));
-}
-
-class TestReceiver : public Receiver {
- public:
-  TestReceiver() {
-    // Make our saved header invalid so we can't confuse the locally
-    // initialized one with a valid one that's received.
-    header_.signature = 0;
-    last_barrier_.barrier_id =
-        std::numeric_limits<decltype(last_barrier_.barrier_id)>::max();
-  }
-
-  bool got_header() const { return got_header_; }
-  const StreamHeader& header() const { return header_; }
-  void OnHeader(const StreamHeader& header) override {
-    ASSERT_FALSE(got_header_);  // Don't expect more than one.
-    got_header_ = true;
-    header_ = header;
-  }
-
-  int alloc_count() const { return alloc_count_; }
-  const AllocPacket& last_alloc() const { return last_alloc_; }
-  const std::vector<Address>& last_alloc_stack() const {
-    return last_alloc_stack_;
-  }
-  const std::string& last_alloc_context() const { return last_alloc_context_; }
-  void OnAlloc(const AllocPacket& alloc_packet,
-               std::vector<Address>&& stack,
-               std::string&& context) override {
-    alloc_count_++;
-    last_alloc_ = alloc_packet;
-    last_alloc_stack_ = std::move(stack);
-    last_alloc_context_ = std::move(context);
-  }
-
-  int free_count() const { return free_count_; }
-  const FreePacket& last_free() const { return last_free_; }
-  void OnFree(const FreePacket& free_packet) override {
-    free_count_++;
-    last_free_ = free_packet;
-  }
-
-  int barrier_count() const { return barrier_count_; }
-  const BarrierPacket& last_barrier() const { return last_barrier_; }
-  void OnBarrier(const BarrierPacket& barrier) override {
-    barrier_count_++;
-    last_barrier_.barrier_id = barrier.barrier_id;
-  }
-
-  int string_mapping_count() const { return string_mapping_count_; }
-  const StringMappingPacket& last_string_mapping() const {
-    return last_string_mapping_;
-  }
-  const char* last_raw_string() const { return last_raw_string_.c_str(); }
-
-  void OnStringMapping(const StringMappingPacket& string_mapping,
-                       const std::string& str) override {
-    string_mapping_count_++;
-    memcpy(&last_string_mapping_, &string_mapping, sizeof(StringMappingPacket));
-    last_raw_string_ = str;
-  }
-
-  bool got_complete() const { return got_complete_; }
-  void OnComplete() override {
-    ASSERT_FALSE(got_complete_);  // Don't expect more than one.
-    got_complete_ = true;
-  }
-
- private:
-  bool got_header_ = false;
-  StreamHeader header_;
-
-  int alloc_count_ = 0;
-  AllocPacket last_alloc_;
-  std::vector<Address> last_alloc_stack_;
-  std::string last_alloc_context_;
-
-  int free_count_ = 0;
-  FreePacket last_free_;
-
-  int barrier_count_ = 0;
-  BarrierPacket last_barrier_;
-
-  int string_mapping_count_ = 0;
-  StringMappingPacket last_string_mapping_;
-  std::string last_raw_string_;
-
-  bool got_complete_ = false;
-};
-
-}  // namespace
-
-TEST(StreamParser, NormalHeader) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-
-  // Should work to send in two packets.
-  StreamHeader header;
-  size_t first_size = sizeof(StreamHeader) / 2;
-  SendData(parser, &header, first_size);
-  EXPECT_FALSE(receiver.got_header());
-  SendData(parser, &reinterpret_cast<char*>(&header)[first_size],
-           sizeof(StreamHeader) - first_size);
-  EXPECT_TRUE(receiver.got_header());
-  EXPECT_FALSE(receiver.got_complete());
-
-  parser->OnStreamComplete();
-  EXPECT_TRUE(receiver.got_complete());
-}
-
-TEST(StreamParser, BadHeader) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-
-  StreamHeader header;
-  header.signature = 15;
-  SendData(parser, &header, sizeof(StreamHeader));
-  EXPECT_FALSE(receiver.got_header());
-  EXPECT_TRUE(receiver.got_complete());
-  EXPECT_TRUE(parser->has_error());
-}
-
-TEST(StreamParser, GoodAlloc) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-  SendHeader(parser);
-
-  constexpr size_t kStackSize = 4;
-  uint64_t stack[kStackSize] = {0x1, 0x2, 0x3, 0x4};
-
-  std::string context("hello");
-
-  AllocPacket alloc;
-  alloc.allocator = AllocatorType::kMalloc;
-  alloc.address = 0x87654321;
-  alloc.size = 128;
-  alloc.stack_len = kStackSize;
-  alloc.context_byte_len = static_cast<uint32_t>(context.size());
-
-  SendData(parser, &alloc, sizeof(AllocPacket));
-  EXPECT_EQ(0, receiver.alloc_count());
-  SendData(parser, stack, sizeof(uint64_t) * kStackSize);
-  ASSERT_EQ(0, receiver.alloc_count());
-  SendData(parser, context.data(), context.size());
-  ASSERT_EQ(1, receiver.alloc_count());
-
-  EXPECT_EQ(alloc.allocator, receiver.last_alloc().allocator);
-  EXPECT_EQ(alloc.address, receiver.last_alloc().address);
-  EXPECT_EQ(alloc.size, receiver.last_alloc().size);
-  EXPECT_EQ(alloc.stack_len, receiver.last_alloc().stack_len);
-  EXPECT_EQ(context, receiver.last_alloc_context());
-
-  ASSERT_EQ(4u, receiver.last_alloc_stack().size());
-  EXPECT_EQ(stack[0], receiver.last_alloc_stack()[0].value);
-  EXPECT_EQ(stack[1], receiver.last_alloc_stack()[1].value);
-  EXPECT_EQ(stack[2], receiver.last_alloc_stack()[2].value);
-  EXPECT_EQ(stack[3], receiver.last_alloc_stack()[3].value);
-}
-
-TEST(StreamParser, AllocBigStack) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-  SendHeader(parser);
-
-  AllocPacket alloc;
-  alloc.allocator = AllocatorType::kMalloc;
-  alloc.address = 0x87654321;
-  alloc.size = 128;
-  alloc.stack_len = 10000;  // Too large a stack.
-  alloc.context_byte_len = 0;
-
-  SendData(parser, &alloc, sizeof(AllocPacket));
-
-  // Even though no stack was sent, the alloc header with the too-large stack
-  // should have triggered an error.
-  EXPECT_EQ(0, receiver.alloc_count());
-  EXPECT_TRUE(receiver.got_complete());
-}
-
-TEST(StreamParser, AllocBigContext) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-  SendHeader(parser);
-
-  AllocPacket alloc;
-  alloc.allocator = AllocatorType::kMalloc;
-  alloc.address = 0x87654321;
-  alloc.size = 128;
-  alloc.stack_len = 0;  // Too large a stack.
-  alloc.context_byte_len = 10000;
-
-  SendData(parser, &alloc, sizeof(AllocPacket));
-
-  // Even though no stack or context was sent, the alloc header with the
-  // too-large stack should have triggered an error.
-  EXPECT_EQ(0, receiver.alloc_count());
-  EXPECT_TRUE(receiver.got_complete());
-}
-
-TEST(StreamParser, GoodFree) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-  SendHeader(parser);
-
-  FreePacket fr;
-  fr.address = 0x87654321;
-
-  SendData(parser, &fr, sizeof(FreePacket));
-  EXPECT_EQ(1, receiver.free_count());
-
-  EXPECT_EQ(fr.address, receiver.last_free().address);
-}
-
-TEST(StreamParser, Barrier) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-  SendHeader(parser);
-
-  constexpr uint32_t barrier_id = 0x12345678;
-
-  BarrierPacket b;
-  b.barrier_id = barrier_id;
-
-  SendData(parser, &b, sizeof(BarrierPacket));
-  EXPECT_EQ(1, receiver.barrier_count());
-
-  EXPECT_EQ(barrier_id, receiver.last_barrier().barrier_id);
-}
-
-TEST(StreamParser, StringMapping) {
-  TestReceiver receiver;
-  scoped_refptr<StreamParser> parser(new StreamParser(&receiver));
-  SendHeader(parser);
-
-  const std::string kDummyText = "kDummyText";
-
-  StringMappingPacket p;
-  p.address = 0x1234;
-  p.string_len = static_cast<uint32_t>(kDummyText.size());
-  SendData(parser, &p, sizeof(StringMappingPacket));
-  SendData(parser, kDummyText.data(), kDummyText.size());
-
-  EXPECT_EQ(1, receiver.string_mapping_count());
-  EXPECT_EQ(p.address, receiver.last_string_mapping().address);
-  EXPECT_EQ(p.string_len, receiver.last_string_mapping().string_len);
-  EXPECT_EQ(kDummyText, receiver.last_raw_string());
-}
-
-}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/stream_receiver.h b/components/services/heap_profiling/stream_receiver.h
deleted file mode 100644
index 4c511eb..0000000
--- a/components/services/heap_profiling/stream_receiver.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_STREAM_RECEIVER_H_
-#define COMPONENTS_SERVICES_HEAP_PROFILING_STREAM_RECEIVER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-
-namespace heap_profiling {
-
-// A stream receiver is a sink for unparsed bytes. See also LogReceiver.
-class StreamReceiver : public base::RefCountedThreadSafe<StreamReceiver> {
- public:
-  StreamReceiver() {}
-
-  // Returns true on success, false on unrecoverable error. The implementation
-  // should be able to handle calls after an error has been reported (some
-  // cross-thread calls may have been dispatched before the flag propagates).
-  virtual bool OnStreamData(std::unique_ptr<char[]> data, size_t sz) = 0;
-
-  // Indicates the connection has been closed.
-  virtual void OnStreamComplete() = 0;
-
- protected:
-  friend class base::RefCountedThreadSafe<StreamReceiver>;
-  virtual ~StreamReceiver() {}
-};
-
-}  // namespace heap_profiling
-
-#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_STREAM_RECEIVER_H_
diff --git a/components/test/data/autofill/heuristics/input/017_checkout_advanceautoparts.com.html b/components/test/data/autofill/heuristics/input/017_checkout_advanceautoparts.com.html
index cf51d6b4..627dffc 100644
--- a/components/test/data/autofill/heuristics/input/017_checkout_advanceautoparts.com.html
+++ b/components/test/data/autofill/heuristics/input/017_checkout_advanceautoparts.com.html
@@ -11,16 +11,16 @@
 
 
 
-	
+
 <!-- Start LivePersonTagConfig.jspf -->
 
-<!-- End LivePersonTagConfig.jspf --> 
+<!-- End LivePersonTagConfig.jspf -->
 </head>
 <body>
 
 
 
-<h3>Returning Customer</h3>	
+<h3>Returning Customer</h3>
 <form name="logonForm" method="post" action="/webapp/wcs/stores/servlet/BillShipLogon">
 <input type="hidden" name="action" value="login">
 <input type="hidden" name="storeId" value="10151">
@@ -33,12 +33,12 @@
 <tr>
 <th><label>Email Address:</label></th>
 <td colspan="2">
-  <input type="text" name="logonId" id="logonId" size="30" value="" tabindex="1" autocomplete="off" /></td>
+  <input type="text" name="logonId" id="logonId" size="30" value="" tabindex="1" /></td>
 </tr>
 <tr>
 <th><label>Password:</label></th>
 <td>
-  <input type="password" name="logonPassword" id="logonPassword" size="20" tabindex="2" autocomplete="off" /></td>
+  <input type="password" name="logonPassword" id="logonPassword" size="20" tabindex="2" /></td>
 <td><a href="https://shop.advanceautoparts.com/webapp/wcs/stores/servlet/ForgotPasswordView?storeId=10151&catalogId=10051&langId=-1&userType=G&userState=&userId=69626587" class="small-red" tabindex="3">I forgot my password</a></td>
 </tr>
 <tr>
@@ -74,9 +74,9 @@
 <input type="hidden" name="shipDayPhone" value="">
 <input type="hidden" name="shipNightPhone" value="">
 <input type="hidden" name="shippingMode" value="40501">
-<!-- Guest user and page loaded for the first time.	-->	
+<!-- Guest user and page loaded for the first time.	-->
 <input type="hidden" name="billAddressId" value="">
-<input type="hidden" name="shipAddressId" value="">	
+<input type="hidden" name="shipAddressId" value="">
 <table cellpadding="0" cellspacing="0" width="100%" style="padding:0 20px;">
 <tr>
 <td valign="top" width="49%" id="bill-form">
@@ -87,9 +87,9 @@
 Make shipping the same as my billing address
 </p>
 <h4>Use form below for your billing address:</h4>
-<table cellpadding="2" cellspacing="0">	
+<table cellpadding="2" cellspacing="0">
 <tr>
-<th class="required-text">* required fields</th>	
+<th class="required-text">* required fields</th>
 </tr>
 <tr>
 <th><span class="required-text">*</span>First Name:</th>
@@ -118,7 +118,7 @@
 </tr>
 <tr>
 <th></th>
-<td>(Military Customers, enter APO/FPO/DPO for city)</td>	
+<td>(Military Customers, enter APO/FPO/DPO for city)</td>
 </tr>
 <input type="hidden" name="billCountry" value="US">
 <tr>
@@ -238,7 +238,7 @@
 <h4>Add a new shipping address:</h4>
 <table>
 <tr>
-<th class="required-text">* required fields</th>	
+<th class="required-text">* required fields</th>
 </tr>
 <tr>
 <th>*First Name:</th>
@@ -342,12 +342,12 @@
 <tr>
 <th>*Day Phone:</th>
 <td>(<input type="text" name="shipDayPhonePart1" maxlength="3" size="3" tabindex="124" value="" title="shipDayPhonePart1">)<input type="text" name="shipDayPhonePart2" maxlength="3" size="3" tabindex="125" value="" title="shipDayPhonePart2">
-  <input type="text" name="shipDayPhonePart3" maxlength="4" size="4" tabindex="126" value="" title="shipDayPhonePart3"></td>	
+  <input type="text" name="shipDayPhonePart3" maxlength="4" size="4" tabindex="126" value="" title="shipDayPhonePart3"></td>
 </tr>
 <tr>
 <th>Night Phone:</th>
 <td>(<input type="text" name="shipNightPhonePart1" maxlength="3" size="3" tabindex="127" value="" title="shipNightPhonePart1">)<input type="text" name="shipNightPhonePart2" maxlength="3" size="3" tabindex="128" value="" title="shipNightPhonePart2">
-  <input type="text" name="shipNightPhonePart3" maxlength="4" size="4" tabindex="129" value="" title="shipNightPhonePart3"></td>	
+  <input type="text" name="shipNightPhonePart3" maxlength="4" size="4" tabindex="129" value="" title="shipNightPhonePart3"></td>
 </tr>
 </table>
 </div>
@@ -356,7 +356,7 @@
 When the shipping address is different from the billing address, your order may be subject to further verification delays. For questions regarding billing and shipping address please
 <a href="https://shop.advanceautoparts.com/webapp/wcs/stores/servlet/content_contactus___" target="_blank" tabindex="126">
 contact us
-</a>.	
+</a>.
 </p>
 </td>
 </tr>
@@ -370,10 +370,10 @@
 <td>&nbsp;</td>
 <td valign="top">
 <br/>
-<input type="image" src="#" property="submitButton" tabindex="150" value="Continue to Step 2 >>" class="button" id="shipBill"/> 
+<input type="image" src="#" property="submitButton" tabindex="150" value="Continue to Step 2 >>" class="button" id="shipBill"/>
 </td>
 </tr>
-</table>	
+</table>
 </form>
 
 
diff --git a/components/test/data/autofill/heuristics/input/018_checkout_ae.com.html b/components/test/data/autofill/heuristics/input/018_checkout_ae.com.html
index be606f5..9f02204 100644
--- a/components/test/data/autofill/heuristics/input/018_checkout_ae.com.html
+++ b/components/test/data/autofill/heuristics/input/018_checkout_ae.com.html
@@ -27,7 +27,7 @@
 <label for="tl_myAccount_username" class="sm_label">Secure account sign in</label>
 <input value="Email Address" maxlength="60" type="text" class="in_field js_defaultAsLabel" name="logonUsername" id="tl_myAccount_username">
 <input value=" " type="hidden" name="_D:logonUsername">
-<input value="password" autocomplete="off" maxlength="15" type="password" class="in_field js_defaultAsLabel" name="logonPassword" id="tl_myAccount_password">
+<input value="password" maxlength="15" type="password" class="in_field js_defaultAsLabel" name="logonPassword" id="tl_myAccount_password">
 <input value=" " type="hidden" name="_D:logonPassword">
 <a href="https://www.ae.com/web/myaccount/password_assistance.jsp" id="tl_myAccount_forgot">Forgot Password?</a>
 <input value="Sign In" type="submit" class="sm_bttn" name="/atg/userprofiling/ProfileFormHandler.login" id="tl_myAccount_submit">
@@ -39,8 +39,8 @@
 
 
 
-    
-    
+
+
 <form action="http://www.ae.com/web/storelocator/storeResult.jsp?_DARGS=/web/global/nav/f_nav_findstore.jsp.storelocatorFid" name="storelocator" method="post" id="storelocator">
 <input value="UTF-8" type="hidden" name="_dyncharset">
 </input>
@@ -64,8 +64,8 @@
 
 
 
-    
-    
+
+
 <form action="https://www.ae.com/web/wishlist/nav/f_wishlist_access.jsp?_DARGS=/web/global/nav/f_nav_wishlist.jsp.form_wlloginFid" name="TNwishlistloginform" method="post" id="form_wllogin">
 <input value="UTF-8" type="hidden" name="_dyncharset">
 </input>
@@ -80,7 +80,7 @@
 <label for="tl_wishlist_email" class="sm_label">Access your wish list</label>
 <input value="Email" maxlength="60" type="text" class="in_field js_defaultAsLabel" name="username" id="tl_wishlist_email">
 <input value=" " type="hidden" name="_D:username">
-<input value="Password" autocomplete="off" type="password" class="in_field js_defaultAsLabel" name="password" id="tl_wishlist_password">
+<input value="Password" type="password" class="in_field js_defaultAsLabel" name="password" id="tl_wishlist_password">
 <input value=" " type="hidden" name="_D:password">
 <a href="https://www.ae.com/web/myaccount/password_assistance.jsp" id="tl_wishlist_forgot">Forgot Password?</a>
 <input value="Sign In" type="submit" class="sm_bttn" name="/atg/userprofiling/ProfileFormHandler.login" id="tl_wishlist_submit">
@@ -90,7 +90,7 @@
 </form>
 
 
-  
+
 <form action="http://www.ae.com/web/wishlist/search_wishlist.jsp?_DARGS=/web/global/nav/f_nav_wishlist.jsp.form_glsearchFid" name="TNwishlistsearchform" method="post" id="form_glsearch">
 <input value="UTF-8" type="hidden" name="_dyncharset">
 </input>
@@ -497,13 +497,13 @@
 </span>
 </label>
 <div class="checkoutInputLeft">
-<input type="text" name="giftNumEntry" id="giftNumEntry" class="checkoutInput giftNumEntryField" value="" maxlength="19" autocomplete="off" />
+<input type="text" name="giftNumEntry" id="giftNumEntry" class="checkoutInput giftNumEntryField" value="" maxlength="19" />
 </div>
 </div>
 <div class="inputLabelHolder">
 <label for="pinNumEntry">PIN:</label>
 <div class="checkoutInputLeft">
-<input type="text" autocomplete="off" name="pinNumEntry" id="pinNumEntry" class="checkoutInput pinNumEntryField" value="" maxlength="4" autocomplete="off" />
+<input type="text" name="pinNumEntry" id="pinNumEntry" class="checkoutInput pinNumEntryField" value="" maxlength="4" />
 </div>
 </div>
 <input value="Add Card" width="79" type="image" class="addGCbtn" src="#" name="/aeo/commerce/order/checkout/AeoGiftCardPaymentHandler.applyGiftCard" id="applyGiftCardBtn">
@@ -586,7 +586,7 @@
 <div id="ccNumberHolderCCField" class="inputLabelHolder">
 <label for="ccNumberCCField">Card Number:</label>
 <div class="checkoutInputLeft">
-<input type="text" name="ccNumber" id="ccNumberCCField" size="30" maxlength="16" value="" class="checkoutInput" autocomplete="off"/>
+<input type="text" name="ccNumber" id="ccNumberCCField" size="30" maxlength="16" value="" class="checkoutInput"/>
 </div>
 </div>
 <div id="expDateCCField" class="inputLabelHolder">
@@ -648,7 +648,7 @@
 </span>
 </label>
 <div class="checkoutInputLeft">
-<input type="text" name="ccSecCode" id="ccSecCodeCCField" size="4" maxlength="4" value="" class="checkoutInput" autocomplete="off"/>
+<input type="text" name="ccSecCode" id="ccSecCodeCCField" size="4" maxlength="4" value="" class="checkoutInput"/>
 </div>
 </div>
 </div>
@@ -838,7 +838,7 @@
 </span>
 </label>
 <div class="checkoutInputLeft">
-<input type="text" name="SSN" size="4" maxlength="4" value="" id="SSNBMLField" class="checkoutInput" autocomplete="off" />
+<input type="text" name="SSN" size="4" maxlength="4" value="" id="SSNBMLField" class="checkoutInput" />
 </div>
 </div>
 <div style="clear:both;">
@@ -1790,7 +1790,7 @@
 </span>
 </label>
 <div style="float: left;" class="checkoutInputLeft">
-<input value="" autocomplete="off" maxlength="25" type="text" class="checkoutInput" size="25" name="CouponCode" id="discountCodeField">
+<input value="" maxlength="25" type="text" class="checkoutInput" size="25" name="CouponCode" id="discountCodeField">
 <input value=" " type="hidden" name="_D:CouponCode">
 </div>
 <div style="float: left;">
diff --git a/components/test/data/autofill/heuristics/input/023_checkout_gamestop.com.html b/components/test/data/autofill/heuristics/input/023_checkout_gamestop.com.html
index fc007af7..e6816c0 100644
--- a/components/test/data/autofill/heuristics/input/023_checkout_gamestop.com.html
+++ b/components/test/data/autofill/heuristics/input/023_checkout_gamestop.com.html
@@ -21,13 +21,13 @@
 </head>
 
 <body >
-    
-    
-    
-    
+
+
+
+
 
     <div class="baseContent">
-        <form name="aspnetForm" method="post" action="/Orders/OrderShippingAddress.aspx?ct=guest" language="javascript" autocomplete="off" id="aspnetForm">
+        <form name="aspnetForm" method="post" action="/Orders/OrderShippingAddress.aspx?ct=guest" language="javascript" id="aspnetForm">
 <div>
 <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
 <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
@@ -65,10 +65,10 @@
 
 
 
-            
 
-            
-            
+
+
+
     <div class="wrap">
 	    <div class="site container_24">
 <div id="mainHeader" class="header" style="background: #FFFFFF url(/common/css/gamestopdotcom/images/gslogo.png) no-repeat 13px 19px;">
@@ -77,13 +77,13 @@
      	<div class="toplinks"><a id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lnkStoreLocator" href="/StoreLocator.aspx">Find a Store</a>|<a id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lnkStoreEvents" href="/gs/gamestopevents">Events</a>|<a id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lnkWeeklyAd" href="/weeklyad">Weekly Ad</a>|<a id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lnkGiftCards" href="/Catalog/Gifts.aspx">Gift Cards</a>|<a id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lnkOrderHistory" href="/Profiles/OrderTrackingLogin.aspx">Order History</a>|<a id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lnkWishList" href="/Profiles/WishList.aspx">Wish List</a>
      	</div>
 	    <div class="accessbox" id="header_auth_state">
-	    	<span id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lblGreeting">Welcome, Guest!</span> 
-	        
+	    	<span id="ctl00_ctl00_ctl00_BaseContentPlaceHolder_cHeader_lblGreeting">Welcome, Guest!</span>
+
                     <a href='/Profiles/Login.aspx?ReturnUrl=/Orders/OrderShippingAddress.aspx?ct=guest' id='header_auth_actions' rel='nofollow'>Log In / Register</a>
-	                       
+
 	    </div>
 		<div class="primenav">
-			 
+
 			        <a href='/xbox360' id='xbox360_link' class="navLink">Xbox 360</a>
                     <div id='xbox360_mega' class="mega_menu">
 		                <div class="mega_menu_col menu_col_hot" Style="display:inline">
@@ -95,163 +95,163 @@
 		                <div class="mega_menu_col menu_col_genres" Style="display:inline">
 			                <h3>Xbox 360 Games</h3>
 			                <ul id="menu_xbox_genres" class="menu_genres">
-                                
+
                                         <li>
                                             <a href='/browse/xbox-360?nav=1385'>
                                             All
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/3d?nav=1385-1a3'>
                                             3D
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/action?nav=1385-56'>
                                             Action
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/add-ons?nav=1385-18a'>
                                             Add-ons
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/casual?nav=1385-d4'>
                                             Casual
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/fighting?nav=1385-69'>
                                             Fighting
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/kinect?nav=1385-19d'>
                                             Kinect
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/movies-tv?nav=1385-c6'>
                                             Movies & TV
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/music-party?nav=1385-be'>
                                             Music & Party
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/puzzle-cards?nav=1385-63'>
                                             Puzzle & Cards
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/role-playing?nav=1385-6a'>
                                             Role-Playing
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/shooter?nav=1385-65'>
                                             Shooter
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/simulation?nav=1385-67'>
                                             Simulation
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/sports?nav=1385-66'>
                                             Sports
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/strategy?nav=1385-68'>
                                             Strategy
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/xbox-360/strategy-guides?nav=1385-c8'>
                                             Strategy Guides
                                             </a>
                                         </li>
-                                    
+
 			                </ul>
 		                </div>
 			            <div class="mega_menu_col menu_col_deals" Style="display:inline">
 				            <div Style="display:inline">
 				                <h3>Xbox 360 Deals</h3>
 				                <ul id="menu_xbox_deals" class="menu_deals">
-				                    
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-162'>
                                                 Price Drop
                                                 </a>
                                             </li>
-                                        
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-d3'>
                                                 Under $20
                                                 </a>
                                             </li>
-                                        
+
 				                </ul>
 				            </div>
 				            <div Style="display:inline">
 				                <h3>Shop by ESRB</h3>
 				                <ul id="menu_xbox_esrb" class="menu_esrb">
-				                    
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-33'
                                                 class='mm_everyone'>
                                                 Everyone
                                                 </a>
                                             </li>
-					                
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-38'
                                                 class='mm_everyone_plus'>
                                                 Everyone 10+
                                                 </a>
                                             </li>
-					                
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-34'
                                                 class='mm_teen'>
                                                 Teen
                                                 </a>
                                             </li>
-					                
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-35'
                                                 class='mm_mature'>
                                                 Mature
                                                 </a>
                                             </li>
-					                
+
                                             <li>
                                                 <a href='/browse/xbox-360?nav=1385-36'
                                                 class='mm_rating_pending'>
                                                 Rating Pending
                                                 </a>
                                             </li>
-					                
+
 				                </ul>
 				            </div>
 			            </div>
@@ -259,79 +259,79 @@
 				            <div Style="display:inline">
 				                <h3>Xbox 360 Hardware</h3>
 				                <ul id="menu_xbox_hardware" class="menu_hardware_and_accessories">
-				                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/systems?nav=1385-c4'>
                                                 Game Systems
                                                 </a>
                                             </li>
-					                    
+
 				                </ul>
 				            </div>
 				            <div Style="display:inline">
 				                <h3>Xbox 360 Accessories</h3>
 				                <ul id="menu_xbox_accessories" class="menu_hardware_and_accessories">
-				                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/batteries-chargers?nav=1385-a5'>
                                                 Batteries & Chargers
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/cables-adaptors?nav=1385-73'>
                                                 Cables & Adaptors
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/controllers?nav=1385-74'>
                                                 Controllers
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/cooling-systems?nav=1385-a2'>
                                                 Cooling Systems
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/systems?nav=1385-c4'>
                                                 Game Systems
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/headsets-mics?nav=1385-7b'>
                                                 Headsets & Mics
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/memory-cards?nav=1385-75'>
                                                 Memory Cards
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/repair-cleaning?nav=1385-a6'>
                                                 Repair & Cleaning
                                                 </a>
                                             </li>
-					                    
+
                                             <li>
                                                 <a href='/browse/xbox-360/accessories/storage-cases?nav=1385-77'>
                                                 Storage & Cases
                                                 </a>
                                             </li>
-					                    
+
 				                </ul>
 				            </div>
 				            <a href='/browse/xbox-360?nav=1385' class="menu_see_all">See All Xbox 360 &rarr;</a>
 			            </div>
 		            </div>
-			    
+
 			        <a href='/ps3' id='ps3_link' class="navLink">PS3</a>
                     <div id='ps3_mega' class="mega_menu">
 		                <div class="mega_menu_col menu_col_hot" Style="display:inline">
@@ -343,163 +343,163 @@
 		                <div class="mega_menu_col menu_col_genres" Style="display:inline">
 			                <h3>PlayStation 3 Games</h3>
 			                <ul id="menu_xbox_genres" class="menu_genres">
-                                
+
                                         <li>
                                             <a href='/browse/playstation-3?nav=138d'>
                                             All
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/playstation-3/3d?nav=138d-1a3'>
                                             3D
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/playstation-3/action?nav=138d-56'>
                                             Action
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/playstation-3/add-ons?nav=138d-18a'>
                                             Add-ons
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/playstation-3/casual?nav=138d-d4'>
                                             Casual
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/playstation-3/fighting?nav=138d-69'>
                                             Fighting
                                             </a>
                                         </li>
-                                    
+
                                         <li>
                                             <a href='/browse/playstation-3/move?nav=138d-19e'>
                                             Move
                                             </a>