diff --git a/BUILD.gn b/BUILD.gn
index 6e48a19..edeb047 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1184,10 +1184,7 @@
       ]
     }
     if (enable_ipc_fuzzer && !is_component_build) {
-      deps += [
-        "//chrome/app:service_manifests",
-        "//tools/ipc_fuzzer:ipc_fuzzer_all",
-      ]
+      deps += [ "//tools/ipc_fuzzer:ipc_fuzzer_all" ]
     }
     if (!is_chromeos) {
       deps += [
diff --git a/DEPS b/DEPS
index 8d30236..455c8e7b 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,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': '2a0967383087e8753246e0cfc95f90bc8eed0059',
+  'skia_revision': 'f16825ed3c715131489ed574ddd40533e7f0277f',
   # 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': 'cdef3415a2805f926e6da2d5da25da678867c821',
+  'v8_revision': 'f6f84c97a6497408eedc6e4fa6877c9239d5c473',
   # 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.
@@ -133,7 +133,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': '52f5da43184e62123d9327e2b4ebf4cc67a6a96f',
+  'angle_revision': '8441286093152097eda821869d2743a85759ff7b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -145,7 +145,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '25bc9a92b33868ebc8ca333935da8af837e1266d',
+  'pdfium_revision': '92770e8072cd3a38597966116045147c78b5a359',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -181,7 +181,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '442e7b2731071e114fd7382afdcd6d5dc1248795',
+  'catapult_revision': '7c1d51b169edfb62a3e2f88730f1182240cfe981',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -245,7 +245,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.
-  'dawn_revision': '300eec0f82c3c086e2c472d157594dff8fa81feb',
+  'dawn_revision': 'cb71ba7b3a42849b5e15794426cb9fe55cba8b13',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -679,7 +679,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '89e50af847ea000405fae5955f4f8399af20d784',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2c70338572204ba8c265f015b3097d1e60a699c1',
       'condition': 'checkout_linux',
   },
 
@@ -826,7 +826,7 @@
   },
 
   'src/third_party/arcore-android-sdk/src': {
-      'url': Var('chromium_git') + '/external/github.com/google-ar/arcore-android-sdk.git' + '@' + '25b4589b55c02344cee5fd5722b06202c8b8776d',
+      'url': Var('chromium_git') + '/external/github.com/google-ar/arcore-android-sdk.git' + '@' + '772bed8e2e1bc525a0d10441fa71168a9a87eb69',
       'condition': 'checkout_android',
   },
 
@@ -1199,7 +1199,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a2b35635aaef3e9301d69f77f9a0a3fd99291b08',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'd375f1c8d19f64cdeb64dd38d94316586efa4cac',
+    Var('webrtc_git') + '/src.git' + '@' + '35a9c6df44461580966b6f6d725db493ff764bce',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1230,7 +1230,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@896defe03d0b160467ff8392ee2ab4fef27abd6d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ff16c5b02fa501739c85ae01e5b8a931b08def76',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index c848ea3..84c47e0 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -31,7 +31,10 @@
 
     shared_resources = true
 
-    if (!defined(use_trichrome_library) || !use_trichrome_library) {
+    _use_trichrome_library =
+        defined(use_trichrome_library) && use_trichrome_library
+
+    if (!_use_trichrome_library) {
       shared_libraries = [ "//android_webview:libwebviewchromium" ]
       if (build_apk_secondary_abi && android_64bit_target_cpu) {
         secondary_abi_shared_libraries = [ "//android_webview:libwebviewchromium($android_secondary_abi_toolchain)" ]
@@ -64,8 +67,7 @@
       }
     }
 
-    if (!defined(use_trichrome_library) || !use_trichrome_library ||
-        android_64bit_target_cpu) {
+    if (!_use_trichrome_library || android_64bit_target_cpu) {
       # 32-bit TrichromeWebView doesn't have a native library, so only do this
       # for other configs.
       native_lib_version_rule = "//build/util:chrome_version_json"
@@ -74,9 +76,6 @@
       native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
     }
 
-    if (!defined(version_name)) {
-      version_name = chrome_version_name
-    }
     aapt_locale_whitelist = locales
 
     resource_blacklist_regex = "[/-]xxxhdpi[/-]"
@@ -112,5 +111,16 @@
       png_to_webp = true
     }
     command_line_flags_file = "webview-command-line"
+
+    if (!defined(version_code)) {
+      if (_use_trichrome_library) {
+        version_code = trichrome_version_code
+      } else {
+        version_code = webview_version_code
+      }
+    }
+    if (!defined(version_name)) {
+      version_name = chrome_version_name
+    }
   }
 }
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py
index 14ef0d6d..c23187a6 100755
--- a/android_webview/tools/apk_merger.py
+++ b/android_webview/tools/apk_merger.py
@@ -121,7 +121,7 @@
   # TODO(crbug.com/839191): Remove this once we're plumbing the lib correctly.
   missing_file_set = set(
       f for f in missing_file_set if not os.path.basename(f) ==
-      'libarcore_sdk_c.so')
+      'libarcore_sdk_c_minimal.so')
 
   errors = []
   if unexpected_file_set:
@@ -189,7 +189,7 @@
 
   # TODO(crbug.com/839191): we should pass this in via script arguments.
   if not args.loadable_module_32:
-    args.loadable_module_32.append('libarcore_sdk_c.so')
+    args.loadable_module_32.append('libarcore_sdk_c_minimal.so')
 
   for f in args.loadable_module_32:
     expected_files[f] = not args.uncompress_shared_libraries
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 01a39a8..a877e3396 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1772,8 +1772,8 @@
       <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE" desc="Title for Assistant timer notification.">
         Time's up
       </message>
-      <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_CONTENT" desc="Content for Assistant timer notification.">
-        00:00s
+      <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_MESSAGE" desc="Message for Assistant timer notification. Example: -01:23s. [ICU Syntax]">
+        <ph name="SIGN">{0}<ex>-</ex></ph><ph name="MINUTES_REMAINING">{1,number,00}<ex>01</ex></ph>:<ph name="SECONDS_REMAINING">{2,number,00}<ex>02</ex></ph>s
       </message>
       <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON" desc="Label for button to add 1 minute to timer in Assistant timer notification.">
         Add 1 min
diff --git a/ash/assistant/assistant_alarm_timer_controller.cc b/ash/assistant/assistant_alarm_timer_controller.cc
index f014d18f..7f5cde3 100644
--- a/ash/assistant/assistant_alarm_timer_controller.cc
+++ b/ash/assistant/assistant_alarm_timer_controller.cc
@@ -8,6 +8,8 @@
 #include "ash/assistant/assistant_notification_controller.h"
 #include "ash/assistant/util/deep_link_util.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "base/i18n/message_formatter.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chromeos/services/assistant/public/features.h"
 #include "chromeos/services/assistant/public/mojom/assistant.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -22,8 +24,64 @@
 // Interval at which alarms/timers are ticked.
 constexpr base::TimeDelta kTickInterval = base::TimeDelta::FromSeconds(1);
 
+// Helpers ---------------------------------------------------------------------
+
+std::string CreateTimerNotificationMessage(const AlarmTimer& alarm_timer,
+                                           base::TimeDelta time_remaining) {
+  const int minutes_remaining = time_remaining.InMinutes();
+  const int seconds_remaining =
+      (time_remaining - base::TimeDelta::FromMinutes(minutes_remaining))
+          .InSeconds();
+  return base::UTF16ToUTF8(base::i18n::MessageFormatter::FormatWithNumberedArgs(
+      l10n_util::GetStringUTF16(IDS_ASSISTANT_TIMER_NOTIFICATION_MESSAGE),
+      alarm_timer.expired() ? "-" : "", minutes_remaining, seconds_remaining));
+}
+
+// TODO(llin): Migrate to use the AlarmManager API to better support multiple
+// timers when the API is available.
+chromeos::assistant::mojom::AssistantNotificationPtr CreateTimerNotification(
+    const AlarmTimer& alarm_timer,
+    base::TimeDelta time_remaining) {
+  using chromeos::assistant::mojom::AssistantNotification;
+  using chromeos::assistant::mojom::AssistantNotificationButton;
+  using chromeos::assistant::mojom::AssistantNotificationPtr;
+
+  const std::string title =
+      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE);
+  const std::string message =
+      CreateTimerNotificationMessage(alarm_timer, time_remaining);
+  const GURL action_url = assistant::util::CreateAssistantQueryDeepLink(
+      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_QUERY));
+
+  AssistantNotificationPtr notification = AssistantNotification::New();
+
+  notification->title = title;
+  notification->message = message;
+  notification->action_url = action_url;
+  notification->client_id = alarm_timer.id;
+  notification->grouping_key = kTimerNotificationGroupingKey;
+
+  // "STOP" button.
+  notification->buttons.push_back(AssistantNotificationButton::New(
+      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON),
+      action_url));
+
+  // "ADD 1 MIN" button.
+  notification->buttons.push_back(
+      chromeos::assistant::mojom::AssistantNotificationButton::New(
+          l10n_util::GetStringUTF8(
+              IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON),
+          assistant::util::CreateAssistantQueryDeepLink(
+              l10n_util::GetStringUTF8(
+                  IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_QUERY))));
+
+  return notification;
+}
+
 }  // namespace
 
+// AssistantAlarmTimerController -----------------------------------------------
+
 AssistantAlarmTimerController::AssistantAlarmTimerController(
     AssistantController* assistant_controller)
     : assistant_controller_(assistant_controller), binding_(this) {
@@ -70,55 +128,48 @@
     const AlarmTimer& alarm_timer,
     const base::TimeDelta& time_remaining) {
   // Schedule a repeating timer to tick the tracked alarms/timers.
-  if (!timer_.IsRunning()) {
+  if (chromeos::assistant::features::IsTimerTicksEnabled() &&
+      !timer_.IsRunning()) {
     timer_.Start(FROM_HERE, kTickInterval, &model_,
                  &AssistantAlarmTimerModel::Tick);
   }
 
-  const std::string title =
-      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE);
-  const std::string message =
-      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_CONTENT);
-  const GURL action_url = assistant::util::CreateAssistantQueryDeepLink(
-      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_QUERY));
-
-  chromeos::assistant::mojom::AssistantNotificationPtr notification =
-      chromeos::assistant::mojom::AssistantNotification::New();
-
-  notification->title = title;
-  notification->message = message;
-  notification->action_url = action_url;
-  notification->client_id = alarm_timer.id;
-  notification->grouping_key = kTimerNotificationGroupingKey;
-
-  // "STOP" button.
-  notification->buttons.push_back(
-      chromeos::assistant::mojom::AssistantNotificationButton::New(
-          l10n_util::GetStringUTF8(
-              IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON),
-          action_url));
-
-  // "ADD 1 MIN" button.
-  notification->buttons.push_back(
-      chromeos::assistant::mojom::AssistantNotificationButton::New(
-          l10n_util::GetStringUTF8(
-              IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON),
-          assistant::util::CreateAssistantQueryDeepLink(
-              l10n_util::GetStringUTF8(
-                  IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_QUERY))));
-
+  // Create a notification for the added alarm/timer.
   DCHECK(chromeos::assistant::features::IsTimerNotificationEnabled());
-  assistant_controller_->notification_controller()->AddNotification(
-      std::move(notification));
+  if (chromeos::assistant::features::IsTimerNotificationEnabled()) {
+    assistant_controller_->notification_controller()->AddOrUpdateNotification(
+        CreateTimerNotification(alarm_timer, time_remaining));
+  }
+}
+
+void AssistantAlarmTimerController::OnAlarmsTimersTicked(
+    const std::map<std::string, base::TimeDelta>& times_remaining) {
+  // This code should only be called when timer notifications/ticks are enabled.
+  DCHECK(chromeos::assistant::features::IsTimerNotificationEnabled());
+  DCHECK(chromeos::assistant::features::IsTimerTicksEnabled());
+
+  // Update any existing notifications associated w/ our alarms/timers.
+  for (auto& pair : times_remaining) {
+    auto* notification_controller =
+        assistant_controller_->notification_controller();
+    if (notification_controller->model()->HasNotificationForId(pair.first)) {
+      notification_controller->AddOrUpdateNotification(CreateTimerNotification(
+          *model_.GetAlarmTimerById(pair.first), pair.second));
+    }
+  }
 }
 
 void AssistantAlarmTimerController::OnAllAlarmsTimersRemoved() {
-  timer_.Stop();
+  if (chromeos::assistant::features::IsTimerTicksEnabled())
+    timer_.Stop();
 
+  // Remove any notifications associated w/ alarms/timers.
   DCHECK(chromeos::assistant::features::IsTimerNotificationEnabled());
-  assistant_controller_->notification_controller()
-      ->RemoveNotificationByGroupingKey(kTimerNotificationGroupingKey,
-                                        /*from_server=*/false);
+  if (chromeos::assistant::features::IsTimerNotificationEnabled()) {
+    assistant_controller_->notification_controller()
+        ->RemoveNotificationByGroupingKey(kTimerNotificationGroupingKey,
+                                          /*from_server=*/false);
+  }
 }
 
 }  // namespace ash
diff --git a/ash/assistant/assistant_alarm_timer_controller.h b/ash/assistant/assistant_alarm_timer_controller.h
index abe601c..ac3a1b7 100644
--- a/ash/assistant/assistant_alarm_timer_controller.h
+++ b/ash/assistant/assistant_alarm_timer_controller.h
@@ -42,6 +42,8 @@
   // AssistantAlarmTimerModelObserver:
   void OnAlarmTimerAdded(const AlarmTimer& alarm_timer,
                          const base::TimeDelta& time_remaining) override;
+  void OnAlarmsTimersTicked(
+      const std::map<std::string, base::TimeDelta>& times_remaining) override;
   void OnAllAlarmsTimersRemoved() override;
 
  private:
diff --git a/ash/assistant/assistant_notification_controller.cc b/ash/assistant/assistant_notification_controller.cc
index c8bca90..489e1e7 100644
--- a/ash/assistant/assistant_notification_controller.cc
+++ b/ash/assistant/assistant_notification_controller.cc
@@ -27,6 +27,32 @@
 
 // Helpers ---------------------------------------------------------------------
 
+std::unique_ptr<message_center::Notification> CreateSystemNotification(
+    const message_center::NotifierId& notifier_id,
+    const chromeos::assistant::mojom::AssistantNotification* notification) {
+  const base::string16 title = base::UTF8ToUTF16(notification->title);
+  const base::string16 message = base::UTF8ToUTF16(notification->message);
+  const base::string16 display_source =
+      l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_NOTIFICATION_DISPLAY_SOURCE);
+
+  message_center::RichNotificationData data;
+  for (const auto& button : notification->buttons) {
+    data.buttons.push_back(
+        message_center::ButtonInfo(base::UTF8ToUTF16(button->label)));
+  }
+
+  std::unique_ptr<message_center::Notification> system_notification =
+      ash::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, notification->client_id,
+          title, message, display_source, GURL(), notifier_id, data,
+          /*delegate=*/nullptr, kNotificationAssistantIcon,
+          message_center::SystemNotificationWarningLevel::NORMAL);
+
+  system_notification->set_priority(message_center::DEFAULT_PRIORITY);
+
+  return system_notification;
+}
+
 message_center::NotifierId GetNotifierId() {
   return message_center::NotifierId(
       message_center::NotifierType::SYSTEM_COMPONENT, kNotifierId);
@@ -77,9 +103,9 @@
 
 // mojom::AssistantNotificationController --------------------------------------
 
-void AssistantNotificationController::AddNotification(
+void AssistantNotificationController::AddOrUpdateNotification(
     AssistantNotificationPtr notification) {
-  model_.AddNotification(std::move(notification));
+  model_.AddOrUpdateNotification(std::move(notification));
 }
 
 void AssistantNotificationController::RemoveNotificationById(
@@ -102,35 +128,23 @@
 
 void AssistantNotificationController::OnNotificationAdded(
     const AssistantNotification* notification) {
-  DCHECK(assistant_);
-
-  // Do not show system notification if the setting is false.
+  // Do not show system notifications if the setting is disabled.
   if (!Shell::Get()->voice_interaction_controller()->notification_enabled())
     return;
 
-  // Create the specified system |notification|.
-  const base::string16 title = base::UTF8ToUTF16(notification->title);
-  const base::string16 message = base::UTF8ToUTF16(notification->message);
-  const base::string16 display_source =
-      l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_NOTIFICATION_DISPLAY_SOURCE);
-
-  message_center::RichNotificationData data;
-  for (const auto& button : notification->buttons) {
-    data.buttons.push_back(
-        message_center::ButtonInfo(base::UTF8ToUTF16(button->label)));
-  }
-
-  std::unique_ptr<message_center::Notification> system_notification =
-      ash::CreateSystemNotification(
-          message_center::NOTIFICATION_TYPE_SIMPLE, notification->client_id,
-          title, message, display_source, GURL(), notifier_id_, data,
-          /*delegate=*/nullptr, kNotificationAssistantIcon,
-          message_center::SystemNotificationWarningLevel::NORMAL);
-
-  system_notification->set_priority(message_center::DEFAULT_PRIORITY);
-
   message_center::MessageCenter::Get()->AddNotification(
-      std::move(system_notification));
+      CreateSystemNotification(notifier_id_, notification));
+}
+
+void AssistantNotificationController::OnNotificationUpdated(
+    const AssistantNotification* notification) {
+  // Do not show system notifications if the setting is disabled.
+  if (!Shell::Get()->voice_interaction_controller()->notification_enabled())
+    return;
+
+  message_center::MessageCenter::Get()->UpdateNotification(
+      notification->client_id,
+      CreateSystemNotification(notifier_id_, notification));
 }
 
 void AssistantNotificationController::OnNotificationRemoved(
diff --git a/ash/assistant/assistant_notification_controller.h b/ash/assistant/assistant_notification_controller.h
index dad592ff..69cf45a7 100644
--- a/ash/assistant/assistant_notification_controller.h
+++ b/ash/assistant/assistant_notification_controller.h
@@ -49,7 +49,7 @@
   void SetAssistant(chromeos::assistant::mojom::Assistant* assistant);
 
   // mojom::AssistantNotificationController:
-  void AddNotification(AssistantNotificationPtr notification) override;
+  void AddOrUpdateNotification(AssistantNotificationPtr notification) override;
   void RemoveNotificationById(const std::string& id, bool from_server) override;
   void RemoveNotificationByGroupingKey(const std::string& grouping_id,
                                        bool from_server) override;
@@ -57,6 +57,8 @@
 
   // AssistantNotificationModelObserver:
   void OnNotificationAdded(const AssistantNotification* notification) override;
+  void OnNotificationUpdated(
+      const AssistantNotification* notification) override;
   void OnNotificationRemoved(const AssistantNotification* notification,
                              bool from_server) override;
   void OnAllNotificationsRemoved(bool from_server) override;
@@ -67,6 +69,7 @@
       const std::string& id,
       const base::Optional<int>& button_index,
       const base::Optional<base::string16>& reply) override;
+  void OnNotificationUpdated(const std::string& notification) override {}
   void OnNotificationRemoved(const std::string& notification_id,
                              bool by_user) override;
 
diff --git a/ash/assistant/model/assistant_alarm_timer_model.cc b/ash/assistant/model/assistant_alarm_timer_model.cc
index bfa6403..00efbd92 100644
--- a/ash/assistant/model/assistant_alarm_timer_model.cc
+++ b/ash/assistant/model/assistant_alarm_timer_model.cc
@@ -38,6 +38,12 @@
   NotifyAllAlarmsTimersRemoved();
 }
 
+const AlarmTimer* AssistantAlarmTimerModel::GetAlarmTimerById(
+    const std::string& id) const {
+  auto it = alarms_timers_.find(id);
+  return it != alarms_timers_.end() ? &it->second : nullptr;
+}
+
 void AssistantAlarmTimerModel::Tick() {
   const base::TimeTicks now = base::TimeTicks::Now();
 
diff --git a/ash/assistant/model/assistant_alarm_timer_model.h b/ash/assistant/model/assistant_alarm_timer_model.h
index bf2e064..1ee7cb8 100644
--- a/ash/assistant/model/assistant_alarm_timer_model.h
+++ b/ash/assistant/model/assistant_alarm_timer_model.h
@@ -24,6 +24,9 @@
   std::string id;
   AlarmTimerType type;
   base::TimeTicks end_time;
+
+  // Returns true if this alarm/timer has expired.
+  bool expired() const { return base::TimeTicks::Now() >= end_time; }
 };
 
 // The model belonging to AssistantAlarmTimerController which tracks alarm/timer
@@ -43,6 +46,9 @@
   // Remove all alarms/timers from the model.
   void RemoveAllAlarmsTimers();
 
+  // Returns the alarm/timer uniquely identified by |id|.
+  const AlarmTimer* GetAlarmTimerById(const std::string& id) const;
+
   // Invoke to tick any alarms/timers and to notify observers of time remaining.
   void Tick();
 
diff --git a/ash/assistant/model/assistant_notification_model.cc b/ash/assistant/model/assistant_notification_model.cc
index 9bc1d3d6..eae1924 100644
--- a/ash/assistant/model/assistant_notification_model.cc
+++ b/ash/assistant/model/assistant_notification_model.cc
@@ -23,15 +23,19 @@
   observers_.RemoveObserver(observer);
 }
 
-void AssistantNotificationModel::AddNotification(
+void AssistantNotificationModel::AddOrUpdateNotification(
     AssistantNotificationPtr notification) {
   AssistantNotification* ptr = notification.get();
 
   DCHECK(!ptr->client_id.empty());
-  DCHECK(!base::ContainsKey(notifications_, ptr->client_id));
+  bool is_update = HasNotificationForId(ptr->client_id);
 
   notifications_[ptr->client_id] = std::move(notification);
-  NotifyNotificationAdded(ptr);
+
+  if (is_update)
+    NotifyNotificationUpdated(ptr);
+  else
+    NotifyNotificationAdded(ptr);
 }
 
 void AssistantNotificationModel::RemoveNotificationById(const std::string& id,
@@ -74,12 +78,23 @@
   return it != notifications_.end() ? it->second.get() : nullptr;
 }
 
+bool AssistantNotificationModel::HasNotificationForId(
+    const std::string& id) const {
+  return base::ContainsKey(notifications_, id);
+}
+
 void AssistantNotificationModel::NotifyNotificationAdded(
     const AssistantNotification* notification) {
   for (auto& observer : observers_)
     observer.OnNotificationAdded(notification);
 }
 
+void AssistantNotificationModel::NotifyNotificationUpdated(
+    const AssistantNotification* notification) {
+  for (auto& observer : observers_)
+    observer.OnNotificationUpdated(notification);
+}
+
 void AssistantNotificationModel::NotifyNotificationRemoved(
     const AssistantNotification* notification,
     bool from_server) {
diff --git a/ash/assistant/model/assistant_notification_model.h b/ash/assistant/model/assistant_notification_model.h
index 06c21003..566f104f 100644
--- a/ash/assistant/model/assistant_notification_model.h
+++ b/ash/assistant/model/assistant_notification_model.h
@@ -32,8 +32,10 @@
   void AddObserver(AssistantNotificationModelObserver* observer);
   void RemoveObserver(AssistantNotificationModelObserver* observer);
 
-  // Adds the specified |notification| to the model.
-  void AddNotification(AssistantNotificationPtr notification);
+  // Adds or updates the specified |notification| in the model. If there is an
+  // existing notification with the same |client_id|, an update will occur.
+  // Otherwise a new notification will be added.
+  void AddOrUpdateNotification(AssistantNotificationPtr notification);
 
   // Removes the notification uniquely identified by |id|. If |from_server| is
   // true the request to remove was initiated by the server.
@@ -51,8 +53,13 @@
   // Returns the notification uniquely identified by |id|.
   const AssistantNotification* GetNotificationById(const std::string& id) const;
 
+  // Returns true if the model contains a notification uniquely identified by
+  // |id|, otherwise false.
+  bool HasNotificationForId(const std::string& id) const;
+
  private:
   void NotifyNotificationAdded(const AssistantNotification* notification);
+  void NotifyNotificationUpdated(const AssistantNotification* notification);
   void NotifyNotificationRemoved(const AssistantNotification* notification,
                                  bool from_server);
   void NotifyAllNotificationsRemoved(bool from_server);
diff --git a/ash/assistant/model/assistant_notification_model_observer.h b/ash/assistant/model/assistant_notification_model_observer.h
index a49a39b2..e98a11c 100644
--- a/ash/assistant/model/assistant_notification_model_observer.h
+++ b/ash/assistant/model/assistant_notification_model_observer.h
@@ -27,6 +27,10 @@
   // Invoked when the specified |notification| has been added.
   virtual void OnNotificationAdded(const AssistantNotification* notification) {}
 
+  // Invoked when the specified |notification| has been updated.
+  virtual void OnNotificationUpdated(
+      const AssistantNotification* notification) {}
+
   // Invoked when the specified |notification| has been removed. If
   // |from_server| is true the request to remove was initiated by the server.
   virtual void OnNotificationRemoved(const AssistantNotification* notification,
diff --git a/ash/public/interfaces/assistant_controller.mojom b/ash/public/interfaces/assistant_controller.mojom
index 47bef27..dba5eb9 100644
--- a/ash/public/interfaces/assistant_controller.mojom
+++ b/ash/public/interfaces/assistant_controller.mojom
@@ -44,13 +44,14 @@
 // AssistantController. Currently used by the Assistant service to modify
 // Assistant notification state in Ash in response to LibAssistant events.
 interface AssistantNotificationController {
-  // Requests that the specified |notification| be added.
-  AddNotification(chromeos.assistant.mojom.AssistantNotification notification);
+  // Requests that the specified |notification| be added or updated. If the
+  // |client_id| for |notification| matches that of an existing notification,
+  // an update will occur. Otherwise, a new notification will be added.
+  AddOrUpdateNotification(
+    chromeos.assistant.mojom.AssistantNotification notification);
 
-  // Requests that the notification uniquely identified by |id| be removed.
-  // Note that |id| refers to the notification's client id which may or may not
-  // be the same as its server id. If |from_server| is true the request to
-  // remove was initiated by the server.
+  // Requests that the notification uniquely identified by |id| be removed. If
+  // |from_server| is true the request to remove was initiated by the server.
   RemoveNotificationById(string id, bool from_server);
 
   // Requests that all notifications associated with the given |grouping_key|
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 33f359b..8f5b37e8 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -234,6 +234,10 @@
 class VrShell;
 }
 
+namespace web {
+class WebSubThread;
+}
+
 namespace webrtc {
 class DesktopConfigurationMonitor;
 }
@@ -317,6 +321,7 @@
   friend class mojo::CoreLibraryInitializer;
   friend class resource_coordinator::TabManagerDelegate;  // crbug.com/778703
   friend class ui::MaterialDesignController;
+  friend class web::WebSubThread;
   friend class StackSamplingProfiler;
 
   ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
diff --git a/build/android/gyp/assert_static_initializers.py b/build/android/gyp/assert_static_initializers.py
index 717861b7..59ab6f49 100755
--- a/build/android/gyp/assert_static_initializers.py
+++ b/build/android/gyp/assert_static_initializers.py
@@ -28,7 +28,7 @@
   args = parser.parse_args()
 
   #TODO(crbug.com/838414): add support for files included via loadable_modules.
-  ignored_libs = ['libarcore_sdk_c.so']
+  ignored_libs = ['libarcore_sdk_c_minimal.so']
 
   si_count = resource_sizes.AnalyzeStaticInitializers(
       args.apk, args.tool_prefix, False, '.', ignored_libs)
diff --git a/build/config/android/chrome_version.gni b/build/config/android/chrome_version.gni
index 1531bf2..966a9abc 100644
--- a/build/config/android/chrome_version.gni
+++ b/build/config/android/chrome_version.gni
@@ -14,3 +14,51 @@
   # builders (which currently set the version number with this GN arg).
   chrome_version_name = chrome_version_full
 }
+
+_version_code = chrome_version_id
+
+# The architecture preference is encoded into the version_code for devices
+# that support multiple architectures
+if (target_cpu == "arm") {
+  _arch_preference = 0
+} else if (target_cpu == "x86") {
+  _arch_preference = 10
+} else if (target_cpu == "mipsel") {
+  _arch_preference = 20
+} else if (target_cpu == "arm64") {
+  _arch_preference = 50
+} else if (target_cpu == "x64") {
+  _arch_preference = 60
+} else {
+  assert(false, "Error: Unrecognized target_cpu: " + target_cpu)
+}
+_version_code += _arch_preference
+
+if (!public_android_sdk) {
+  # Match downstream logic for next builds
+  _version_code += 5
+}
+
+webview_version_code = "$_version_code"
+chrome_version_code = "$_version_code"
+
+_version_code += 1
+chrome_modern_version_code = "$_version_code"
+
+_version_code += 1
+monochrome_version_code = "$_version_code"
+
+_version_code += 1
+trichrome_version_code = "$_version_code"
+
+if (android_override_version_code != "") {
+  webview_version_code = android_override_version_code
+  chrome_version_code = android_override_version_code
+  chrome_modern_version_code = android_override_version_code
+  monochrome_version_code = android_override_version_code
+  trichrome_version_code = android_override_version_code
+}
+
+if (android_override_version_name != "") {
+  chrome_version_name = android_override_version_name
+}
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index af4c3f5..7a02ba5 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -159,6 +159,12 @@
     # Android versionName for android_apk()s that don't explicitly set one.
     android_default_version_name = "Developer Build"
 
+    # Forced Android versionCode
+    android_override_version_code = ""
+
+    # Forced Android versionName
+    android_override_version_name = ""
+
     # The path to the keystore to use for signing builds.
     android_keystore_path = default_android_keystore_path
 
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 8789e9f..bcb3d717 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2006,14 +2006,20 @@
           rebase_path(_final_apk_path_no_ext, root_build_dir) + ".ap_"
     }
 
-    _version_code = android_default_version_code
-    if (defined(invoker.version_code)) {
+    if (android_override_version_code != "") {
+      _version_code = android_override_version_code
+    } else if (defined(invoker.version_code)) {
       _version_code = invoker.version_code
+    } else {
+      _version_code = android_default_version_code
     }
 
-    _version_name = android_default_version_name
-    if (defined(invoker.version_name)) {
+    if (android_override_version_name != "") {
+      _version_name = android_override_version_name
+    } else if (defined(invoker.version_name)) {
       _version_name = invoker.version_name
+    } else {
+      _version_name = android_default_version_name
     }
 
     _deps = []
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
index 11dba35..522efa7 100644
--- a/build/config/clang/BUILD.gn
+++ b/build/config/clang/BUILD.gn
@@ -35,21 +35,6 @@
       "find-bad-constructs",
     ]
 
-    cflags += [
-      "-Xclang",
-      "-plugin-arg-find-bad-constructs",
-      "-Xclang",
-      "enforce-in-thirdparty-webkit",
-    ]
-
-    # TODO(dcheng): remove this once the plugin is updated and rolled again.
-    cflags += [
-      "-Xclang",
-      "-plugin-arg-find-bad-constructs",
-      "-Xclang",
-      "check-enum-max-value",
-    ]
-
     if (is_linux || is_android || is_fuchsia) {
       cflags += [
         "-Xclang",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 470de44..07d8efa 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -126,7 +126,7 @@
 
   # Turn this on to use ghash feature of lld for faster debug link on Windows.
   # http://blog.llvm.org/2018/01/improving-link-time-on-windows-with.html
-  use_ghash = true
+  use_ghash = false
 
   # Whether to enable ThinLTO optimizations. Turning ThinLTO optimizations on
   # can substantially increase link time and binary size, but they generally
@@ -2230,7 +2230,10 @@
       # it all. This flag is incompatible with /PROFILE
       ldflags = [ "/DEBUG:FASTLINK" ]
     } else if (is_clang && use_lld && use_ghash) {
-      cflags += [ "-gcodeview-ghash" ]
+      cflags += [
+        "-mllvm",
+        "-emit-codeview-ghash-section",
+      ]
       ldflags = [ "/DEBUG:GHASH" ]
     } else {
       ldflags = [ "/DEBUG" ]
diff --git a/build/util/version.gni b/build/util/version.gni
index 01e3807..189d109f1 100644
--- a/build/util/version.gni
+++ b/build/util/version.gni
@@ -15,9 +15,11 @@
 
 # Give version.py a pattern that will expand to a GN scope consisting of
 # all values we need at once.
-_version_dictionary_template = "full = \"@MAJOR@.@MINOR@.@BUILD@.@PATCH@\" " +
-                               "major = \"@MAJOR@\" minor = \"@MINOR@\" " +
-                               "build = \"@BUILD@\" patch = \"@PATCH@\" "
+_version_dictionary_template =
+    "full = \"@MAJOR@.@MINOR@.@BUILD@.@PATCH@\" " +
+    "major = \"@MAJOR@\" minor = \"@MINOR@\" " +
+    "build = \"@BUILD@\" patch = \"@PATCH@\" " + "version_id = @VERSION_ID@ " +
+    "patch_hi = @PATCH_HI@ " + "patch_lo = @PATCH_LO@ "
 
 # The file containing the Chrome version number.
 chrome_version_file = "//chrome/VERSION"
@@ -28,6 +30,12 @@
                         rebase_path(chrome_version_file, root_build_dir),
                         "-t",
                         _version_dictionary_template,
+                        "-e",
+                        "VERSION_ID='%s%03d00' % (BUILD, int(PATCH))",
+                        "-e",
+                        "PATCH_HI=int(PATCH)/256",
+                        "-e",
+                        "PATCH_LO=int(PATCH)%256",
                       ],
                       "scope",
                       [ chrome_version_file ])
@@ -40,20 +48,11 @@
 chrome_version_minor = _result.minor
 chrome_version_build = _result.build
 chrome_version_patch = _result.patch
+chrome_version_id = _result.version_id
+chrome_version_patch_hi = _result.patch_hi
+chrome_version_patch_lo = _result.patch_lo
 
 if (is_mac) {
-  _result = exec_script("version.py",
-                        [
-                          "-f",
-                          rebase_path(chrome_version_file, root_build_dir),
-                          "-t",
-                          "@BUILD@.@PATCH_HI@.@PATCH_LO@",
-                          "-e",
-                          "PATCH_HI=int(PATCH)/256",
-                          "-e",
-                          "PATCH_LO=int(PATCH)%256",
-                        ],
-                        "trim string",
-                        [ chrome_version_file ])
-  chrome_dylib_version = _result
+  chrome_dylib_version = "$chrome_version_build.$chrome_version_patch_hi" +
+                         ".$chrome_version_patch_lo"
 }
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index d363fe84b..22db5dd 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -48,10 +48,6 @@
 // Enables the GPU benchmarking extension
 const char kEnableGpuBenchmarking[] = "enable-gpu-benchmarking";
 
-// Always asks the display compositor to send back presentation times.
-const char kAlwaysRequestPresentationTime[] =
-    "always-request-presentation-time";
-
 // Renders a border around compositor layers to help debug and study
 // layer compositing.
 const char kShowCompositedLayerBorders[] = "show-composited-layer-borders";
diff --git a/cc/base/switches.h b/cc/base/switches.h
index fe8de281..cde4700 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -29,7 +29,6 @@
 
 // Switches for both the renderer and ui compositors.
 CC_BASE_EXPORT extern const char kEnableGpuBenchmarking[];
-CC_BASE_EXPORT extern const char kAlwaysRequestPresentationTime[];
 
 // Debug visualizations.
 CC_BASE_EXPORT extern const char kShowCompositedLayerBorders[];
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 3116354..7a34b6eb 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -305,14 +305,11 @@
   }
 
   sync_tree->set_source_frame_number(SourceFrameNumber());
-  bool request_presentation_time =
-      settings_.always_request_presentation_time ||
-      !pending_presentation_time_callbacks_.empty();
-  if (request_presentation_time && pending_presentation_time_callbacks_.empty())
-    pending_presentation_time_callbacks_.push_back(base::DoNothing());
-  sync_tree->AddPresentationCallbacks(
-      std::move(pending_presentation_time_callbacks_));
-  pending_presentation_time_callbacks_.clear();
+  if (!pending_presentation_time_callbacks_.empty()) {
+    sync_tree->AddPresentationCallbacks(
+        std::move(pending_presentation_time_callbacks_));
+    pending_presentation_time_callbacks_.clear();
+  }
 
   if (needs_full_tree_sync_)
     TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 93b6eb9..537d6a2b 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1928,9 +1928,7 @@
   metadata.root_background_color = active_tree_->background_color();
   metadata.content_source_id = active_tree_->content_source_id();
 
-  metadata.request_presentation_feedback = true;
-  if (active_tree_->has_presentation_callbacks() ||
-      settings_.always_request_presentation_time) {
+  if (active_tree_->has_presentation_callbacks()) {
     frame_token_infos_.emplace_back(metadata.frame_token,
                                     CurrentBeginFrameArgs().frame_time,
                                     active_tree_->TakePresentationCallbacks());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index cf20f63..cde6927 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -7849,55 +7849,15 @@
 };
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPaintedDeviceScaleFactor);
 
-// Makes sure that presentation-time requests are correctly propagated to the
-// frame's metadata.
-class LayerTreeHostTestPresentationTimeRequest : public LayerTreeHostTest {
+// Tests that a presentation-timestamps are received for a frame.
+class LayerTreeHostTestPresentationTime : public LayerTreeHostTest {
  protected:
   void BeginTest() override {
-    layer_tree_host()->RequestPresentationTimeForNextFrame(base::DoNothing());
     PostSetNeedsCommitToMainThread();
   }
 
   void DisplayReceivedCompositorFrameOnThread(
       const viz::CompositorFrame& frame) override {
-    EXPECT_TRUE(frame.metadata.request_presentation_feedback);
-    EndTest();
-  }
-
-  void AfterTest() override {}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPresentationTimeRequest);
-
-// A SwapPromise that turns on |request_presentation_feedback| during
-// WillSwap().
-class RequestPresentationFeedbackSwapPromise : public SwapPromise {
- public:
-  RequestPresentationFeedbackSwapPromise() = default;
-  ~RequestPresentationFeedbackSwapPromise() override = default;
-
-  // SwapPromise:
-  void DidActivate() override {}
-  void WillSwap(viz::CompositorFrameMetadata* metadata) override {
-    metadata->request_presentation_feedback = true;
-  }
-  void DidSwap() override {}
-  void DidNotSwap(DidNotSwapReason reason) override {}
-  int64_t TraceId() const override { return 0; }
-};
-
-// Tests that a presentation-token can be requested during swap.
-class LayerTreeHostTestPresentationTimeRequestDuringSwap
-    : public LayerTreeHostTest {
- protected:
-  void BeginTest() override {
-    layer_tree_host()->QueueSwapPromise(
-        std::make_unique<RequestPresentationFeedbackSwapPromise>());
-    PostSetNeedsCommitToMainThread();
-  }
-
-  void DisplayReceivedCompositorFrameOnThread(
-      const viz::CompositorFrame& frame) override {
-    EXPECT_TRUE(frame.metadata.request_presentation_feedback);
     frame_token_ = frame.metadata.frame_token;
   }
 
@@ -7914,8 +7874,7 @@
  private:
   uint32_t frame_token_ = 0;
 };
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostTestPresentationTimeRequestDuringSwap);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPresentationTime);
 
 // Makes sure that viz::LocalSurfaceId is propagated to the LayerTreeFrameSink.
 class LayerTreeHostTestLocalSurfaceId : public LayerTreeHostTest {
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index d50a4cc..dd854fb 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -1061,8 +1061,7 @@
 
   void DisplayReceivedCompositorFrameOnThread(
       const viz::CompositorFrame& frame) override {
-    if (frame.metadata.request_presentation_feedback)
-      received_token_ = frame.metadata.frame_token;
+    received_token_ = frame.metadata.frame_token;
   }
 
   void AfterTest() override {
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 7f074dd9..9de6c5f5 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -145,10 +145,6 @@
   // Whether to use edge anti-aliasing for all layer types that supports it.
   bool enable_edge_anti_aliasing = true;
 
-  // Whether to request presentation time regardless if existence of
-  // presentation time callbacks.
-  bool always_request_presentation_time = false;
-
   // Whether SetViewportSizeAndScale should update the painted scale factor or
   // the device scale factor.
   bool use_painted_device_scale_factor = false;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 2ff0f55..dcbe126 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -123,9 +123,6 @@
       public_deps += [ ":reorder_imports" ]
       data_deps += [ ":reorder_imports" ]
     }
-    if (use_aura && (is_win || is_linux)) {
-      data_deps += [ "//chrome/app:service_manifests" ]
-    }
     if (is_chromeos) {
       data_deps += [ "//sandbox/linux:chrome_sandbox" ]
     }
@@ -1228,13 +1225,9 @@
     ]
 
     if (is_chrome_branded) {
-      framework_contents += [
-        "Default Apps",
-      ]
+      framework_contents += [ "Default Apps" ]
       if (enable_keystone_registration_framework) {
-        framework_contents += [
-          "Frameworks",  # For KeystoneRegistration.framework.
-        ]
+        framework_contents += [ "Frameworks" ]  # For KeystoneRegistration.framework.
       }
     }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 8d2e027f..85d7f51 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=73
 MINOR=0
-BUILD=3648
+BUILD=3650
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 51d36ede..4a1c252 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1802,6 +1802,8 @@
     manifest_package = manifest_package
     module_name = "ArPublic"
     base_module_target = ":monochrome_public_base_module"
+    version_code = monochrome_version_code
+    version_name = chrome_version_name
   }
 }
 
@@ -1810,6 +1812,8 @@
     manifest_package = manifest_package
     module_name = "VrPublic"
     base_module_target = ":chrome_modern_public_base_module"
+    version_code = chrome_modern_version_code
+    version_name = chrome_version_name
   }
 }
 
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index fd2a07a..1a4685c 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -4,6 +4,7 @@
 
 import("//base/android/linker/config.gni")
 import("//base/android/proguard/proguard.gni")
+import("//build/config/android/chrome_version.gni")
 import("//build/config/android/extract_unwind_tables.gni")
 import("//build/config/android/rules.gni")
 import("//build/config/compiler/compiler.gni")
@@ -109,6 +110,10 @@
 
   _is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
 
+  _use_trichrome_library =
+      defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
+  assert(_use_trichrome_library || !_use_trichrome_library)  # Mark as used.
+
   if (defined(invoker.enable_multidex)) {
     _enable_multidex = invoker.enable_multidex
   } else {
@@ -230,6 +235,19 @@
     if (enable_vr && (_target_type == "android_apk" || !modularize_vr)) {
       deps += [ "//chrome/browser/android/vr:java" ]
     }
+
+    if (!defined(version_code)) {
+      if (_use_trichrome_library) {
+        version_code = trichrome_version_code
+      } else if (_is_monochrome) {
+        version_code = monochrome_version_code
+      } else if (_is_modern) {
+        version_code = chrome_modern_version_code
+      } else {
+        # For chrome without the modern design, used on pre-L devices
+        version_code = chrome_version_code
+      }
+    }
   }
 }
 
@@ -243,9 +261,10 @@
   }
   chrome_public_common_apk_or_module_tmpl(target_name) {
     is_monochrome = true
+    use_trichrome_library =
+        defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
 
-    if (!defined(invoker.use_trichrome_library) ||
-        !invoker.use_trichrome_library) {
+    if (!use_trichrome_library) {
       if (invoker.target_type == "android_app_bundle_module") {
         _suffix = bundle_library_suffix
       } else {
@@ -357,19 +376,19 @@
       deps += [ "//chrome/browser/android/vr:java" ]
     }
 
-    if ((invoker.target_type == "android_apk" || !modularize_ar) &&
-        package_arcore) {
-      deps += [ "//third_party/android_deps:com_google_ar_core_java" ]
-
-      # We store this as a separate .so in the APK and only load as needed.
-      if (android_64bit_target_cpu) {
-        if (android_64bit_browser) {
-          loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/arm64-v8a/libarcore_sdk_c.so" ]
-        } else if (build_apk_secondary_abi) {
-          secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+    if (invoker.target_type == "android_apk" || !modularize_ar) {
+      if (enable_arcore) {
+        deps += [ "//third_party/arcore-android-sdk:libdynamite_client_java" ]
+      }
+      if (package_arcore) {
+        # We store this as a separate .so in the APK and only load as needed.
+        if (android_64bit_target_cpu && build_apk_secondary_abi) {
+          secondary_abi_loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
+        } else if (android_64bit_target_cpu && !build_apk_secondary_abi) {
+          loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so" ]
+        } else {
+          loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
         }
-      } else {
-        loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
       }
     }
   }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 6a0f1e6..17c4693 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -169,10 +169,11 @@
         <!-- ARCore APK integration -->
         <!-- This tag indicates that this application optionally uses ARCore. -->
         <meta-data android:name="com.google.ar.core" android:value="optional" />
-        <!-- TODO(crbug.com/917406): We should pull this flag in from the ArCore AAR. It's added here
-             because it doesn't get added properly for bundle base modules. -->
+        <!-- This value referes to ARCore 1.1.
+             This value should be updated when ARCore features require
+             a newer version of the ARCore SDK. -->
         <meta-data android:name="com.google.ar.core.min_apk_version"
-            android:value="180815000"/>
+            android:value="180226000"/>
         {% endif %}
 
         <!-- Cast support -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
index aac33c1..593ff30 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
@@ -90,7 +90,7 @@
     private static String getArCoreShimLibraryPath() {
         try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
             return ((BaseDexClassLoader) ContextUtils.getApplicationContext().getClassLoader())
-                    .findLibrary("arcore_sdk_c");
+                    .findLibrary("arcore_sdk_c_minimal");
         }
     }
 
@@ -203,7 +203,6 @@
                 break;
         }
 
-        // TODO(https://crbug.com/916651) - use ARCore SDK's InstallActivity to install ARCore
         SimpleConfirmInfoBarBuilder.Listener listener = new SimpleConfirmInfoBarBuilder.Listener() {
             @Override
             public void onInfoBarDismissed() {
@@ -229,7 +228,7 @@
     private boolean shouldRequestInstallArModule() {
         try {
             // Try to find class in AR module that has not been obfuscated.
-            Class.forName("com.google.ar.core.ArCoreApk");
+            Class.forName("com.google.vr.dynamite.client.UsedByNative");
             return false;
         } catch (ClassNotFoundException e) {
             return true;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedSchedulerBridgeConformanceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedSchedulerBridgeConformanceTest.java
index 6e016d0..2b9581b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedSchedulerBridgeConformanceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedSchedulerBridgeConformanceTest.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.feed;
 
-import static org.mockito.Mockito.mock;
-
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.UiThreadTestRule;
 
@@ -19,6 +17,7 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.Description;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 
 import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
@@ -57,6 +56,10 @@
                 }
             });
 
+    @Mock
+    private RequestManager mRequestManager;
+    @Mock
+    private SessionManager mSessionManager;
     private boolean mUseRequestManager;
 
     public FeedSchedulerBridgeConformanceTest(boolean useRequestManager) {
@@ -69,8 +72,7 @@
         scheduler = new FeedSchedulerBridge(Profile.getLastUsedProfile());
         if (mUseRequestManager) {
             ((FeedSchedulerBridge) scheduler)
-                    .initializeFeedDependencies(
-                            mock(RequestManager.class), mock(SessionManager.class));
+                    .initializeFeedDependencies(mRequestManager, mSessionManager);
         }
     }
 
diff --git a/chrome/android/modules/ar/ar_module_tmpl.gni b/chrome/android/modules/ar/ar_module_tmpl.gni
index 9fae827..8c156b9 100644
--- a/chrome/android/modules/ar/ar_module_tmpl.gni
+++ b/chrome/android/modules/ar/ar_module_tmpl.gni
@@ -30,27 +30,28 @@
                              "base_module_target",
                              "module_name",
                              "version_code",
+                             "version_name",
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":$_manifest_target"
     deps = [
-      "//third_party/android_deps:com_google_ar_core_java",
+      "//third_party/arcore-android-sdk:libdynamite_client_java",
     ]
 
     # We only want to add the 32 bit arcore shim even for 64 bit monochrome
     # builds. AR is never used in 64 bit mode. We store the arcore shim as a
     # separate .so in the bundle module and only load as needed.
     if (android_64bit_target_cpu && build_apk_secondary_abi) {
-      secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+      secondary_abi_loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
 
       # Disguise 32 bit library as 64 bit. This works around a Play Core bug where only 64 bit
       # libraries are extracted on 64 bit devices.
       # TODO(crbug.com/902859): Remove once bug is fixed.
-      loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+      loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
     } else if (android_64bit_target_cpu && !build_apk_secondary_abi) {
-      loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+      loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so" ]
     } else {
-      loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+      loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
     }
     uncompress_shared_libraries = true
 
diff --git a/chrome/android/modules/vr/vr_module_tmpl.gni b/chrome/android/modules/vr/vr_module_tmpl.gni
index 01596969..9ff046a 100644
--- a/chrome/android/modules/vr/vr_module_tmpl.gni
+++ b/chrome/android/modules/vr/vr_module_tmpl.gni
@@ -31,6 +31,7 @@
                              "base_module_target",
                              "module_name",
                              "version_code",
+                             "version_name",
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":${_manifest_target}"
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 8c90db5..8e1b7a2 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-73.0.3647.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-73.0.3649.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
index 3b76a89..fe21a31b 100644
--- a/chrome/android/trichrome.gni
+++ b/chrome/android/trichrome.gni
@@ -16,7 +16,7 @@
   "min_sdk_version=28",
   "target_sdk_version=$android_sdk_version",
   "trichrome_library=$trichrome_library_package",
-  "trichrome_version=$android_default_version_code",
+  "trichrome_version=$trichrome_version_code",
   "trichrome_certdigest=$trichrome_certdigest",
 ]
 
@@ -44,6 +44,7 @@
     use_chromium_linker = false
     uncompress_shared_libraries = true
     version_name = chrome_version_name
+    version_code = trichrome_version_code
 
     # Only try to generate the native library version in configurations that
     # include a native library.
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 016b0ba2..39bd9e5c 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -519,70 +519,3 @@
     ":chrome_content_utility_manifest_overlay",
   ]
 }
-
-if (use_aura || enable_ipc_fuzzer) {
-  # NOTE: These rules generate compiled versions of the content service
-  # manifests with Chrome's overlays applied. These are only used at run-time,
-  # and only when running Chrome inside the Mash environment. In production
-  # Chrome, the content manifests and Chrome's overlays are baked into browser
-  # resources and merged at runtime.
-
-  service_manifest("chrome_content_packaged_services_manifest") {
-    source_manifest = "//content/public/app:packaged_services_manifest"
-    overlays = [ ":chrome_content_packaged_services_manifest_overlay" ]
-  }
-
-  service_manifest("chrome_content_browser_manifest") {
-    source_manifest = "//content/public/app:browser_manifest"
-    overlays = [ ":chrome_content_browser_manifest_overlay" ]
-  }
-
-  service_manifest("chrome_test_browser_manifest") {
-    source_manifest = ":chrome_content_browser_manifest"
-    overlays = [ ":chrome_test_browser_overlay" ]
-  }
-
-  service_manifest("chrome_content_gpu_manifest") {
-    source_manifest = "//content/public/app:gpu_manifest"
-    overlays = [ ":chrome_content_gpu_manifest_overlay" ]
-  }
-
-  service_manifest("chrome_content_plugin_manifest") {
-    source_manifest = "//content/public/app:plugin_manifest"
-    overlays = [ ":chrome_content_plugin_manifest_overlay" ]
-  }
-
-  service_manifest("chrome_content_renderer_manifest") {
-    source_manifest = "//content/public/app:renderer_manifest"
-    overlays = [ ":chrome_content_renderer_manifest_overlay" ]
-  }
-
-  service_manifest("chrome_content_utility_manifest") {
-    source_manifest = "//content/public/app:utility_manifest"
-    overlays = [ ":chrome_content_utility_manifest_overlay" ]
-  }
-
-  group("service_manifests") {
-    deps = [
-      ":chrome_content_browser_manifest",
-      ":chrome_content_gpu_manifest",
-      ":chrome_content_plugin_manifest",
-      ":chrome_content_renderer_manifest",
-      ":chrome_content_utility_manifest",
-    ]
-  }
-
-  chrome_embedded_services = [
-    ":chrome_content_browser_manifest",
-    ":chrome_content_gpu_manifest",
-    ":chrome_content_plugin_manifest",
-    ":chrome_content_renderer_manifest",
-    ":chrome_content_utility_manifest",
-    ":chrome_renderer_manifest",
-  ]
-
-  catalog("catalog") {
-    embedded_services = chrome_embedded_services +
-                        [ ":chrome_content_packaged_services_manifest" ]
-  }
-}
diff --git a/chrome/browser/android/vr/arcore_device/arcore.h b/chrome/browser/android/vr/arcore_device/arcore.h
index cd57addb..9b0b0cf 100644
--- a/chrome/browser/android/vr/arcore_device/arcore.h
+++ b/chrome/browser/android/vr/arcore_device/arcore.h
@@ -45,6 +45,7 @@
 
   virtual bool RequestHitTest(
       const mojom::XRRayPtr& ray,
+      const gfx::Size& image_size,
       std::vector<mojom::XRHitResultPtr>* hit_results) = 0;
 
   virtual void Pause() = 0;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
index 1f6a024..370b03a 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -265,7 +265,8 @@
   gl_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ArCoreGl::ProcessFrame, weak_ptr_factory_.GetWeakPtr(),
-                     base::Passed(&frame_data), base::Passed(&callback)));
+                     base::Passed(&frame_data), frame_size,
+                     base::Passed(&callback)));
 }
 
 void ArCoreGl::RequestHitTest(
@@ -283,6 +284,7 @@
 
 void ArCoreGl::ProcessFrame(
     mojom::XRFrameDataPtr frame_data,
+    const gfx::Size& frame_size,
     mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
   DCHECK(IsOnGlThread());
   DCHECK(is_initialized_);
@@ -302,7 +304,7 @@
   // obvious how the timing between the results and the frame should go.
   for (auto& request : hit_test_requests_) {
     std::vector<mojom::XRHitResultPtr> results;
-    if (arcore_->RequestHitTest(request->ray, &results)) {
+    if (arcore_->RequestHitTest(request->ray, frame_size, &results)) {
       std::move(request->callback).Run(std::move(results));
     } else {
       // Hit test failed, i.e. unprojected location was offscreen.
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h
index e12f33a..1dd2d82 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -67,7 +67,9 @@
   base::WeakPtr<ArCoreGl> GetWeakPtr();
 
  private:
+  // TODO(https://crbug/835948): remove frame_size.
   void ProcessFrame(mojom::XRFrameDataPtr frame_data,
+                    const gfx::Size& frame_size,
                     mojom::XRFrameDataProvider::GetFrameDataCallback callback);
 
   bool InitializeGl();
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
index 3fd89bd..9d9a1d3a 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -62,6 +62,13 @@
     return false;
   }
 
+  // We just use the default config.
+  status = ArSession_checkSupported(session.get(), arcore_config.get());
+  if (status != AR_SUCCESS) {
+    DLOG(ERROR) << "ArSession_checkSupported failed: " << status;
+    return false;
+  }
+
   status = ArSession_configure(session.get(), arcore_config.get());
   if (status != AR_SUCCESS) {
     DLOG(ERROR) << "ArSession_configure failed: " << status;
@@ -207,8 +214,10 @@
   return result;
 }
 
+// TODO(835948): remove image-size
 bool ArCoreImpl::RequestHitTest(
     const mojom::XRRayPtr& ray,
+    const gfx::Size& image_size,
     std::vector<mojom::XRHitResultPtr>* hit_results) {
   DCHECK(IsOnGlThread());
   DCHECK(arcore_session_.is_valid());
@@ -225,14 +234,17 @@
     return false;
   }
 
+  gfx::PointF screen_point;
+  if (!TransformRayToScreenSpace(ray, image_size, &screen_point)) {
+    return false;
+  }
+
   // ArCore returns hit-results in sorted order, thus providing the guarantee
   // of sorted results promised by the WebXR spec for requestHitTest().
-  float origin[3] = {ray->origin.x(), ray->origin.y(), ray->origin.z()};
-  float direction[3] = {ray->direction.x(), ray->direction.y(),
-                        ray->direction.z()};
-
-  ArFrame_hitTestRay(arcore_session_.get(), arcore_frame_.get(), origin,
-                     direction, arcore_hit_result_list.get());
+  ArFrame_hitTest(arcore_session_.get(), arcore_frame_.get(),
+                  screen_point.x() * image_size.width(),
+                  screen_point.y() * image_size.height(),
+                  arcore_hit_result_list.get());
 
   int arcore_hit_result_list_size = 0;
   ArHitResultList_getSize(arcore_session_.get(), arcore_hit_result_list.get(),
@@ -310,6 +322,61 @@
   return true;
 }
 
+// TODO(835948): remove this method.
+bool ArCoreImpl::TransformRayToScreenSpace(const mojom::XRRayPtr& ray,
+                                           const gfx::Size& image_size,
+                                           gfx::PointF* screen_point) {
+  DCHECK(IsOnGlThread());
+  DCHECK(arcore_session_.is_valid());
+  DCHECK(arcore_frame_.is_valid());
+
+  internal::ScopedArCoreObject<ArCamera*> arcore_camera;
+  ArFrame_acquireCamera(
+      arcore_session_.get(), arcore_frame_.get(),
+      internal::ScopedArCoreObject<ArCamera*>::Receiver(arcore_camera).get());
+  DCHECK(arcore_camera.is_valid())
+      << "ArFrame_acquireCamera failed despite documentation saying it cannot";
+
+  // Get the projection matrix.
+  float projection_matrix[16];
+  ArCamera_getProjectionMatrix(arcore_session_.get(), arcore_camera.get(), 0.1,
+                               1000, projection_matrix);
+  SkMatrix44 projection44;
+  projection44.setColMajorf(projection_matrix);
+  gfx::Transform projection_transform(projection44);
+
+  // Get the view matrix.
+  float view_matrix[16];
+  ArCamera_getViewMatrix(arcore_session_.get(), arcore_camera.get(),
+                         view_matrix);
+  SkMatrix44 view44;
+  view44.setColMajorf(view_matrix);
+  gfx::Transform view_transform(view44);
+
+  // Create the combined matrix.
+  gfx::Transform proj_view_transform = projection_transform * view_transform;
+
+  // Transform the ray into screen space.
+  gfx::Point3F screen_point_3d = ray->origin + ray->direction;
+
+  proj_view_transform.TransformPoint(&screen_point_3d);
+  if (screen_point_3d.x() < -1 || screen_point_3d.x() > 1 ||
+      screen_point_3d.y() < -1 || screen_point_3d.y() > 1) {
+    // The point does not project back into screen space, so this won't
+    // work with the screen-space-based hit-test API.
+    DLOG(ERROR) << "Invalid ray - does not originate from device screen.";
+    return false;
+  }
+
+  screen_point->set_x((screen_point_3d.x() + 1) / 2);
+  // The calculated point in GL's normalized device coordinates (NDC) ranges
+  // from -1..1, with -1, -1 at the bottom left of the screen, +1 at the top.
+  // The output screen space coordinates range from 0..1, with 0, 0 at the
+  // top left.
+  screen_point->set_y((-screen_point_3d.y() + 1) / 2);
+  return true;
+}
+
 bool ArCoreImpl::IsOnGlThread() {
   return gl_thread_task_runner_->BelongsToCurrentThread();
 }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.h b/chrome/browser/android/vr/arcore_device/arcore_impl.h
index 344d7fa..2561e08 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_impl.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_impl.h
@@ -82,9 +82,14 @@
   void Pause() override;
   void Resume() override;
   bool RequestHitTest(const mojom::XRRayPtr& ray,
+                      const gfx::Size& image_size,
                       std::vector<mojom::XRHitResultPtr>* hit_results) override;
 
  private:
+  bool TransformRayToScreenSpace(const mojom::XRRayPtr& ray,
+                                 const gfx::Size& image_size,
+                                 gfx::PointF* screen_point);
+
   bool IsOnGlThread();
   base::WeakPtr<ArCoreImpl> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
diff --git a/chrome/browser/android/vr/arcore_device/arcore_shim.cc b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
index 9b9fabff..76edce51 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_shim.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
@@ -22,7 +22,7 @@
   CALL(ArFrame_acquireCamera)            \
   CALL(ArFrame_create)                   \
   CALL(ArFrame_destroy)                  \
-  CALL(ArFrame_hitTestRay)               \
+  CALL(ArFrame_hitTest)                  \
   CALL(ArFrame_transformDisplayUvCoords) \
   CALL(ArHitResult_create)               \
   CALL(ArHitResult_destroy)              \
@@ -35,6 +35,7 @@
   CALL(ArPose_destroy)                   \
   CALL(ArPose_getMatrix)                 \
   CALL(ArPose_getPoseRaw)                \
+  CALL(ArSession_checkSupported)         \
   CALL(ArSession_configure)              \
   CALL(ArSession_create)                 \
   CALL(ArSession_destroy)                \
@@ -78,13 +79,13 @@
   if (!sdk_handle) {
     char* error_string = nullptr;
     error_string = dlerror();
-    LOG(ERROR) << "Could not open libarcore_sdk_c.so: " << error_string;
+    LOG(ERROR) << "Could not open libarcore_sdk_c_minimal.so: " << error_string;
     return false;
   } else {
     VLOG(2) << "Opened shim shared library.";
   }
 
-  // TODO(https://crbug.com/914999): check SDK version.
+  // TODO(vollick): check SDK version.
   arcore_api = new ArCoreApi();
 
 #define CALL(fn) LoadFunction(sdk_handle, #fn, &arcore_api->impl_##fn);
@@ -152,13 +153,13 @@
   arcore_api->impl_ArFrame_destroy(frame);
 }
 
-void ArFrame_hitTestRay(const ArSession* session,
-                        const ArFrame* frame,
-                        const float* ray_origin_3,
-                        const float* ray_direction_3,
-                        ArHitResultList* out_hit_results) {
-  arcore_api->impl_ArFrame_hitTestRay(session, frame, ray_origin_3,
-                                      ray_direction_3, out_hit_results);
+void ArFrame_hitTest(const ArSession* session,
+                     const ArFrame* frame,
+                     float pixel_x,
+                     float pixel_y,
+                     ArHitResultList* out_hit_results) {
+  arcore_api->impl_ArFrame_hitTest(session, frame, pixel_x, pixel_y,
+                                   out_hit_results);
 }
 
 void ArFrame_transformDisplayUvCoords(const ArSession* session,
@@ -255,6 +256,11 @@
   arcore_api->impl_ArPose_getPoseRaw(session, pose, out_pose_raw);
 }
 
+ArStatus ArSession_checkSupported(const ArSession* session,
+                                  const ArConfig* config) {
+  return arcore_api->impl_ArSession_checkSupported(session, config);
+}
+
 ArStatus ArSession_configure(ArSession* session, const ArConfig* config) {
   return arcore_api->impl_ArSession_configure(session, config);
 }
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.cc b/chrome/browser/android/vr/arcore_device/fake_arcore.cc
index 1205748..b4bdfc19 100644
--- a/chrome/browser/android/vr/arcore_device/fake_arcore.cc
+++ b/chrome/browser/android/vr/arcore_device/fake_arcore.cc
@@ -203,6 +203,7 @@
 
 bool FakeArCore::RequestHitTest(
     const mojom::XRRayPtr& ray,
+    const gfx::Size& image_size,
     std::vector<mojom::XRHitResultPtr>* hit_results) {
   mojom::XRHitResultPtr hit = mojom::XRHitResult::New();
   hit->hit_matrix.resize(16);
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.h b/chrome/browser/android/vr/arcore_device/fake_arcore.h
index 12b560d8..d78672a 100644
--- a/chrome/browser/android/vr/arcore_device/fake_arcore.h
+++ b/chrome/browser/android/vr/arcore_device/fake_arcore.h
@@ -35,6 +35,7 @@
   void Resume() override;
 
   bool RequestHitTest(const mojom::XRRayPtr& ray,
+                      const gfx::Size& image_size,
                       std::vector<mojom::XRHitResultPtr>* hit_results) override;
 
   void SetCameraAspect(float aspect) { camera_aspect_ = aspect; }
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index d54bee5..14db9cd 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -123,14 +123,14 @@
 };
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-class ScopedPreviewTestingDelegate : PrintPreviewUI::TestingDelegate {
+class ScopedPreviewTestingDelegate : printing::PrintPreviewUI::TestingDelegate {
  public:
   ScopedPreviewTestingDelegate() {
-    PrintPreviewUI::SetDelegateForTesting(this);
+    printing::PrintPreviewUI::SetDelegateForTesting(this);
   }
 
   ~ScopedPreviewTestingDelegate() {
-    PrintPreviewUI::SetDelegateForTesting(NULL);
+    printing::PrintPreviewUI::SetDelegateForTesting(NULL);
   }
 
   // PrintPreviewUI::TestingDelegate implementation.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 83e0983..fdbf81e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -105,6 +105,7 @@
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_navigation_throttle.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/browser/safe_browsing/url_checker_delegate_impl.h"
@@ -4238,6 +4239,11 @@
       PreviewsLitePageDecider::MaybeCreateThrottleFor(handle);
   if (previews_lite_page_throttle)
     throttles.push_back(std::move(previews_lite_page_throttle));
+  if (base::FeatureList::IsEnabled(safe_browsing::kCommittedSBInterstitials)) {
+    throttles.push_back(
+        std::make_unique<safe_browsing::SafeBrowsingNavigationThrottle>(
+            handle));
+  }
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || \
     (defined(OS_LINUX) && !defined(OS_CHROMEOS))
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 2670ce4..443158fa 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -178,7 +178,6 @@
     // Please keep these in alphabetical order. Non-UI Compositor switches
     // here should also be added to
     // content/browser/renderer_host/render_process_host_impl.cc.
-    cc::switches::kAlwaysRequestPresentationTime,
     cc::switches::kCheckDamageEarly,
     cc::switches::kDisableCompositedAntialiasing,
     cc::switches::kDisableMainFrameBeforeActivation,
diff --git a/chrome/browser/devtools/devtools_file_watcher.cc b/chrome/browser/devtools/devtools_file_watcher.cc
index 3ea1d41d6..559af7c 100644
--- a/chrome/browser/devtools/devtools_file_watcher.cc
+++ b/chrome/browser/devtools/devtools_file_watcher.cc
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <set>
+#include <unordered_map>
 
 #include "base/bind.h"
 #include "base/files/file_enumerator.h"
@@ -42,9 +43,8 @@
       DevToolsFileWatcher::SharedFileWatcher>;
   ~SharedFileWatcher();
 
-  using FilePathTimesMap = std::map<base::FilePath, base::Time>;
-  void GetModificationTimes(const base::FilePath& path,
-                            FilePathTimesMap* file_path_times);
+  using FilePathTimesMap = std::unordered_map<base::FilePath, base::Time>;
+  FilePathTimesMap GetModificationTimes(const base::FilePath& path);
   void DirectoryChanged(const base::FilePath& path, bool error);
   void DispatchNotifications();
 
@@ -99,25 +99,28 @@
   if (!success)
     return;
 
-  GetModificationTimes(path, &file_path_times_[path]);
+  file_path_times_[path] = GetModificationTimes(path);
 }
 
-void DevToolsFileWatcher::SharedFileWatcher::GetModificationTimes(
-    const base::FilePath& path,
-    FilePathTimesMap* times_map) {
+DevToolsFileWatcher::SharedFileWatcher::FilePathTimesMap
+DevToolsFileWatcher::SharedFileWatcher::GetModificationTimes(
+    const base::FilePath& path) {
+  FilePathTimesMap times_map;
   base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES);
   base::FilePath file_path = enumerator.Next();
   while (!file_path.empty()) {
     base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
-    (*times_map)[file_path] = file_info.GetLastModifiedTime();
+    times_map[std::move(file_path)] = file_info.GetLastModifiedTime();
     file_path = enumerator.Next();
   }
+  return times_map;
 }
 
 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch(
     const base::FilePath& path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   watchers_.erase(path);
+  file_path_times_.erase(path);
 }
 
 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged(
@@ -154,8 +157,7 @@
 
   for (const auto& path : pending_paths_) {
     FilePathTimesMap& old_times = file_path_times_[path];
-    FilePathTimesMap current_times;
-    GetModificationTimes(path, &current_times);
+    FilePathTimesMap current_times = GetModificationTimes(path);
     for (const auto& path_time : current_times) {
       const base::FilePath& path = path_time.first;
       auto old_timestamp = old_times.find(path);
diff --git a/chrome/browser/printing/print_preview_message_handler.h b/chrome/browser/printing/print_preview_message_handler.h
index d5d9823..8b57c48 100644
--- a/chrome/browser/printing/print_preview_message_handler.h
+++ b/chrome/browser/printing/print_preview_message_handler.h
@@ -13,7 +13,6 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
-class PrintPreviewUI;
 struct PrintHostMsg_DidPreviewDocument_Params;
 struct PrintHostMsg_DidPreviewPage_Params;
 struct PrintHostMsg_DidStartPreview_Params;
@@ -36,6 +35,7 @@
 
 namespace printing {
 
+class PrintPreviewUI;
 struct PageSizeMargins;
 
 // Manages the print preview handling for a WebContents.
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 673928c..7cf3e07 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -326,7 +326,7 @@
   // Discard immediately without waiting for LogMemory() (https://crbug/850545).
   // Consider removing LogMemory() at all if nobody cares about the log.
   LogMemory("Tab Discards Memory details");
-  PurgeMemoryAndDiscardTab(reason);
+  DiscardTab(reason);
 }
 
 void TabManager::LogMemory(const std::string& title) {
@@ -397,13 +397,6 @@
 // TabManager, private:
 
 // static
-void TabManager::PurgeMemoryAndDiscardTab(LifecycleUnitDiscardReason reason) {
-  TabManager* manager = g_browser_process->GetTabManager();
-  manager->PurgeBrowserMemory();
-  manager->DiscardTab(reason);
-}
-
-// static
 bool TabManager::IsInternalPage(const GURL& url) {
   // There are many chrome:// UI URLs, but only look for the ones that users
   // are likely to have open. Most of the benefit is the from NTP URL.
@@ -420,20 +413,6 @@
   return false;
 }
 
-void TabManager::PurgeBrowserMemory() {
-  // Based on experimental evidence, attempts to free memory from renderers
-  // have been too slow to use in OOM situations (V8 garbage collection) or
-  // do not lead to persistent decreased usage (image/bitmap caches). This
-  // function therefore only targets large blocks of memory in the browser.
-  // Note that other objects will listen to MemoryPressureListener events
-  // to release memory.
-  for (auto* web_contents : AllTabContentses()) {
-    // Screenshots can consume ~5 MB per web contents for platforms that do
-    // touch back/forward.
-    web_contents->GetController().ClearAllScreenshots();
-  }
-}
-
 // This function is called when |update_timer_| fires. It will adjust the clock
 // if needed (if it detects that the machine was asleep) and will fire the stats
 // updating on ChromeOS via the delegate. This function also tries to purge
@@ -547,8 +526,6 @@
       return;
   }
   NOTREACHED();
-  // TODO(skuhne): If more memory pressure levels are introduced, consider
-  // calling PurgeBrowserMemory() before CRITICAL is reached.
 }
 
 void TabManager::OnActiveTabChanged(content::WebContents* old_contents,
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index f562d3f1..b7bea32 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -269,15 +269,10 @@
   // min time to purge times this value.
   const int kDefaultMinMaxTimeToPurgeRatio = 4;
 
-  static void PurgeMemoryAndDiscardTab(LifecycleUnitDiscardReason reason);
-
   // Returns true if the |url| represents an internal Chrome web UI page that
   // can be easily reloaded and hence makes a good choice to discard.
   static bool IsInternalPage(const GURL& url);
 
-  // Purges data structures in the browser that can be easily recomputed.
-  void PurgeBrowserMemory();
-
   // Callback for when |update_timer_| fires. Takes care of executing the tasks
   // that need to be run periodically (see comment in implementation).
   void UpdateTimerCallback();
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
index 499f1cfb..08aed1e70 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
@@ -77,7 +77,7 @@
       <h2>$i18n{setDefaultSubHeader}</h2>
       <div class="illustration"></div>
       <div class="button-bar">
-        <paper-button on-click="onDeclineClick_">
+        <paper-button id="decline-button" on-click="onDeclineClick_">
           $i18n{setDefaultSkip}
         </paper-button>
         <step-indicator model="[[indicatorModel]]"></step-indicator>
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js
index 68795f4..7e0c674 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js
+++ b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js
@@ -60,7 +60,7 @@
   onDeclineClick_: function() {
     if (this.finalized_)
       return;
-    this.finalized_ = true;
+
     this.browserProxy_.recordSkip();
     this.finished_();
   },
@@ -69,7 +69,7 @@
   onSetDefaultClick_: function() {
     if (this.finalized_)
       return;
-    this.finalized_ = true;
+
     this.browserProxy_.recordBeginSetDefault();
     this.browserProxy_.setAsDefault();
   },
@@ -88,6 +88,8 @@
 
   /** @private */
   finished_: function() {
+    this.finalized_ = true;
+
     welcome.navigateToNextStep();
   },
 });
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 1d1d47c..5fdc5156 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -94,6 +94,8 @@
       "safe_browsing_navigation_observer.h",
       "safe_browsing_navigation_observer_manager.cc",
       "safe_browsing_navigation_observer_manager.h",
+      "safe_browsing_navigation_throttle.cc",
+      "safe_browsing_navigation_throttle.h",
       "safe_browsing_service.cc",
       "safe_browsing_service.h",
       "services_delegate.h",
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 2fbcf07..6ac4a14 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -52,6 +53,7 @@
 #include "components/safe_browsing/renderer/threat_dom_details.h"
 #include "components/safe_browsing/web_ui/constants.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
+#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "components/security_interstitials/core/controller_client.h"
 #include "components/security_interstitials/core/metrics_helper.h"
 #include "components/security_interstitials/core/urls.h"
@@ -101,6 +103,10 @@
 const char kMaliciousIframe[] = "/safe_browsing/malware_iframe.html";
 const char kUnrelatedUrl[] = "https://www.google.com";
 
+bool AreCommittedMainFrameInterstitialsEnabled() {
+  return base::FeatureList::IsEnabled(kCommittedSBInterstitials);
+}
+
 // A SafeBrowsingDatabaseManager class that allows us to inject the malicious
 // URLs.
 class FakeSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
@@ -548,12 +554,19 @@
     ASSERT_FALSE(contents->ShowingInterstitialPage());
   }
 
-  bool YesInterstitial() {
+  bool IsShowingInterstitial() {
     WebContents* contents =
         browser()->tab_strip_model()->GetActiveWebContents();
-    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
-        contents);
-    return interstitial_page != NULL;
+    if (AreCommittedMainFrameInterstitialsEnabled()) {
+      security_interstitials::SecurityInterstitialTabHelper* helper =
+          security_interstitials::SecurityInterstitialTabHelper::
+              FromWebContents(contents);
+      return helper &&
+             (helper
+                  ->GetBlockingPageForCurrentlyCommittedNavigationForTesting() !=
+              nullptr);
+    }
+    return InterstitialPage::GetInterstitialPage(contents) != nullptr;
   }
 
   void SetReportSentCallback(const base::Closure& callback) {
@@ -607,6 +620,11 @@
 
   bool WaitForReady(Browser* browser) {
     WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
+    if (AreCommittedMainFrameInterstitialsEnabled()) {
+      if (!content::WaitForRenderFrameReady(contents->GetMainFrame()))
+        return false;
+      return IsShowingInterstitial();
+    }
     content::WaitForInterstitialAttach(contents);
     InterstitialPage* interstitial = contents->GetInterstitialPage();
     if (!interstitial)
@@ -840,7 +858,7 @@
   MalwareRedirectCancelAndProceed("openWin");
   // Clicking proceed won't do anything if the main request is cancelled
   // already.  See crbug.com/76460.
-  EXPECT_TRUE(YesInterstitial());
+  EXPECT_TRUE(IsShowingInterstitial());
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest, HardcodedUrls) {
@@ -917,7 +935,7 @@
   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
   EXPECT_EQ(interstitial_tab,
             browser()->tab_strip_model()->GetActiveWebContents());
-  EXPECT_TRUE(YesInterstitial());
+  EXPECT_TRUE(IsShowingInterstitial());
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest, Proceed) {
@@ -1272,7 +1290,7 @@
   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
   EXPECT_EQ(interstitial_tab,
             browser()->tab_strip_model()->GetActiveWebContents());
-  EXPECT_TRUE(YesInterstitial());
+  EXPECT_TRUE(IsShowingInterstitial());
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest,
@@ -1705,7 +1723,23 @@
   base::RunLoop().RunUntilIdle();
   WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::WaitForRenderFrameReady(contents->GetMainFrame()));
-  EXPECT_FALSE(YesInterstitial());
+  EXPECT_FALSE(IsShowingInterstitial());
+}
+
+// TODO(crbug.com/916683): Once interstitial bindings are hooked with committed
+// interstitials, all other tests should run with committed interstitials
+// enabled. At that point this test will become redundant and should be removed.
+// Test that an main frame interstitial is displayed with committed
+// interstitials enabled.
+IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest,
+                       CommittedInterstitialShows) {
+  base::test::ScopedFeatureList feature_list;
+  std::vector<base::Feature> enable;
+  enable.push_back(kCommittedSBInterstitials);
+  enable.push_back(kCheckByURLLoaderThrottle);
+  feature_list.InitWithFeatures(enable, std::vector<base::Feature>());
+  SetupWarningAndNavigate(browser());
+  EXPECT_TRUE(IsShowingInterstitial());
 }
 
 INSTANTIATE_TEST_CASE_P(
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_throttle.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_throttle.cc
new file mode 100644
index 0000000..850a5aa
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_throttle.cc
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/safe_browsing_navigation_throttle.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
+#include "components/security_interstitials/content/unsafe_resource.h"
+#include "content/public/browser/navigation_handle.h"
+
+namespace safe_browsing {
+
+SafeBrowsingNavigationThrottle::SafeBrowsingNavigationThrottle(
+    content::NavigationHandle* handle)
+    : content::NavigationThrottle(handle) {}
+
+const char* SafeBrowsingNavigationThrottle::GetNameForLogging() {
+  return "SafeBrowsingNavigationThrottle";
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+SafeBrowsingNavigationThrottle::WillFailRequest() {
+  SafeBrowsingService* service = g_browser_process->safe_browsing_service();
+  if (!service) {
+    return content::NavigationThrottle::PROCEED;
+  }
+
+  security_interstitials::UnsafeResource resource;
+  content::NavigationHandle* handle = navigation_handle();
+  scoped_refptr<SafeBrowsingUIManager> manager = service->ui_manager();
+
+  if (manager->PopUnsafeResourceForURL(handle->GetURL(), &resource)) {
+    SafeBrowsingBlockingPage* blocking_page =
+        SafeBrowsingBlockingPage::CreateBlockingPage(
+            manager.get(), handle->GetWebContents(), handle->GetURL(),
+            resource);
+    std::string error_page_content = blocking_page->GetHTMLContents();
+    security_interstitials::SecurityInterstitialTabHelper::
+        AssociateBlockingPage(handle->GetWebContents(),
+                              handle->GetNavigationId(),
+                              base::WrapUnique(blocking_page));
+
+    manager->AddToWhitelistUrlSet(handle->GetURL().GetWithEmptyPath(),
+                                  handle->GetWebContents(), true /* pending */,
+                                  resource.threat_type);
+
+    return content::NavigationThrottle::ThrottleCheckResult(
+        CANCEL, net::ERR_BLOCKED_BY_CLIENT, error_page_content);
+  }
+
+  return content::NavigationThrottle::PROCEED;
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_throttle.h b/chrome/browser/safe_browsing/safe_browsing_navigation_throttle.h
new file mode 100644
index 0000000..d3edcc2
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_throttle.h
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_NAVIGATION_THROTTLE_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_NAVIGATION_THROTTLE_H_
+
+#include "content/public/browser/navigation_throttle.h"
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
+
+namespace safe_browsing {
+
+// This throttle monitors failed requests, and if a request failed due to it
+// being blocked by Safe Browsing, it creates and displays an interstitial.
+// This throttle is only created when Safe Browsing committed interstitials are
+// enabled.
+class SafeBrowsingNavigationThrottle : public content::NavigationThrottle {
+ public:
+  explicit SafeBrowsingNavigationThrottle(content::NavigationHandle* handle);
+  ~SafeBrowsingNavigationThrottle() override {}
+  const char* GetNameForLogging() override;
+
+  content::NavigationThrottle::ThrottleCheckResult WillFailRequest() override;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_NAVIGATION_THROTTLE_H_
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc
index 606bd95..9b3104d 100644
--- a/chrome/browser/safe_browsing/ui_manager.cc
+++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -152,6 +152,26 @@
   observer_list_.RemoveObserver(observer);
 }
 
+void SafeBrowsingUIManager::AddUnsafeResource(
+    GURL url,
+    security_interstitials::UnsafeResource resource) {
+  unsafe_resources_.push_back(std::make_pair(url, resource));
+}
+
+bool SafeBrowsingUIManager::PopUnsafeResourceForURL(
+    GURL url,
+    security_interstitials::UnsafeResource* resource) {
+  for (auto it = unsafe_resources_.begin(); it != unsafe_resources_.end();
+       it++) {
+    if (it->first == url) {
+      *resource = it->second;
+      unsafe_resources_.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
 const std::string SafeBrowsingUIManager::app_locale() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return g_browser_process->GetApplicationLocale();
diff --git a/chrome/browser/safe_browsing/ui_manager.h b/chrome/browser/safe_browsing/ui_manager.h
index 073567a..4adf5d4 100644
--- a/chrome/browser/safe_browsing/ui_manager.h
+++ b/chrome/browser/safe_browsing/ui_manager.h
@@ -17,6 +17,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "components/safe_browsing/base_ui_manager.h"
+#include "components/security_interstitials/content/unsafe_resource.h"
 
 class GURL;
 
@@ -88,6 +89,20 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* remove);
 
+  // Adds an UnsafeResource |resource| for |url| to unsafe_resources_,
+  // this should be called by the UrlCheckerDelegate whenever a resource load
+  // is blocked due to a SB hit.
+  void AddUnsafeResource(GURL url,
+                         security_interstitials::UnsafeResource resource);
+
+  // Checks if an UnsafeResource |resource| exists for |url|, if so, it is
+  // removed from the vector, assigned to |resource| and the function returns
+  // true. Otherwise the function returns false and nothing gets assigned to
+  // |resource|.
+  bool PopUnsafeResourceForURL(
+      GURL url,
+      security_interstitials::UnsafeResource* resource);
+
   const std::string app_locale() const override;
   history::HistoryService* history_service(
       content::WebContents* web_contents) override;
@@ -119,6 +134,12 @@
   // Safebrowsing service.
   scoped_refptr<SafeBrowsingService> sb_service_;
 
+  // Stores unsafe resources so they can be fetched from a navigation throttle
+  // in the committed interstitials flow. Implemented as a pair vector since
+  // most of the time it will be empty or contain a single element.
+  std::vector<std::pair<GURL, security_interstitials::UnsafeResource>>
+      unsafe_resources_;
+
   base::ObserverList<Observer>::Unchecked observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUIManager);
diff --git a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
index fd0bba50..77207ca 100644
--- a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
+++ b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/task/post_task.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/data_reduction_proxy_util.h"
 #include "chrome/browser/prerender/prerender_contents.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
@@ -99,6 +100,7 @@
     bool has_user_gesture) {
   if (base::FeatureList::IsEnabled(kCommittedSBInterstitials) &&
       is_main_frame) {
+    ui_manager_->AddUnsafeResource(resource.url, resource);
     // With committed interstitials we just cancel the load from here, the
     // actual interstitial will be shown from the
     // SafeBrowsingNavigationThrottle.
diff --git a/chrome/browser/ui/views/autofill/migratable_card_view.cc b/chrome/browser/ui/views/autofill/migratable_card_view.cc
index 97e7e4b..bd89dde 100644
--- a/chrome/browser/ui/views/autofill/migratable_card_view.cc
+++ b/chrome/browser/ui/views/autofill/migratable_card_view.cc
@@ -126,7 +126,7 @@
     case MigratableCreditCard::MigrationStatus::FAILURE_ON_UPLOAD: {
       auto* migration_failed_image = new views::ImageView();
       migration_failed_image->SetImage(
-          gfx::CreateVectorIcon(kBrowserToolsErrorIcon,
+          gfx::CreateVectorIcon(vector_icons::kErrorIcon,
                                 kMigrationResultImageSize, gfx::kGoogleRed700));
       migratable_card_description_view->AddChildView(migration_failed_image);
       break;
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index dbebf5d4..f62f7be 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -610,7 +610,7 @@
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   if (url.host_piece() == chrome::kChromeUIPrintHost &&
       !profile->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled)) {
-    return &NewWebUI<PrintPreviewUI>;
+    return &NewWebUI<printing::PrintPreviewUI>;
   }
 #endif
 #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY)
diff --git a/chrome/browser/ui/webui/print_preview/cloud_printer_handler.cc b/chrome/browser/ui/webui/print_preview/cloud_printer_handler.cc
index 97763541..d3a513c 100644
--- a/chrome/browser/ui/webui/print_preview/cloud_printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/cloud_printer_handler.cc
@@ -4,12 +4,14 @@
 
 #include "chrome/browser/ui/webui/print_preview/cloud_printer_handler.h"
 
-#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/values.h"
 
+namespace printing {
+
 CloudPrinterHandler::CloudPrinterHandler() {}
 
 CloudPrinterHandler::~CloudPrinterHandler() {}
@@ -40,3 +42,5 @@
   // TODO(https://crbug.com/829414): Print to cloud print
   NOTIMPLEMENTED();
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/cloud_printer_handler.h b/chrome/browser/ui/webui/print_preview/cloud_printer_handler.h
index 64d469a..381b913c 100644
--- a/chrome/browser/ui/webui/print_preview/cloud_printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/cloud_printer_handler.h
@@ -11,6 +11,8 @@
 #include "base/macros.h"
 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
 
+namespace printing {
+
 // Implementation of PrinterHandler interface
 class CloudPrinterHandler : public PrinterHandler {
  public:
@@ -35,4 +37,7 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(CloudPrinterHandler);
 };
+
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_CLOUD_PRINTER_HANDLER_H_
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc
index a852ea25..c293f55 100644
--- a/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc
@@ -42,7 +42,8 @@
 using extensions::ExtensionRegistry;
 using extensions::ListBuilder;
 using extensions::UsbPrinterManifestData;
-using printing::PwgRasterConverter;
+
+namespace printing {
 
 namespace {
 
@@ -241,7 +242,7 @@
   if (!pwg_raster_converter_)
     pwg_raster_converter_ = PwgRasterConverter::CreateDefault();
 
-  printing::PwgRasterSettings bitmap_settings =
+  PwgRasterSettings bitmap_settings =
       PwgRasterConverter::GetBitmapSettings(printer_description, ticket);
   pwg_raster_converter_->Start(
       data.get(),
@@ -286,10 +287,10 @@
     const base::DictionaryValue& capability) {
   base::Value capabilities(base::Value::Type::DICTIONARY);
   std::unique_ptr<base::DictionaryValue> cdd =
-      printing::ValidateCddForPrintPreview(capability);
+      ValidateCddForPrintPreview(capability);
   // Leave |capabilities| empty if |cdd| is empty.
   if (!cdd->empty()) {
-    capabilities.SetKey(printing::kSettingCapabilities,
+    capabilities.SetKey(kSettingCapabilities,
                         base::Value::FromUniquePtrValue(std::move(cdd)));
   }
   std::move(callback).Run(std::move(capabilities));
@@ -360,3 +361,5 @@
   if (pending_enumeration_count_ == 0)
     std::move(done_callback_).Run();
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler.h b/chrome/browser/ui/webui/print_preview/extension_printer_handler.h
index 6259a19..7485fff 100644
--- a/chrome/browser/ui/webui/print_preview/extension_printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler.h
@@ -21,8 +21,6 @@
 class RefCountedMemory;
 }
 
-class Profile;
-
 namespace cloud_devices {
 class CloudDeviceDescription;
 }
@@ -35,9 +33,11 @@
 class Size;
 }
 
+class Profile;
+
 namespace printing {
+
 class PwgRasterConverter;
-}
 
 // Implementation of PrinterHandler interface backed by printerProvider
 // extension API.
@@ -70,7 +70,7 @@
   friend class ExtensionPrinterHandlerTest;
 
   void SetPwgRasterConverterForTesting(
-      std::unique_ptr<printing::PwgRasterConverter> pwg_raster_converter);
+      std::unique_ptr<PwgRasterConverter> pwg_raster_converter);
 
   // Converts |data| to PWG raster format (from PDF) for a printer described
   // by |printer_description|.
@@ -107,7 +107,7 @@
   Profile* const profile_;
   GetPrintersDoneCallback done_callback_;
   PrintJobCallback print_job_callback_;
-  std::unique_ptr<printing::PwgRasterConverter> pwg_raster_converter_;
+  std::unique_ptr<PwgRasterConverter> pwg_raster_converter_;
   int pending_enumeration_count_ = 0;
 
   base::WeakPtrFactory<ExtensionPrinterHandler> weak_ptr_factory_;
@@ -115,4 +115,6 @@
   DISALLOW_COPY_AND_ASSIGN(ExtensionPrinterHandler);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_EXTENSION_PRINTER_HANDLER_H_
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
index 9768d56b..586847c0 100644
--- a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
@@ -50,7 +50,8 @@
 using extensions::PrinterProviderAPI;
 using extensions::PrinterProviderPrintJob;
 using extensions::TestExtensionEnvironment;
-using printing::PwgRasterConverter;
+
+namespace printing {
 
 namespace {
 
@@ -214,7 +215,7 @@
   ++(*call_count);
   const base::Value* capabilities = nullptr;
   if (capability.is_dict()) {
-    capabilities = capability.FindKeyOfType(printing::kSettingCapabilities,
+    capabilities = capability.FindKeyOfType(kSettingCapabilities,
                                             base::Value::Type::DICTIONARY);
   }
   *capability_out =
@@ -282,8 +283,8 @@
   // PwgRasterConverter implementation. It writes |data| to shared memory.
   // Also, remembers conversion and bitmap settings passed into the method.
   void Start(const base::RefCountedMemory* data,
-             const printing::PdfRenderSettings& conversion_settings,
-             const printing::PwgRasterSettings& bitmap_settings,
+             const PdfRenderSettings& conversion_settings,
+             const PwgRasterSettings& bitmap_settings,
              ResultCallback callback) override {
     base::ReadOnlySharedMemoryRegion invalid_pwg_region;
     if (fail_conversion_) {
@@ -308,17 +309,15 @@
   // Makes |Start| method always return an error.
   void FailConversion() { fail_conversion_ = true; }
 
-  const printing::PdfRenderSettings& conversion_settings() const {
+  const PdfRenderSettings& conversion_settings() const {
     return conversion_settings_;
   }
 
-  const printing::PwgRasterSettings& bitmap_settings() const {
-    return bitmap_settings_;
-  }
+  const PwgRasterSettings& bitmap_settings() const { return bitmap_settings_; }
 
  private:
-  printing::PdfRenderSettings conversion_settings_;
-  printing::PwgRasterSettings bitmap_settings_;
+  PdfRenderSettings conversion_settings_;
+  PwgRasterSettings bitmap_settings_;
   bool fail_conversion_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(FakePwgRasterConverter);
@@ -778,13 +777,13 @@
   ASSERT_TRUE(fake_api);
   ASSERT_EQ(1u, fake_api->pending_print_count());
 
-  EXPECT_EQ(printing::TRANSFORM_NORMAL,
+  EXPECT_EQ(TRANSFORM_NORMAL,
             pwg_raster_converter_->bitmap_settings().odd_page_transform);
   EXPECT_FALSE(pwg_raster_converter_->bitmap_settings().rotate_all_pages);
   EXPECT_FALSE(pwg_raster_converter_->bitmap_settings().reverse_page_order);
   EXPECT_TRUE(pwg_raster_converter_->bitmap_settings().use_color);
 
-  EXPECT_EQ(gfx::Size(printing::kDefaultPdfDpi, printing::kDefaultPdfDpi),
+  EXPECT_EQ(gfx::Size(kDefaultPdfDpi, kDefaultPdfDpi),
             pwg_raster_converter_->conversion_settings().dpi);
   EXPECT_TRUE(pwg_raster_converter_->conversion_settings().autorotate);
   // size = vertically_oriented_size * vertical_dpi / points_per_inch x
@@ -832,7 +831,7 @@
   ASSERT_TRUE(fake_api);
   ASSERT_EQ(1u, fake_api->pending_print_count());
 
-  EXPECT_EQ(printing::TRANSFORM_FLIP_VERTICAL,
+  EXPECT_EQ(TRANSFORM_FLIP_VERTICAL,
             pwg_raster_converter_->bitmap_settings().odd_page_transform);
   EXPECT_TRUE(pwg_raster_converter_->bitmap_settings().rotate_all_pages);
   EXPECT_TRUE(pwg_raster_converter_->bitmap_settings().reverse_page_order);
@@ -998,3 +997,5 @@
   EXPECT_EQ(0u, call_count);
   EXPECT_FALSE(printer_info.get());
 }
+
+}  // namespace printing
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 4408032..b759de476 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
@@ -32,6 +32,8 @@
 #include "printing/backend/print_backend_consts.h"
 #include "printing/backend/printing_restrictions.h"
 
+namespace printing {
+
 namespace {
 
 using chromeos::CupsPrintersManager;
@@ -41,8 +43,8 @@
 // as the system_driverinfo option value, and the Printer#display_name in
 // the |printer_description| field.  This will match how Mac OS X presents
 // printer information.
-printing::PrinterBasicInfo ToBasicInfo(const chromeos::Printer& printer) {
-  printing::PrinterBasicInfo basic_info;
+PrinterBasicInfo ToBasicInfo(const chromeos::Printer& printer) {
+  PrinterBasicInfo basic_info;
 
   // TODO(skau): Unify Mac with the other platforms for display name
   // presentation so I can remove this strange code.
@@ -56,7 +58,7 @@
 }
 
 void AddPrintersToList(const std::vector<chromeos::Printer>& printers,
-                       printing::PrinterList* list) {
+                       PrinterList* list) {
   for (const auto& printer : printers) {
     list->push_back(ToBasicInfo(printer));
   }
@@ -65,8 +67,8 @@
 void CapabilitiesFetched(base::DictionaryValue policies,
                          LocalPrinterHandlerChromeos::GetCapabilityCallback cb,
                          std::unique_ptr<base::DictionaryValue> printer_info) {
-  printer_info->FindKey(printing::kPrinter)
-      ->SetKey(printing::kSettingPolicies, std::move(policies));
+  printer_info->FindKey(kPrinter)->SetKey(kSettingPolicies,
+                                          std::move(policies));
   std::move(cb).Run(std::move(*printer_info));
 }
 
@@ -75,13 +77,12 @@
                        LocalPrinterHandlerChromeos::GetCapabilityCallback cb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  printing::PrinterBasicInfo basic_info = ToBasicInfo(*printer);
+  PrinterBasicInfo basic_info = ToBasicInfo(*printer);
 
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
-      base::BindOnce(
-          &printing::GetSettingsOnBlockingPool, printer->id(), basic_info,
-          printing::PrinterSemanticCapsAndDefaults::Papers(), nullptr),
+      base::BindOnce(&GetSettingsOnBlockingPool, printer->id(), basic_info,
+                     PrinterSemanticCapsAndDefaults::Papers(), nullptr),
       base::BindOnce(&CapabilitiesFetched, std::move(policies), std::move(cb)));
 }
 
@@ -123,7 +124,7 @@
   // thread.
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  printing::PrinterList printer_list;
+  PrinterList printer_list;
   AddPrintersToList(
       printers_manager_->GetPrinters(CupsPrintersManager::kConfigured),
       &printer_list);
@@ -134,8 +135,8 @@
       printers_manager_->GetPrinters(CupsPrintersManager::kAutomatic),
       &printer_list);
 
-  printing::ConvertPrinterListForCallback(
-      added_printers_callback, std::move(done_callback), printer_list);
+  ConvertPrinterListForCallback(added_printers_callback,
+                                std::move(done_callback), printer_list);
 }
 
 void LocalPrinterHandlerChromeos::StartGetCapability(
@@ -184,19 +185,17 @@
       printers_manager_->PrinterInstalled(*printer, true /*is_automatic*/);
 
       // populate |policies| with policies for native printers.
+      auto* prefs = profile_->GetPrefs();
       base::DictionaryValue policies;
+      policies.SetInteger(kAllowedColorModes,
+                          prefs->GetInteger(prefs::kPrintingAllowedColorModes));
       policies.SetInteger(
-          printing::kAllowedColorModes,
-          profile_->GetPrefs()->GetInteger(prefs::kPrintingAllowedColorModes));
-      policies.SetInteger(
-          printing::kAllowedDuplexModes,
-          profile_->GetPrefs()->GetInteger(prefs::kPrintingAllowedDuplexModes));
-      policies.SetInteger(
-          printing::kDefaultColorMode,
-          profile_->GetPrefs()->GetInteger(prefs::kPrintingColorDefault));
-      policies.SetInteger(
-          printing::kDefaultDuplexMode,
-          profile_->GetPrefs()->GetInteger(prefs::kPrintingDuplexDefault));
+          kAllowedDuplexModes,
+          prefs->GetInteger(prefs::kPrintingAllowedDuplexModes));
+      policies.SetInteger(kDefaultColorMode,
+                          prefs->GetInteger(prefs::kPrintingColorDefault));
+      policies.SetInteger(kDefaultDuplexMode,
+                          prefs->GetInteger(prefs::kPrintingDuplexDefault));
       // fetch settings on the blocking pool and invoke callback.
       FetchCapabilities(std::move(printer), std::move(policies), std::move(cb));
       return;
@@ -241,6 +240,8 @@
   size_t size_in_kb = print_data->size() / 1024;
   UMA_HISTOGRAM_MEMORY_KB("Printing.CUPS.PrintDocumentSize", size_in_kb);
 
-  printing::StartLocalPrint(ticket_json, print_data, preview_web_contents_,
-                            std::move(callback));
+  StartLocalPrint(ticket_json, print_data, preview_web_contents_,
+                  std::move(callback));
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
index 07ec869..0658c38 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
@@ -23,6 +23,8 @@
 
 class Profile;
 
+namespace printing {
+
 class LocalPrinterHandlerChromeos : public PrinterHandler {
  public:
   LocalPrinterHandlerChromeos(Profile* profile,
@@ -59,4 +61,6 @@
   DISALLOW_COPY_AND_ASSIGN(LocalPrinterHandlerChromeos);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_LOCAL_PRINTER_HANDLER_CHROMEOS_H_
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 c80280b48..d7b287c 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
@@ -22,30 +22,30 @@
 #include "components/printing/common/printer_capabilities_mac.h"
 #endif
 
+namespace printing {
+
 namespace {
 
-printing::PrinterList EnumeratePrintersAsync() {
+PrinterList EnumeratePrintersAsync() {
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  scoped_refptr<printing::PrintBackend> print_backend(
-      printing::PrintBackend::CreateInstance(nullptr));
+  scoped_refptr<PrintBackend> print_backend(
+      PrintBackend::CreateInstance(nullptr));
 
-  printing::PrinterList printer_list;
+  PrinterList printer_list;
   print_backend->EnumeratePrinters(&printer_list);
   return printer_list;
 }
 
 base::Value FetchCapabilitiesAsync(const std::string& device_name) {
-  printing::PrinterSemanticCapsAndDefaults::Papers additional_papers;
+  PrinterSemanticCapsAndDefaults::Papers additional_papers;
 #if defined(OS_MACOSX)
-  if (base::FeatureList::IsEnabled(
-          printing::features::kEnableCustomMacPaperSizes)) {
-    additional_papers = printing::GetMacCustomPaperSizes();
-  }
+  if (base::FeatureList::IsEnabled(features::kEnableCustomMacPaperSizes))
+    additional_papers = GetMacCustomPaperSizes();
 #endif
 
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  scoped_refptr<printing::PrintBackend> print_backend(
-      printing::PrintBackend::CreateInstance(nullptr));
+  scoped_refptr<PrintBackend> print_backend(
+      PrintBackend::CreateInstance(nullptr));
 
   VLOG(1) << "Get printer capabilities start for " << device_name;
 
@@ -54,18 +54,18 @@
     return base::Value();
   }
 
-  printing::PrinterBasicInfo basic_info;
+  PrinterBasicInfo basic_info;
   if (!print_backend->GetPrinterBasicInfo(device_name, &basic_info))
     return base::Value();
 
-  return std::move(*printing::GetSettingsOnBlockingPool(
+  return std::move(*GetSettingsOnBlockingPool(
       device_name, basic_info, additional_papers, print_backend));
 }
 
 std::string GetDefaultPrinterAsync() {
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  scoped_refptr<printing::PrintBackend> print_backend(
-      printing::PrintBackend::CreateInstance(nullptr));
+  scoped_refptr<PrintBackend> print_backend(
+      PrintBackend::CreateInstance(nullptr));
 
   std::string default_printer = print_backend->GetDefaultPrinterName();
   VLOG(1) << "Default Printer: " << default_printer;
@@ -101,7 +101,7 @@
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
       base::BindOnce(&EnumeratePrintersAsync),
-      base::BindOnce(&printing::ConvertPrinterListForCallback, callback,
+      base::BindOnce(&ConvertPrinterListForCallback, callback,
                      std::move(done_callback)));
 }
 
@@ -124,6 +124,8 @@
     const gfx::Size& page_size,
     const scoped_refptr<base::RefCountedMemory>& print_data,
     PrintCallback callback) {
-  printing::StartLocalPrint(ticket_json, print_data, preview_web_contents_,
-                            std::move(callback));
+  StartLocalPrint(ticket_json, print_data, preview_web_contents_,
+                  std::move(callback));
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.h b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.h
index a9da375..aaa992d 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.h
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.h
@@ -18,6 +18,8 @@
 class WebContents;
 }
 
+namespace printing {
+
 class LocalPrinterHandlerDefault : public PrinterHandler {
  public:
   explicit LocalPrinterHandlerDefault(
@@ -45,4 +47,6 @@
   DISALLOW_COPY_AND_ASSIGN(LocalPrinterHandlerDefault);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_LOCAL_PRINTER_HANDLER_DEFAULT_H_
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
index c71f8bc..393aa21 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
@@ -39,11 +39,13 @@
 #include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
+namespace printing {
+
 namespace {
 
 constexpr base::FilePath::CharType kPdfExtension[] = FILE_PATH_LITERAL("pdf");
 
-class PrintingContextDelegate : public printing::PrintingContext::Delegate {
+class PrintingContextDelegate : public PrintingContext::Delegate {
  public:
   // PrintingContext::Delegate methods.
   gfx::NativeView GetParentView() override { return NULL; }
@@ -54,15 +56,14 @@
 
 gfx::Size GetDefaultPdfMediaSizeMicrons() {
   PrintingContextDelegate delegate;
-  std::unique_ptr<printing::PrintingContext> printing_context(
-      printing::PrintingContext::Create(&delegate));
-  if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
+  auto printing_context(PrintingContext::Create(&delegate));
+  if (PrintingContext::OK != printing_context->UsePdfSettings() ||
       printing_context->settings().device_units_per_inch() <= 0) {
     return gfx::Size();
   }
   gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
   float device_microns_per_device_unit =
-      static_cast<float>(printing::kMicronsPerInch) /
+      static_cast<float>(kMicronsPerInch) /
       printing_context->settings().device_units_per_inch();
   return gfx::Size(pdf_media_size.width() * device_microns_per_device_unit,
                    pdf_media_size.height() * device_microns_per_device_unit);
@@ -82,7 +83,7 @@
   ColorCapability color;
   {
     Color standard_color(STANDARD_COLOR);
-    standard_color.vendor_id = base::IntToString(printing::COLOR);
+    standard_color.vendor_id = base::IntToString(COLOR);
     color.AddDefaultOption(standard_color, true);
   }
   color.SaveTo(&description);
@@ -145,7 +146,7 @@
 
 PdfPrinterHandler::PdfPrinterHandler(Profile* profile,
                                      content::WebContents* preview_web_contents,
-                                     printing::StickySettings* sticky_settings)
+                                     StickySettings* sticky_settings)
     : preview_web_contents_(preview_web_contents),
       profile_(profile),
       sticky_settings_(sticky_settings),
@@ -169,9 +170,8 @@
 void PdfPrinterHandler::StartGetCapability(const std::string& destination_id,
                                            GetCapabilityCallback callback) {
   base::Value printer_info(base::Value::Type::DICTIONARY);
-  printer_info.SetKey(printing::kSettingDeviceName,
-                      base::Value(destination_id));
-  printer_info.SetKey(printing::kSettingCapabilities,
+  printer_info.SetKey(kSettingDeviceName, base::Value(destination_id));
+  printer_info.SetKey(kSettingCapabilities,
                       std::move(*GetPdfCapabilities(
                           g_browser_process->GetApplicationLocale())));
   std::move(callback).Run(std::move(printer_info));
@@ -202,8 +202,8 @@
   DCHECK(!print_callback_);
   print_callback_ = std::move(callback);
 
-  printing::PrintPreviewDialogController* dialog_controller =
-      printing::PrintPreviewDialogController::GetInstance();
+  PrintPreviewDialogController* dialog_controller =
+      PrintPreviewDialogController::GetInstance();
   content::WebContents* initiator =
       dialog_controller ? dialog_controller->GetInitiator(preview_web_contents_)
                         : nullptr;
@@ -387,3 +387,5 @@
       &file_type_info, 0, base::FilePath::StringType(),
       platform_util::GetTopLevel(preview_web_contents_->GetNativeView()), NULL);
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
index 0fb1a7b..7bb8bc97 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
@@ -34,12 +34,14 @@
 class GURL;
 class Profile;
 
+namespace printing {
+
 class PdfPrinterHandler : public PrinterHandler,
                           public ui::SelectFileDialog::Listener {
  public:
   PdfPrinterHandler(Profile* profile,
                     content::WebContents* preview_web_contents,
-                    printing::StickySettings* sticky_settings);
+                    StickySettings* sticky_settings);
 
   ~PdfPrinterHandler() override;
 
@@ -96,7 +98,7 @@
                            const base::FilePath& directory);
 
   Profile* const profile_;
-  printing::StickySettings* const sticky_settings_;
+  StickySettings* const sticky_settings_;
 
   // Holds the path to the print to pdf request. It is empty if no such request
   // exists.
@@ -117,4 +119,6 @@
   DISALLOW_COPY_AND_ASSIGN(PdfPrinterHandler);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PDF_PRINTER_HANDLER_H_
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/pdf_printer_handler_unittest.cc
index 4393bc3..3272c55 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler_unittest.cc
@@ -11,6 +11,8 @@
 
 #define FPL(x) FILE_PATH_LITERAL(x)
 
+namespace printing {
+
 using PdfPrinterHandlerTest = testing::Test;
 
 TEST_F(PdfPrinterHandlerTest, GetFileNameForPrintJobTitle) {
@@ -102,3 +104,5 @@
     EXPECT_EQ(data.expected_output, path.value());
   }
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler_win_unittest.cc b/chrome/browser/ui/webui/print_preview/pdf_printer_handler_win_unittest.cc
index 03e57126..6038b4a9 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler_win_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler_win_unittest.cc
@@ -20,6 +20,8 @@
 
 using content::WebContents;
 
+namespace printing {
+
 namespace {
 
 void ExecuteCancelledSelectFileDialog(
@@ -39,7 +41,7 @@
  public:
   FakePdfPrinterHandler(Profile* profile,
                         content::WebContents* contents,
-                        printing::StickySettings* sticky_settings)
+                        StickySettings* sticky_settings)
       : PdfPrinterHandler(profile, contents, sticky_settings),
         save_failed_(false) {}
 
@@ -126,3 +128,5 @@
       L"1111111111111111111111111111111111111111111111111.html");
   EXPECT_TRUE(pdf_printer_->save_failed());
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 4b7e70a..87977229 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -89,8 +89,8 @@
 
 using content::RenderFrameHost;
 using content::WebContents;
-using printing::PrintViewManager;
-using printing::PrinterType;
+
+namespace printing {
 
 namespace {
 
@@ -321,19 +321,16 @@
   // from the print ticket, as they may have dummy values in the preview
   // request.
   const base::ListValue* page_range_array = NULL;
-  if (preview_settings.GetList(printing::kSettingPageRange,
-                               &page_range_array) &&
+  if (preview_settings.GetList(kSettingPageRange, &page_range_array) &&
       !page_range_array->empty()) {
     ReportPrintSettingHistogram(PAGE_RANGE);
   }
 
   const base::DictionaryValue* media_size_value = NULL;
-  if (preview_settings.GetDictionary(printing::kSettingMediaSize,
-                                     &media_size_value) &&
+  if (preview_settings.GetDictionary(kSettingMediaSize, &media_size_value) &&
       !media_size_value->empty()) {
     bool is_default = false;
-    if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault,
-                                     &is_default) &&
+    if (media_size_value->GetBoolean(kSettingMediaSizeIsDefault, &is_default) &&
         is_default) {
       ReportPrintSettingHistogram(DEFAULT_MEDIA);
     } else {
@@ -342,92 +339,86 @@
   }
 
   bool landscape = false;
-  if (preview_settings.GetBoolean(printing::kSettingLandscape, &landscape))
+  if (preview_settings.GetBoolean(kSettingLandscape, &landscape))
     ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
 
   int copies = 1;
-  if (print_settings.GetInteger(printing::kSettingCopies, &copies) &&
-      copies > 1) {
+  if (print_settings.GetInteger(kSettingCopies, &copies) && copies > 1) {
     ReportPrintSettingHistogram(COPIES);
   }
 
   int scaling = 100;
-  if (preview_settings.GetInteger(printing::kSettingScaleFactor, &scaling) &&
+  if (preview_settings.GetInteger(kSettingScaleFactor, &scaling) &&
       scaling != 100) {
     ReportPrintSettingHistogram(SCALING);
   }
 
   int pages_per_sheet = 1;
-  if (preview_settings.GetInteger(printing::kSettingPagesPerSheet,
-                                  &pages_per_sheet) &&
+  if (preview_settings.GetInteger(kSettingPagesPerSheet, &pages_per_sheet) &&
       pages_per_sheet != 1) {
     ReportPrintSettingHistogram(PAGES_PER_SHEET);
   }
 
   bool collate = false;
-  if (print_settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
+  if (print_settings.GetBoolean(kSettingCollate, &collate) && collate)
     ReportPrintSettingHistogram(COLLATE);
 
   int duplex_mode = 0;
-  if (print_settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
+  if (print_settings.GetInteger(kSettingDuplexMode, &duplex_mode))
     ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
 
   int color_mode = 0;
-  if (print_settings.GetInteger(printing::kSettingColor, &color_mode)) {
+  if (print_settings.GetInteger(kSettingColor, &color_mode)) {
     ReportPrintSettingHistogram(
-        printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
+        IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
   }
 
   int margins_type = 0;
-  if (preview_settings.GetInteger(printing::kSettingMarginsType,
-                                  &margins_type) &&
+  if (preview_settings.GetInteger(kSettingMarginsType, &margins_type) &&
       margins_type != 0) {
     ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
   }
 
   bool headers = false;
-  if (preview_settings.GetBoolean(printing::kSettingHeaderFooterEnabled,
-                                  &headers) &&
+  if (preview_settings.GetBoolean(kSettingHeaderFooterEnabled, &headers) &&
       headers) {
     ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
   }
 
   bool css_background = false;
-  if (preview_settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
+  if (preview_settings.GetBoolean(kSettingShouldPrintBackgrounds,
                                   &css_background) &&
       css_background) {
     ReportPrintSettingHistogram(CSS_BACKGROUND);
   }
 
   bool selection_only = false;
-  if (preview_settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
+  if (preview_settings.GetBoolean(kSettingShouldPrintSelectionOnly,
                                   &selection_only) &&
       selection_only) {
     ReportPrintSettingHistogram(SELECTION_ONLY);
   }
 
   bool rasterize = false;
-  if (preview_settings.GetBoolean(printing::kSettingRasterizePdf, &rasterize) &&
+  if (preview_settings.GetBoolean(kSettingRasterizePdf, &rasterize) &&
       rasterize) {
     ReportPrintSettingHistogram(PRINT_AS_IMAGE);
   }
 
   bool fit_to_page = false;
   if (is_pdf &&
-      preview_settings.GetBoolean(printing::kSettingFitToPageEnabled,
-                                  &fit_to_page) &&
+      preview_settings.GetBoolean(kSettingFitToPageEnabled, &fit_to_page) &&
       fit_to_page) {
     ReportPrintSettingHistogram(FIT_TO_PAGE);
   }
 
   int dpi_horizontal = 0;
   int dpi_vertical = 0;
-  if (print_settings.GetInteger(printing::kSettingDpiHorizontal,
-                                &dpi_horizontal) &&
-      print_settings.GetInteger(printing::kSettingDpiVertical, &dpi_vertical) &&
+  if (print_settings.GetInteger(kSettingDpiHorizontal, &dpi_horizontal) &&
+      print_settings.GetInteger(kSettingDpiVertical, &dpi_vertical) &&
       dpi_horizontal > 0 && dpi_vertical > 0) {
     bool is_default = false;
-    if (print_settings.GetBoolean(printing::kSettingDpiDefault, &is_default))
+    if (print_settings.GetBoolean(kSettingDpiDefault, &is_default))
       ReportPrintSettingHistogram(is_default ? DEFAULT_DPI : NON_DEFAULT_DPI);
   }
 }
@@ -435,36 +426,36 @@
 UserActionBuckets DetermineUserAction(const base::DictionaryValue& settings) {
   bool value = false;
 #if defined(OS_MACOSX)
-  value = settings.HasKey(printing::kSettingOpenPDFInPreview);
+  value = settings.HasKey(kSettingOpenPDFInPreview);
 #endif
   if (value)
     return OPEN_IN_MAC_PREVIEW;
   // This needs to be checked before checking for a cloud print ID, since a
   // print ticket for printing to Drive will also contain a cloud print ID.
-  settings.GetBoolean(printing::kSettingPrintToGoogleDrive, &value);
+  settings.GetBoolean(kSettingPrintToGoogleDrive, &value);
   if (value)
     return PRINT_TO_GOOGLE_DRIVE;
-  if (settings.HasKey(printing::kSettingCloudPrintId))
+  if (settings.HasKey(kSettingCloudPrintId))
     return PRINT_WITH_CLOUD_PRINT;
-  settings.GetBoolean(printing::kSettingPrintWithPrivet, &value);
+  settings.GetBoolean(kSettingPrintWithPrivet, &value);
   if (value)
     return PRINT_WITH_PRIVET;
-  settings.GetBoolean(printing::kSettingPrintWithExtension, &value);
+  settings.GetBoolean(kSettingPrintWithExtension, &value);
   if (value)
     return PRINT_WITH_EXTENSION;
-  settings.GetBoolean(printing::kSettingPrintToPDF, &value);
+  settings.GetBoolean(kSettingPrintToPDF, &value);
   if (value)
     return PRINT_TO_PDF;
-  settings.GetBoolean(printing::kSettingShowSystemDialog, &value);
+  settings.GetBoolean(kSettingShowSystemDialog, &value);
   if (value)
     return FALLBACK_TO_ADVANCED_SETTINGS_DIALOG;
   return PRINT_TO_PRINTER;
 }
 
-base::LazyInstance<printing::StickySettings>::DestructorAtExit
-    g_sticky_settings = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<StickySettings>::DestructorAtExit g_sticky_settings =
+    LAZY_INSTANCE_INITIALIZER;
 
-printing::StickySettings* GetStickySettings() {
+StickySettings* GetStickySettings() {
   return g_sticky_settings.Pointer();
 }
 
@@ -769,7 +760,7 @@
       GetSettingsDictionary(json_str);
   CHECK(settings);
   int request_id = -1;
-  settings->GetInteger(printing::kPreviewRequestID, &request_id);
+  settings->GetInteger(kPreviewRequestID, &request_id);
   CHECK_GT(request_id, -1);
 
   CHECK(!base::ContainsKey(preview_callbacks_, request_id));
@@ -777,7 +768,7 @@
   print_preview_ui()->OnPrintPreviewRequest(request_id);
   // Add an additional key in order to identify |print_preview_ui| later on
   // when calling PrintPreviewUI::ShouldCancelRequest() on the IO thread.
-  settings->SetInteger(printing::kPreviewUIID,
+  settings->SetInteger(kPreviewUIID,
                        print_preview_ui()->GetIDForPrintPreviewUI().value());
 
   // Increment request count.
@@ -797,18 +788,17 @@
   // Retrieve the page title and url and send it to the renderer process if
   // headers and footers are to be displayed.
   bool display_header_footer = false;
-  bool success = settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
-                                      &display_header_footer);
+  bool success =
+      settings->GetBoolean(kSettingHeaderFooterEnabled, &display_header_footer);
   DCHECK(success);
   if (display_header_footer) {
-    settings->SetString(printing::kSettingHeaderFooterTitle,
-                        initiator->GetTitle());
+    settings->SetString(kSettingHeaderFooterTitle, initiator->GetTitle());
 
     url::Replacements<char> url_sanitizer;
     url_sanitizer.ClearUsername();
     url_sanitizer.ClearPassword();
     const GURL& initiator_url = initiator->GetLastCommittedURL();
-    settings->SetString(printing::kSettingHeaderFooterURL,
+    settings->SetString(kSettingHeaderFooterURL,
                         url_formatter::FormatUrl(
                             initiator_url.ReplaceComponents(url_sanitizer)));
   }
@@ -840,7 +830,7 @@
   const UserActionBuckets user_action = DetermineUserAction(*settings);
 
   int page_count = 0;
-  if (!settings->GetInteger(printing::kSettingPreviewPageCount, &page_count) ||
+  if (!settings->GetInteger(kSettingPreviewPageCount, &page_count) ||
       page_count <= 0) {
     RejectJavascriptCallback(base::Value(callback_id),
                              GetErrorValue(user_action, "NO_PAGE_COUNT"));
@@ -849,7 +839,7 @@
 
   scoped_refptr<base::RefCountedMemory> data;
   print_preview_ui()->GetPrintPreviewDataForIndex(
-      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
+      COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
   if (!data) {
     // Nothing to print, no preview available.
     RejectJavascriptCallback(base::Value(callback_id),
@@ -865,12 +855,12 @@
   int width = 0;
   int height = 0;
   if (user_action == PRINT_WITH_PRIVET || user_action == PRINT_WITH_EXTENSION) {
-    if (!settings->GetString(printing::kSettingDeviceName, &destination_id) ||
-        !settings->GetString(printing::kSettingTicket, &print_ticket) ||
-        !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
-        !settings->GetInteger(printing::kSettingPageWidth, &width) ||
-        !settings->GetInteger(printing::kSettingPageHeight, &height) ||
-        width <= 0 || height <= 0) {
+    if (!settings->GetString(kSettingDeviceName, &destination_id) ||
+        !settings->GetString(kSettingTicket, &print_ticket) ||
+        !settings->GetString(kSettingCapabilities, &capabilities) ||
+        !settings->GetInteger(kSettingPageWidth, &width) ||
+        !settings->GetInteger(kSettingPageHeight, &height) || width <= 0 ||
+        height <= 0) {
       NOTREACHED();
       RejectJavascriptCallback(base::Value(callback_id),
                                GetErrorValue(user_action, "FAILED"));
@@ -926,7 +916,7 @@
 
 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
   std::string data_to_save;
-  printing::StickySettings* sticky_settings = GetStickySettings();
+  StickySettings* sticky_settings = GetStickySettings();
   if (args->GetString(0, &data_to_save) && !data_to_save.empty())
     sticky_settings->StoreAppState(data_to_save);
   sticky_settings->SaveInPrefs(GetPrefs());
@@ -1053,15 +1043,15 @@
   base::DictionaryValue initial_settings;
   initial_settings.SetString(kDocumentTitle,
                              print_preview_ui()->initiator_title());
-  initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
+  initial_settings.SetBoolean(kSettingPreviewModifiable,
                               print_preview_ui()->source_is_modifiable());
-  initial_settings.SetString(printing::kSettingPrinterName, default_printer);
+  initial_settings.SetString(kSettingPrinterName, default_printer);
   initial_settings.SetBoolean(kDocumentHasSelection,
                               print_preview_ui()->source_has_selection());
-  initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
+  initial_settings.SetBoolean(kSettingShouldPrintSelectionOnly,
                               print_preview_ui()->print_selection_only());
   PrefService* prefs = GetPrefs();
-  printing::StickySettings* sticky_settings = GetStickySettings();
+  StickySettings* sticky_settings = GetStickySettings();
   sticky_settings->RestoreFromPrefs(prefs);
   if (sticky_settings->printer_app_state()) {
     initial_settings.SetString(kAppState,
@@ -1113,7 +1103,7 @@
     base::Value settings_info) {
   // Check that |settings_info| is valid.
   if (settings_info.is_dict() &&
-      settings_info.FindKeyOfType(printing::kSettingCapabilities,
+      settings_info.FindKeyOfType(kSettingCapabilities,
                                   base::Value::Type::DICTIONARY)) {
     VLOG(1) << "Get printer capabilities finished";
     ResolveJavascriptCallback(base::Value(callback_id), settings_info);
@@ -1130,7 +1120,7 @@
   base::Value response(base::Value::Type::DICTIONARY);
   base::Value* caps_value =
       destination_info.is_dict()
-          ? destination_info.FindKeyOfType(printing::kSettingCapabilities,
+          ? destination_info.FindKeyOfType(kSettingCapabilities,
                                            base::Value::Type::DICTIONARY)
           : nullptr;
   response.SetKey("printerId", base::Value(printer_name));
@@ -1139,11 +1129,11 @@
                   caps_value ? std::move(*caps_value)
                              : base::Value(base::Value::Type::DICTIONARY));
   if (caps_value) {
-    base::Value* printer = destination_info.FindKeyOfType(
-        printing::kPrinter, base::Value::Type::DICTIONARY);
+    base::Value* printer =
+        destination_info.FindKeyOfType(kPrinter, base::Value::Type::DICTIONARY);
     if (printer) {
       base::Value* policies_value = printer->FindKeyOfType(
-          printing::kSettingPolicies, base::Value::Type::DICTIONARY);
+          kSettingPolicies, base::Value::Type::DICTIONARY);
       if (policies_value)
         response.SetKey("policies", std::move(*policies_value));
     }
@@ -1181,8 +1171,8 @@
 }
 
 WebContents* PrintPreviewHandler::GetInitiator() const {
-  printing::PrintPreviewDialogController* dialog_controller =
-      printing::PrintPreviewDialogController::GetInstance();
+  PrintPreviewDialogController* dialog_controller =
+      PrintPreviewDialogController::GetInstance();
   if (!dialog_controller)
     return NULL;
   return dialog_controller->GetInitiator(preview_web_contents());
@@ -1297,8 +1287,8 @@
   // We no longer require the initiator details. Remove those details associated
   // with the preview dialog to allow the initiator to create another preview
   // dialog.
-  printing::PrintPreviewDialogController* dialog_controller =
-      printing::PrintPreviewDialogController::GetInstance();
+  PrintPreviewDialogController* dialog_controller =
+      PrintPreviewDialogController::GetInstance();
   if (dialog_controller)
     dialog_controller->EraseInitiatorInfo(preview_web_contents());
 }
@@ -1353,7 +1343,7 @@
       GetPrinterHandler(PrinterType::kPdfPrinter));
 }
 
-void PrintPreviewHandler::OnAddedPrinters(printing::PrinterType printer_type,
+void PrintPreviewHandler::OnAddedPrinters(PrinterType printer_type,
                                           const base::ListValue& printers) {
   DCHECK(printer_type == PrinterType::kExtensionPrinter ||
          printer_type == PrinterType::kPrivetPrinter ||
@@ -1392,7 +1382,7 @@
   // Remove the preview dialog from the background printing manager if it is
   // being stored there. Since the PDF has been sent and the callback is
   // resolved or rejected, it is no longer needed and can be destroyed.
-  printing::BackgroundPrintingManager* background_printing_manager =
+  BackgroundPrintingManager* background_printing_manager =
       g_browser_process->background_printing_manager();
   if (background_printing_manager->HasPrintPreviewDialog(
           preview_web_contents())) {
@@ -1442,3 +1432,5 @@
     const base::DictionaryValue& settings) {
   FireWebUIListener("manipulate-settings-for-test", settings);
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index e340c350..35d8bca 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -22,10 +22,6 @@
 #include "printing/backend/print_backend.h"
 #include "printing/buildflags/buildflags.h"
 
-class PdfPrinterHandler;
-class PrinterHandler;
-class PrintPreviewUI;
-
 namespace base {
 class DictionaryValue;
 class RefCountedMemory;
@@ -37,6 +33,10 @@
 
 namespace printing {
 
+class PdfPrinterHandler;
+class PrinterHandler;
+class PrintPreviewUI;
+
 // Must match print_preview.PrinterType in
 // chrome/browser/resources/print_preview/native_layer.js
 enum PrinterType {
@@ -47,8 +47,6 @@
   kCloudPrinter
 };
 
-}  // namespace printing
-
 // The handler for Javascript messages related to the print preview dialog.
 class PrintPreviewHandler
     : public content::WebUIMessageHandler,
@@ -126,7 +124,7 @@
 
  protected:
   // Protected so unit tests can override.
-  virtual PrinterHandler* GetPrinterHandler(printing::PrinterType printer_type);
+  virtual PrinterHandler* GetPrinterHandler(PrinterType printer_type);
 
   // Shuts down the initiator renderer. Called when a bad IPC message is
   // received.
@@ -280,7 +278,7 @@
   // |printer_type|: The type of printers that were added.
   // |printers|: A non-empty list containing information about the printer or
   //     printers that have been added.
-  void OnAddedPrinters(printing::PrinterType printer_type,
+  void OnAddedPrinters(PrinterType printer_type,
                        const base::ListValue& printers);
 
   // Called when printer search is done for some destination type.
@@ -355,4 +353,6 @@
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandler);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINT_PREVIEW_HANDLER_H_
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
index 26ebe83..c255db8e0 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/optional.h"
+#include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/icu_test_util.h"
@@ -45,10 +46,9 @@
 const char kDummyInitiatorName[] = "TestInitiator";
 const char kTestData[] = "abc";
 
-// Array of all printing::PrinterType values.
-const printing::PrinterType kAllTypes[] = {
-    printing::kPrivetPrinter, printing::kExtensionPrinter,
-    printing::kPdfPrinter, printing::kLocalPrinter};
+// Array of all PrinterType values.
+const PrinterType kAllTypes[] = {kPrivetPrinter, kExtensionPrinter, kPdfPrinter,
+                                 kLocalPrinter};
 
 struct PrinterInfo {
   std::string id;
@@ -241,8 +241,6 @@
 
 }  // namespace
 
-}  // namespace printing
-
 class PrintPreviewHandlerTest : public testing::Test {
  public:
   PrintPreviewHandlerTest() = default;
@@ -256,37 +254,35 @@
     content::WebContents* initiator = initiator_web_contents_.get();
     preview_web_contents_ = content::WebContents::Create(
         content::WebContents::CreateParams(profile_.get()));
-    printing::PrintViewManager::CreateForWebContents(initiator);
-    printing::PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(
+    PrintViewManager::CreateForWebContents(initiator);
+    PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(
         initiator->GetMainFrame(), false);
     web_ui_ = std::make_unique<content::TestWebUI>();
     web_ui_->set_web_contents(preview_web_contents_.get());
 
-    printers_.push_back(
-        printing::GetSimplePrinterInfo(printing::kDummyPrinterName, true));
+    printers_.push_back(GetSimplePrinterInfo(kDummyPrinterName, true));
     auto printer_handler = CreatePrinterHandler(printers_);
     printer_handler_ = printer_handler.get();
 
-    auto preview_handler = std::make_unique<printing::TestPrintPreviewHandler>(
+    auto preview_handler = std::make_unique<TestPrintPreviewHandler>(
         std::move(printer_handler), initiator);
     preview_handler->set_web_ui(web_ui());
     handler_ = preview_handler.get();
 
-    auto preview_ui = std::make_unique<printing::FakePrintPreviewUI>(
+    auto preview_ui = std::make_unique<FakePrintPreviewUI>(
         web_ui(), std::move(preview_handler));
-    preview_ui->SetInitiatorTitle(
-        base::ASCIIToUTF16(printing::kDummyInitiatorName));
+    preview_ui->SetInitiatorTitle(base::ASCIIToUTF16(kDummyInitiatorName));
     web_ui()->SetController(std::move(preview_ui));
   }
 
   void TearDown() override {
-    printing::PrintViewManager::FromWebContents(initiator_web_contents_.get())
+    PrintViewManager::FromWebContents(initiator_web_contents_.get())
         ->PrintPreviewDone();
   }
 
-  virtual std::unique_ptr<printing::TestPrinterHandler> CreatePrinterHandler(
-      const std::vector<printing::PrinterInfo>& printers) {
-    return std::make_unique<printing::TestPrinterHandler>(printers);
+  virtual std::unique_ptr<TestPrinterHandler> CreatePrinterHandler(
+      const std::vector<PrinterInfo>& printers) {
+    return std::make_unique<TestPrinterHandler>(printers);
   }
 
   void Initialize() {
@@ -406,9 +402,9 @@
   const Profile* profile() { return profile_.get(); }
   PrefService* prefs() { return profile_->GetPrefs(); }
   content::TestWebUI* web_ui() { return web_ui_.get(); }
-  printing::TestPrintPreviewHandler* handler() { return handler_; }
-  printing::TestPrinterHandler* printer_handler() { return printer_handler_; }
-  std::vector<printing::PrinterInfo>& printers() { return printers_; }
+  TestPrintPreviewHandler* handler() { return handler_; }
+  TestPrinterHandler* printer_handler() { return printer_handler_; }
+  std::vector<PrinterInfo>& printers() { return printers_; }
 
  private:
   content::TestBrowserThreadBundle thread_bundle_;
@@ -417,9 +413,9 @@
   content::RenderViewHostTestEnabler rvh_test_enabler_;
   std::unique_ptr<content::WebContents> preview_web_contents_;
   std::unique_ptr<content::WebContents> initiator_web_contents_;
-  std::vector<printing::PrinterInfo> printers_;
-  printing::TestPrinterHandler* printer_handler_;
-  printing::TestPrintPreviewHandler* handler_;
+  std::vector<PrinterInfo> printers_;
+  TestPrinterHandler* printer_handler_;
+  TestPrintPreviewHandler* handler_;
 
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandlerTest);
 };
@@ -428,9 +424,8 @@
   Initialize();
 
   // Verify initial settings were sent.
-  ValidateInitialSettings(*web_ui()->call_data().back(),
-                          printing::kDummyPrinterName,
-                          printing::kDummyInitiatorName, {});
+  ValidateInitialSettings(*web_ui()->call_data().back(), kDummyPrinterName,
+                          kDummyInitiatorName, {});
 
   // Check that the use-cloud-print event got sent
   AssertWebUIEventFired(*web_ui()->call_data().front(), "use-cloud-print");
@@ -440,18 +435,16 @@
   // Set a pref that should take priority over StickySettings.
   prefs()->SetBoolean(prefs::kPrintHeaderFooter, true);
   Initialize();
-  ValidateInitialSettings(*web_ui()->call_data().back(),
-                          printing::kDummyPrinterName,
-                          printing::kDummyInitiatorName, true);
+  ValidateInitialSettings(*web_ui()->call_data().back(), kDummyPrinterName,
+                          kDummyInitiatorName, true);
 }
 
 TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableHeaderFooter) {
   // Set a pref that should take priority over StickySettings.
   prefs()->SetBoolean(prefs::kPrintHeaderFooter, false);
   Initialize();
-  ValidateInitialSettings(*web_ui()->call_data().back(),
-                          printing::kDummyPrinterName,
-                          printing::kDummyInitiatorName, false);
+  ValidateInitialSettings(*web_ui()->call_data().back(), kDummyPrinterName,
+                          kDummyInitiatorName, false);
 }
 
 TEST_F(PrintPreviewHandlerTest, GetPrinters) {
@@ -459,11 +452,10 @@
 
   // Check all three printer types that implement
   // PrinterHandler::StartGetPrinters().
-  const printing::PrinterType types[] = {printing::kPrivetPrinter,
-                                         printing::kExtensionPrinter,
-                                         printing::kLocalPrinter};
-  for (size_t i = 0; i < arraysize(types); i++) {
-    printing::PrinterType type = types[i];
+  const PrinterType types[] = {kPrivetPrinter, kExtensionPrinter,
+                               kLocalPrinter};
+  for (size_t i = 0; i < base::size(types); i++) {
+    PrinterType type = types[i];
     handler()->reset_calls();
     base::Value args(base::Value::Type::LIST);
     std::string callback_id_in =
@@ -500,7 +492,7 @@
 
 TEST_F(PrintPreviewHandlerTest, GetPrinterCapabilities) {
   // Add an empty printer to the handler.
-  printers().push_back(printing::GetEmptyPrinterInfo());
+  printers().push_back(GetEmptyPrinterInfo());
   printer_handler()->SetPrinters(printers());
 
   // Initial settings first to enable javascript.
@@ -508,14 +500,14 @@
 
   // Check all four printer types that implement
   // PrinterHandler::StartGetCapability().
-  for (size_t i = 0; i < arraysize(printing::kAllTypes); i++) {
-    printing::PrinterType type = printing::kAllTypes[i];
+  for (size_t i = 0; i < base::size(kAllTypes); i++) {
+    PrinterType type = kAllTypes[i];
     handler()->reset_calls();
     base::Value args(base::Value::Type::LIST);
     std::string callback_id_in =
         "test-callback-id-" + base::UintToString(i + 1);
     args.GetList().emplace_back(callback_id_in);
-    args.GetList().emplace_back(printing::kDummyPrinterName);
+    args.GetList().emplace_back(kDummyPrinterName);
     args.GetList().emplace_back(type);
     std::unique_ptr<base::ListValue> list_args =
         base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
@@ -531,19 +523,18 @@
     CheckWebUIResponse(data, callback_id_in, true);
     const base::Value* settings = data.arg3();
     ASSERT_TRUE(settings);
-    EXPECT_TRUE(settings->FindKeyOfType(printing::kSettingCapabilities,
+    EXPECT_TRUE(settings->FindKeyOfType(kSettingCapabilities,
                                         base::Value::Type::DICTIONARY));
   }
 
   // Run through the loop again, this time with a printer that has no
   // capabilities.
-  for (size_t i = 0; i < arraysize(printing::kAllTypes); i++) {
-    printing::PrinterType type = printing::kAllTypes[i];
+  for (size_t i = 0; i < base::size(kAllTypes); i++) {
+    PrinterType type = kAllTypes[i];
     handler()->reset_calls();
     base::Value args(base::Value::Type::LIST);
     std::string callback_id_in =
-        "test-callback-id-" +
-        base::UintToString(i + arraysize(printing::kAllTypes) + 1);
+        "test-callback-id-" + base::UintToString(i + base::size(kAllTypes) + 1);
     args.GetList().emplace_back(callback_id_in);
     args.GetList().emplace_back("EmptyPrinter");
     args.GetList().emplace_back(type);
@@ -552,10 +543,9 @@
     handler()->HandleGetPrinterCapabilities(list_args.get());
     EXPECT_TRUE(handler()->CalledOnlyForType(type));
 
-    // Start with 2 calls from initial settings plus
-    // arraysize(printing::kAllTypes) from first loop, then add 1 more for each
-    // loop iteration.
-    ASSERT_EQ(2u + arraysize(printing::kAllTypes) + (i + 1),
+    // Start with 2 calls from initial settings plus base::size(kAllTypes) from
+    // first loop, then add 1 more for each loop iteration.
+    ASSERT_EQ(2u + base::size(kAllTypes) + (i + 1),
               web_ui()->call_data().size());
 
     // Verify printer capabilities promise was rejected.
@@ -568,17 +558,16 @@
   Initialize();
 
   // All four printer types can print, as well as cloud printers.
-  for (size_t i = 0; i <= arraysize(printing::kAllTypes); i++) {
+  for (size_t i = 0; i <= base::size(kAllTypes); i++) {
     // Also check cloud print. Use dummy type value of Privet (will be ignored).
-    bool cloud = i == arraysize(printing::kAllTypes);
-    printing::PrinterType type =
-        cloud ? printing::kPrivetPrinter : printing::kAllTypes[i];
+    bool cloud = i == base::size(kAllTypes);
+    PrinterType type = cloud ? kPrivetPrinter : kAllTypes[i];
     handler()->reset_calls();
     base::Value args(base::Value::Type::LIST);
     std::string callback_id_in =
         "test-callback-id-" + base::UintToString(i + 1);
     args.GetList().emplace_back(callback_id_in);
-    base::Value print_ticket = printing::GetPrintTicket(type, cloud);
+    base::Value print_ticket = GetPrintTicket(type, cloud);
     std::string json;
     base::JSONWriter::Write(print_ticket, &json);
     args.GetList().emplace_back(json);
@@ -603,7 +592,7 @@
       std::string print_data;
       ASSERT_TRUE(data.arg3()->GetAsString(&print_data));
       std::string expected_data;
-      base::Base64Encode(printing::kTestData, &expected_data);
+      base::Base64Encode(kTestData, &expected_data);
       EXPECT_EQ(print_data, expected_data);
     }
   }
@@ -612,9 +601,9 @@
 TEST_F(PrintPreviewHandlerTest, GetPreview) {
   Initialize();
 
-  base::Value print_ticket = printing::GetPrintPreviewTicket(false);
+  base::Value print_ticket = GetPrintPreviewTicket(false);
   std::unique_ptr<base::ListValue> list_args =
-      printing::ConstructPreviewArgs("test-callback-id-1", print_ticket);
+      ConstructPreviewArgs("test-callback-id-1", print_ticket);
   handler()->HandleGetPreview(list_args.get());
 
   // Verify that the preview was requested from the renderer with the
@@ -622,7 +611,7 @@
   base::DictionaryValue preview_params = VerifyPreviewMessage();
   bool preview_id_found = false;
   for (const auto& it : preview_params.DictItems()) {
-    if (it.first == printing::kPreviewUIID) {  // This is added by the handler.
+    if (it.first == kPreviewUIID) {  // This is added by the handler.
       preview_id_found = true;
       continue;
     }
@@ -637,20 +626,19 @@
   Initialize();
 
   const char callback_id_in[] = "test-callback-id-1";
-  base::Value print_ticket = printing::GetPrintPreviewTicket(false);
+  base::Value print_ticket = GetPrintPreviewTicket(false);
   std::unique_ptr<base::ListValue> list_args =
-      printing::ConstructPreviewArgs(callback_id_in, print_ticket);
+      ConstructPreviewArgs(callback_id_in, print_ticket);
   handler()->HandleGetPreview(list_args.get());
   base::DictionaryValue preview_params = VerifyPreviewMessage();
 
   // Read the preview UI ID and request ID
-  const base::Value* request_value =
-      preview_params.FindKey(printing::kPreviewRequestID);
+  const base::Value* request_value = preview_params.FindKey(kPreviewRequestID);
   ASSERT_TRUE(request_value);
   ASSERT_TRUE(request_value->is_int());
   int preview_request_id = request_value->GetInt();
 
-  const base::Value* ui_value = preview_params.FindKey(printing::kPreviewUIID);
+  const base::Value* ui_value = preview_params.FindKey(kPreviewUIID);
   ASSERT_TRUE(ui_value);
   ASSERT_TRUE(ui_value->is_int());
   int preview_ui_id = ui_value->GetInt();
@@ -658,16 +646,16 @@
   // Simulate renderer responses: PageLayoutReady, PageCountReady,
   // PagePreviewReady, and OnPrintPreviewReady will be called in that order.
   base::DictionaryValue layout;
-  layout.SetKey(printing::kSettingMarginTop, base::Value(34.0));
-  layout.SetKey(printing::kSettingMarginLeft, base::Value(34.0));
-  layout.SetKey(printing::kSettingMarginBottom, base::Value(34.0));
-  layout.SetKey(printing::kSettingMarginRight, base::Value(34.0));
-  layout.SetKey(printing::kSettingContentWidth, base::Value(544.0));
-  layout.SetKey(printing::kSettingContentHeight, base::Value(700.0));
-  layout.SetKey(printing::kSettingPrintableAreaX, base::Value(17));
-  layout.SetKey(printing::kSettingPrintableAreaY, base::Value(17));
-  layout.SetKey(printing::kSettingPrintableAreaWidth, base::Value(578));
-  layout.SetKey(printing::kSettingPrintableAreaHeight, base::Value(734));
+  layout.SetKey(kSettingMarginTop, base::Value(34.0));
+  layout.SetKey(kSettingMarginLeft, base::Value(34.0));
+  layout.SetKey(kSettingMarginBottom, base::Value(34.0));
+  layout.SetKey(kSettingMarginRight, base::Value(34.0));
+  layout.SetKey(kSettingContentWidth, base::Value(544.0));
+  layout.SetKey(kSettingContentHeight, base::Value(700.0));
+  layout.SetKey(kSettingPrintableAreaX, base::Value(17));
+  layout.SetKey(kSettingPrintableAreaY, base::Value(17));
+  layout.SetKey(kSettingPrintableAreaWidth, base::Value(578));
+  layout.SetKey(kSettingPrintableAreaHeight, base::Value(734));
   handler()->SendPageLayoutReady(layout, false, preview_request_id);
 
   // Verify that page-layout-ready webUI event was fired.
@@ -703,10 +691,9 @@
   EXPECT_EQ(handler()->bad_messages(), 3);
 }
 
-class FailingTestPrinterHandler : public printing::TestPrinterHandler {
+class FailingTestPrinterHandler : public TestPrinterHandler {
  public:
-  explicit FailingTestPrinterHandler(
-      const std::vector<printing::PrinterInfo>& printers)
+  explicit FailingTestPrinterHandler(const std::vector<PrinterInfo>& printers)
       : TestPrinterHandler(printers) {}
 
   ~FailingTestPrinterHandler() override = default;
@@ -725,8 +712,8 @@
   PrintPreviewHandlerFailingTest() = default;
   ~PrintPreviewHandlerFailingTest() override = default;
 
-  std::unique_ptr<printing::TestPrinterHandler> CreatePrinterHandler(
-      const std::vector<printing::PrinterInfo>& printers) override {
+  std::unique_ptr<TestPrinterHandler> CreatePrinterHandler(
+      const std::vector<PrinterInfo>& printers) override {
     return std::make_unique<FailingTestPrinterHandler>(printers);
   }
 
@@ -740,7 +727,7 @@
 // handling path. Failure is different from getting no capabilities.
 TEST_F(PrintPreviewHandlerFailingTest, GetPrinterCapabilities) {
   // Add an empty printer to the handler.
-  printers().push_back(printing::GetEmptyPrinterInfo());
+  printers().push_back(GetEmptyPrinterInfo());
   printer_handler()->SetPrinters(printers());
 
   // Initial settings first to enable javascript.
@@ -748,14 +735,14 @@
 
   // Check all four printer types that implement
   // PrinterHandler::StartGetCapability().
-  for (size_t i = 0; i < base::size(printing::kAllTypes); i++) {
-    printing::PrinterType type = printing::kAllTypes[i];
+  for (size_t i = 0; i < base::size(kAllTypes); i++) {
+    PrinterType type = kAllTypes[i];
     handler()->reset_calls();
     base::Value args(base::Value::Type::LIST);
     std::string callback_id_in =
         "test-callback-id-" + base::UintToString(i + 1);
     args.GetList().emplace_back(callback_id_in);
-    args.GetList().emplace_back(printing::kDummyPrinterName);
+    args.GetList().emplace_back(kDummyPrinterName);
     args.GetList().emplace_back(type);
     std::unique_ptr<base::ListValue> list_args =
         base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
@@ -774,3 +761,5 @@
     EXPECT_TRUE(settings->is_none());
   }
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index c346a72..1e5839b 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -66,7 +66,8 @@
 #endif
 
 using content::WebContents;
-using printing::PageSizeMargins;
+
+namespace printing {
 
 namespace {
 
@@ -136,7 +137,7 @@
 // Parameters (< > required):
 //    <PrintPreviewUIID> = PrintPreview UI ID
 //    <PageIndex> = Page index is zero-based or
-//                  |printing::COMPLETE_PREVIEW_DOCUMENT_INDEX| to represent
+//                  |COMPLETE_PREVIEW_DOCUMENT_INDEX| to represent
 //                  a print ready PDF.
 //
 // Example:
@@ -562,7 +563,7 @@
 
 void PrintPreviewUI::OnPrintPreviewDialogClosed() {
   WebContents* preview_dialog = web_ui()->GetWebContents();
-  printing::BackgroundPrintingManager* background_printing_manager =
+  BackgroundPrintingManager* background_printing_manager =
       g_browser_process->background_printing_manager();
   if (background_printing_manager->HasPrintPreviewDialog(preview_dialog))
     return;
@@ -573,7 +574,7 @@
   // Should only get here if the initiator was still tracked by the Print
   // Preview Dialog Controller, so the print job has not yet been sent.
   WebContents* preview_dialog = web_ui()->GetWebContents();
-  printing::BackgroundPrintingManager* background_printing_manager =
+  BackgroundPrintingManager* background_printing_manager =
       g_browser_process->background_printing_manager();
   if (background_printing_manager->HasPrintPreviewDialog(preview_dialog)) {
     // Dialog is hidden but is still generating the preview. Cancel the print
@@ -632,18 +633,16 @@
   printable_area_ = printable_area;
 
   base::DictionaryValue layout;
-  layout.SetDouble(printing::kSettingMarginTop, page_layout.margin_top);
-  layout.SetDouble(printing::kSettingMarginLeft, page_layout.margin_left);
-  layout.SetDouble(printing::kSettingMarginBottom, page_layout.margin_bottom);
-  layout.SetDouble(printing::kSettingMarginRight, page_layout.margin_right);
-  layout.SetDouble(printing::kSettingContentWidth, page_layout.content_width);
-  layout.SetDouble(printing::kSettingContentHeight, page_layout.content_height);
-  layout.SetInteger(printing::kSettingPrintableAreaX, printable_area.x());
-  layout.SetInteger(printing::kSettingPrintableAreaY, printable_area.y());
-  layout.SetInteger(printing::kSettingPrintableAreaWidth,
-                    printable_area.width());
-  layout.SetInteger(printing::kSettingPrintableAreaHeight,
-                    printable_area.height());
+  layout.SetDouble(kSettingMarginTop, page_layout.margin_top);
+  layout.SetDouble(kSettingMarginLeft, page_layout.margin_left);
+  layout.SetDouble(kSettingMarginBottom, page_layout.margin_bottom);
+  layout.SetDouble(kSettingMarginRight, page_layout.margin_right);
+  layout.SetDouble(kSettingContentWidth, page_layout.content_width);
+  layout.SetDouble(kSettingContentHeight, page_layout.content_height);
+  layout.SetInteger(kSettingPrintableAreaX, printable_area.x());
+  layout.SetInteger(kSettingPrintableAreaY, printable_area.y());
+  layout.SetInteger(kSettingPrintableAreaWidth, printable_area.width());
+  layout.SetInteger(kSettingPrintableAreaHeight, printable_area.height());
   handler_->SendPageLayoutReady(layout, has_custom_page_size_style, request_id);
 }
 
@@ -687,8 +686,7 @@
     initial_preview_start_time_ = base::TimeTicks();
   }
 
-  SetPrintPreviewDataForIndex(printing::COMPLETE_PREVIEW_DOCUMENT_INDEX,
-                              std::move(data));
+  SetPrintPreviewDataForIndex(COMPLETE_PREVIEW_DOCUMENT_INDEX, std::move(data));
 
   handler_->OnPrintPreviewReady(*id_, preview_request_id);
 }
@@ -707,7 +705,7 @@
 
 void PrintPreviewUI::OnHidePreviewDialog() {
   WebContents* preview_dialog = web_ui()->GetWebContents();
-  printing::BackgroundPrintingManager* background_printing_manager =
+  BackgroundPrintingManager* background_printing_manager =
       g_browser_process->background_printing_manager();
   if (background_printing_manager->HasPrintPreviewDialog(preview_dialog))
     return;
@@ -779,3 +777,5 @@
   id_ = g_print_preview_ui_id_map.Get().Add(this);
   g_print_preview_request_id_map.Get().Set(*id_, -1);
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
index 7a5c43e63..3af93ad 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -21,7 +21,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 
-class PrintPreviewHandler;
 struct PrintHostMsg_DidStartPreview_Params;
 struct PrintHostMsg_PreviewIds;
 struct PrintHostMsg_RequestPrintPreview_Params;
@@ -38,8 +37,9 @@
 }
 
 namespace printing {
+
+class PrintPreviewHandler;
 struct PageSizeMargins;
-}
 
 class PrintPreviewUI : public ConstrainedWebDialogUI {
  public:
@@ -48,8 +48,7 @@
   ~PrintPreviewUI() override;
 
   // Gets the print preview |data|. |index| is zero-based, and can be
-  // |printing::COMPLETE_PREVIEW_DOCUMENT_INDEX| to get the entire preview
-  // document.
+  // |COMPLETE_PREVIEW_DOCUMENT_INDEX| to get the entire preview document.
   virtual void GetPrintPreviewDataForIndex(
       int index,
       scoped_refptr<base::RefCountedMemory>* data) const;
@@ -106,7 +105,7 @@
 
   // Notifies the Web UI of the default page layout according to the currently
   // selected printer and page size.
-  void OnDidGetDefaultPageLayout(const printing::PageSizeMargins& page_layout,
+  void OnDidGetDefaultPageLayout(const PageSizeMargins& page_layout,
                                  const gfx::Rect& printable_area,
                                  bool has_custom_page_size_style,
                                  int request_id);
@@ -211,11 +210,9 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(PrintPreviewDialogControllerUnitTest,
                            TitleAfterReload);
-  friend class FakePrintPreviewUI;
 
   // Sets the print preview |data|. |index| is zero-based, and can be
-  // |printing::COMPLETE_PREVIEW_DOCUMENT_INDEX| to set the entire preview
-  // document.
+  // |COMPLETE_PREVIEW_DOCUMENT_INDEX| to set the entire preview document.
   void SetPrintPreviewDataForIndex(int index,
                                    scoped_refptr<base::RefCountedMemory> data);
 
@@ -268,4 +265,6 @@
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewUI);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINT_PREVIEW_UI_H_
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc
index c385a358..38c43b9 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc
@@ -27,6 +27,8 @@
 using content::WebContents;
 using web_modal::WebContentsModalDialogManager;
 
+namespace printing {
+
 namespace {
 
 scoped_refptr<base::RefCountedBytes> CreateTestData() {
@@ -71,12 +73,12 @@
   ASSERT_TRUE(initiator);
   EXPECT_FALSE(IsShowingWebContentsModalDialog(initiator));
 
-  printing::PrintPreviewDialogController* controller =
-      printing::PrintPreviewDialogController::GetInstance();
+  PrintPreviewDialogController* controller =
+      PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(controller);
 
-  printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator);
+  PrintViewManager* print_view_manager =
+      PrintViewManager::FromWebContents(initiator);
   print_view_manager->PrintPreviewNow(initiator->GetMainFrame(), false);
   WebContents* preview_dialog = controller->GetOrCreatePreviewDialog(initiator);
 
@@ -90,27 +92,24 @@
   preview_ui->SetPreviewUIId();
 
   scoped_refptr<base::RefCountedMemory> data;
-  preview_ui->GetPrintPreviewDataForIndex(
-      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX,
-      &data);
+  preview_ui->GetPrintPreviewDataForIndex(COMPLETE_PREVIEW_DOCUMENT_INDEX,
+                                          &data);
   EXPECT_FALSE(data);
 
   scoped_refptr<base::RefCountedBytes> dummy_data = CreateTestData();
 
   preview_ui->SetPrintPreviewDataForIndexForTest(
-      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, dummy_data.get());
-  preview_ui->GetPrintPreviewDataForIndex(
-      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX,
-      &data);
+      COMPLETE_PREVIEW_DOCUMENT_INDEX, dummy_data.get());
+  preview_ui->GetPrintPreviewDataForIndex(COMPLETE_PREVIEW_DOCUMENT_INDEX,
+                                          &data);
   EXPECT_EQ(dummy_data->size(), data->size());
   EXPECT_EQ(dummy_data.get(), data.get());
 
   // Clear the preview data.
   preview_ui->ClearAllPreviewDataForTest();
 
-  preview_ui->GetPrintPreviewDataForIndex(
-      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX,
-      &data);
+  preview_ui->GetPrintPreviewDataForIndex(COMPLETE_PREVIEW_DOCUMENT_INDEX,
+                                          &data);
   EXPECT_FALSE(data);
 }
 
@@ -119,12 +118,12 @@
   WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(initiator);
 
-  printing::PrintPreviewDialogController* controller =
-      printing::PrintPreviewDialogController::GetInstance();
+  PrintPreviewDialogController* controller =
+      PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(controller);
 
-  printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator);
+  PrintViewManager* print_view_manager =
+      PrintViewManager::FromWebContents(initiator);
   print_view_manager->PrintPreviewNow(initiator->GetMainFrame(), false);
   WebContents* preview_dialog = controller->GetOrCreatePreviewDialog(initiator);
 
@@ -138,40 +137,37 @@
   preview_ui->SetPreviewUIId();
 
   scoped_refptr<base::RefCountedMemory> data;
-  preview_ui->GetPrintPreviewDataForIndex(printing::FIRST_PAGE_INDEX, &data);
+  preview_ui->GetPrintPreviewDataForIndex(FIRST_PAGE_INDEX, &data);
   EXPECT_FALSE(data);
 
   scoped_refptr<base::RefCountedBytes> dummy_data = CreateTestData();
 
-  preview_ui->SetPrintPreviewDataForIndexForTest(printing::FIRST_PAGE_INDEX,
+  preview_ui->SetPrintPreviewDataForIndexForTest(FIRST_PAGE_INDEX,
                                                  dummy_data.get());
-  preview_ui->GetPrintPreviewDataForIndex(printing::FIRST_PAGE_INDEX, &data);
+  preview_ui->GetPrintPreviewDataForIndex(FIRST_PAGE_INDEX, &data);
   EXPECT_EQ(dummy_data->size(), data->size());
   EXPECT_EQ(dummy_data.get(), data.get());
 
   // Set and get the third page data.
-  preview_ui->SetPrintPreviewDataForIndexForTest(printing::FIRST_PAGE_INDEX + 2,
+  preview_ui->SetPrintPreviewDataForIndexForTest(FIRST_PAGE_INDEX + 2,
                                                  dummy_data.get());
-  preview_ui->GetPrintPreviewDataForIndex(printing::FIRST_PAGE_INDEX + 2,
-                                          &data);
+  preview_ui->GetPrintPreviewDataForIndex(FIRST_PAGE_INDEX + 2, &data);
   EXPECT_EQ(dummy_data->size(), data->size());
   EXPECT_EQ(dummy_data.get(), data.get());
 
   // Get the second page data.
-  preview_ui->GetPrintPreviewDataForIndex(printing::FIRST_PAGE_INDEX + 1,
-                                          &data);
+  preview_ui->GetPrintPreviewDataForIndex(FIRST_PAGE_INDEX + 1, &data);
   EXPECT_FALSE(data);
 
-  preview_ui->SetPrintPreviewDataForIndexForTest(printing::FIRST_PAGE_INDEX + 1,
+  preview_ui->SetPrintPreviewDataForIndexForTest(FIRST_PAGE_INDEX + 1,
                                                  dummy_data.get());
-  preview_ui->GetPrintPreviewDataForIndex(printing::FIRST_PAGE_INDEX + 1,
-                                          &data);
+  preview_ui->GetPrintPreviewDataForIndex(FIRST_PAGE_INDEX + 1, &data);
   EXPECT_EQ(dummy_data->size(), data->size());
   EXPECT_EQ(dummy_data.get(), data.get());
 
   // Clear the preview data.
   preview_ui->ClearAllPreviewDataForTest();
-  preview_ui->GetPrintPreviewDataForIndex(printing::FIRST_PAGE_INDEX, &data);
+  preview_ui->GetPrintPreviewDataForIndex(FIRST_PAGE_INDEX, &data);
   EXPECT_FALSE(data);
 }
 
@@ -180,12 +176,12 @@
   WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(initiator);
 
-  printing::PrintPreviewDialogController* controller =
-      printing::PrintPreviewDialogController::GetInstance();
+  PrintPreviewDialogController* controller =
+      PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(controller);
 
-  printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator);
+  PrintViewManager* print_view_manager =
+      PrintViewManager::FromWebContents(initiator);
   print_view_manager->PrintPreviewNow(initiator->GetMainFrame(), false);
   WebContents* preview_dialog = controller->GetOrCreatePreviewDialog(initiator);
 
@@ -216,3 +212,5 @@
   EXPECT_TRUE(preview_ui->ShouldCancelRequest({kFirstRequestId, preview_id}));
   EXPECT_FALSE(preview_ui->ShouldCancelRequest({kSecondRequestId, preview_id}));
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
index 6d8dc9b..f3db3ad 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
@@ -205,9 +205,9 @@
   }
 
   bool system_dialog = false;
-  job_settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
+  job_settings->GetBoolean(kSettingShowSystemDialog, &system_dialog);
   bool open_in_pdf = false;
-  job_settings->GetBoolean(printing::kSettingOpenPDFInPreview, &open_in_pdf);
+  job_settings->GetBoolean(kSettingOpenPDFInPreview, &open_in_pdf);
   if (system_dialog || open_in_pdf) {
     // Run the callback early, or the modal dialogs will prevent the preview
     // from closing until they do.
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.h b/chrome/browser/ui/webui/print_preview/print_preview_utils.h
index f13e2c1..92016d22 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.h
@@ -32,7 +32,7 @@
 void ConvertPrinterListForCallback(
     const PrinterHandler::AddedPrintersCallback& callback,
     PrinterHandler::GetPrintersDoneCallback done_callback,
-    const printing::PrinterList& printer_list);
+    const PrinterList& printer_list);
 
 // Returns a unique_ptr to a sanitized version of |cdd| to prevent possible JS
 // errors in Print Preview. Will remove null items from lists or options lists
diff --git a/chrome/browser/ui/webui/print_preview/printer_handler.cc b/chrome/browser/ui/webui/print_preview/printer_handler.cc
index 4ce4aca1..d5fcabd 100644
--- a/chrome/browser/ui/webui/print_preview/printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/printer_handler.cc
@@ -20,6 +20,8 @@
 #include "chrome/browser/ui/webui/print_preview/local_printer_handler_default.h"
 #endif
 
+namespace printing {
+
 // static
 std::unique_ptr<PrinterHandler> PrinterHandler::CreateForCloudPrinters() {
   return std::make_unique<CloudPrinterHandler>();
@@ -47,7 +49,7 @@
 std::unique_ptr<PrinterHandler> PrinterHandler::CreateForPdfPrinter(
     Profile* profile,
     content::WebContents* preview_web_contents,
-    printing::StickySettings* sticky_settings) {
+    StickySettings* sticky_settings) {
   return std::make_unique<PdfPrinterHandler>(profile, preview_web_contents,
                                              sticky_settings);
 }
@@ -68,3 +70,5 @@
                                              GetPrinterInfoCallback callback) {
   NOTREACHED();
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/printer_handler.h b/chrome/browser/ui/webui/print_preview/printer_handler.h
index 408cb3cd..04b2998 100644
--- a/chrome/browser/ui/webui/print_preview/printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/printer_handler.h
@@ -28,12 +28,12 @@
 class Size;
 }
 
-namespace printing {
-class StickySettings;
-}
-
 class Profile;
 
+namespace printing {
+
+class StickySettings;
+
 // Wrapper around PrinterProviderAPI to be used by print preview.
 // It makes request lifetime management easier, and hides details of more
 // complex operations like printing from the print preview handler. This class
@@ -45,13 +45,12 @@
   using AddedPrintersCallback =
       base::RepeatingCallback<void(const base::ListValue& printers)>;
   using GetPrintersDoneCallback = base::OnceClosure;
-  // |capability| should contain a CDD with key printing::kSettingCapabilities.
+  // |capability| should contain a CDD with key |kSettingCapabilities|.
   // It may also contain other information about the printer in a dictionary
-  // with key printing::kPrinter.
+  // with key |kPrinter|.
   // If |capability| is null, empty, or does not contain a dictionary with key
-  // printing::kSettingCapabilities, this indicates a failure to retrieve
-  // capabilities.
-  // If the dictionary with key printing::kSettingCapabilities is
+  // |kSettingCapabilities|, this indicates a failure to retrieve capabilities.
+  // If the dictionary with key |kSettingCapabilities| is
   // empty, this indicates capabilities were retrieved but the printer does
   // not support any of the capability fields in a CDD.
   using GetCapabilityCallback =
@@ -72,7 +71,7 @@
   static std::unique_ptr<PrinterHandler> CreateForPdfPrinter(
       Profile* profile,
       content::WebContents* preview_web_contents,
-      printing::StickySettings* sticky_settings);
+      StickySettings* sticky_settings);
 
   static std::unique_ptr<PrinterHandler> CreateForLocalPrinters(
       content::WebContents* preview_web_contents,
@@ -134,4 +133,6 @@
       PrintCallback callback) = 0;
 };
 
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINTER_HANDLER_H_
diff --git a/chrome/browser/ui/webui/print_preview/privet_printer_handler.cc b/chrome/browser/ui/webui/print_preview/privet_printer_handler.cc
index d01ac56..dceb17b1 100644
--- a/chrome/browser/ui/webui/print_preview/privet_printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/privet_printer_handler.cc
@@ -26,6 +26,8 @@
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/gfx/geometry/size.h"
 
+namespace printing {
+
 namespace {
 // Timeout for searching for privet printers, in seconds.
 const int kSearchTimeoutSec = 5;
@@ -198,11 +200,10 @@
                                       std::move(printer_info));
   std::unique_ptr<base::DictionaryValue> capabilities_copy =
       capabilities->CreateDeepCopy();
-  printer_info_and_caps.SetDictionary(printing::kSettingCapabilities,
+  printer_info_and_caps.SetDictionary(kSettingCapabilities,
                                       std::move(capabilities_copy));
   std::move(capabilities_callback_)
-      .Run(std::move(
-          *printing::ValidateCddForPrintPreview(printer_info_and_caps)));
+      .Run(std::move(*ValidateCddForPrintPreview(printer_info_and_caps)));
   privet_capabilities_operation_.reset();
 }
 
@@ -280,3 +281,5 @@
   privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(name);
   privet_http_resolution_->Start(device_description->address, callback);
 }
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/privet_printer_handler.h b/chrome/browser/ui/webui/print_preview/privet_printer_handler.h
index 4a14f2a..01b84a0 100644
--- a/chrome/browser/ui/webui/print_preview/privet_printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/privet_printer_handler.h
@@ -26,6 +26,8 @@
 class Size;
 }
 
+namespace printing {
+
 // Implementation of PrinterHandler interface
 class PrivetPrinterHandler
     : public PrinterHandler,
@@ -113,4 +115,7 @@
 
   DISALLOW_COPY_AND_ASSIGN(PrivetPrinterHandler);
 };
+
+}  // namespace printing
+
 #endif  // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRIVET_PRINTER_HANDLER_H_
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index 2502239..68664618 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -361,7 +361,7 @@
   // "content_utility". This is all set up here.
   service_manager_ = std::make_unique<service_manager::ServiceManager>(
       std::make_unique<NullServiceProcessLauncherFactory>(),
-      CreateServiceProcessCatalog(), nullptr);
+      CreateServiceProcessCatalog());
 
   service_manager::mojom::ServicePtr browser_proxy;
   service_manager_connection_ = content::ServiceManagerConnection::Create(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index f86af4e..b5d915c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2239,8 +2239,6 @@
   ]
 }
 
-# Temporary target for running benchmarks without building Chrome
-# Will be removed as a part of crbug.com/758632
 group("telemetry_perf_tests_without_chrome") {
   testonly = true
   deps = [
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
index 19def6a..b91c66d 100644
--- a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
+++ b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
@@ -871,9 +871,9 @@
     // Connecting to wifi2 should set wifi1 to offline. Connected or Connecting
     // networks should be listed first, sorted by type.
     var expected = ['stub_ethernet_guid',
-                    'stub_wifi2_guid',
                     'stub_wimax_guid',
                     'stub_vpn1_guid',
+                    'stub_wifi2_guid',
                     'stub_wifi1_guid',
                     'stub_vpn2_guid'];
     var done = chrome.test.callbackAdded();
diff --git a/chrome/test/data/webui/welcome/nux_set_as_default_test.js b/chrome/test/data/webui/welcome/nux_set_as_default_test.js
new file mode 100644
index 0000000..f76a7ea
--- /dev/null
+++ b/chrome/test/data/webui/welcome/nux_set_as_default_test.js
@@ -0,0 +1,74 @@
+// 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.
+
+cr.define('onboarding_set_as_default_test', function() {
+  suite('SetAsDefaultTest', function() {
+    /** @type {NuxSetAsDefaultElement} */
+    let testElement;
+
+    /** @type {nux.NuxSetAsDefaultProxy} */
+    let testSetAsDefaultProxy;
+
+    /** @type {!Promise} */
+    let navigatedPromise;
+
+    setup(function() {
+      testSetAsDefaultProxy = new TestNuxSetAsDefaultProxy();
+      nux.NuxSetAsDefaultProxyImpl.instance_ = testSetAsDefaultProxy;
+
+      navigatedPromise = new Promise(resolve => {
+        // Spy on navigational function to make sure it's called.
+        welcome.navigateToNextStep = () => resolve();
+      });
+
+      PolymerTest.clearBody();
+      testElement = document.createElement('nux-set-as-default');
+      document.body.appendChild(testElement);
+    });
+
+    teardown(function() {
+      testElement.remove();
+    });
+
+    test('skip', function() {
+      testElement.$['decline-button'].click();
+      return testSetAsDefaultProxy.whenCalled('recordSkip');
+    });
+
+    test(
+        'click set-default button and finishes setting default',
+        async function() {
+          testElement.$$('.action-button').click();
+
+          await Promise.all([
+            testSetAsDefaultProxy.whenCalled('recordBeginSetDefault'),
+            testSetAsDefaultProxy.whenCalled('setAsDefault'),
+          ]);
+
+          cr.webUIListenerCallback(
+              'browser-default-state-changed', {isDefault: true});
+
+          return Promise.all([
+            testSetAsDefaultProxy.whenCalled('recordSuccessfullySetDefault'),
+            navigatedPromise
+          ]);
+        });
+
+    test('click set-default button but gives up and skip', async function() {
+      testElement.$$('.action-button').click();
+
+      await Promise.all([
+        testSetAsDefaultProxy.whenCalled('recordBeginSetDefault'),
+        testSetAsDefaultProxy.whenCalled('setAsDefault'),
+      ]);
+
+      testElement.$['decline-button'].click();
+
+      return Promise.all([
+        testSetAsDefaultProxy.whenCalled('recordSkip'),
+        navigatedPromise,
+      ]);
+    });
+  });
+});
diff --git a/chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js b/chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js
index 13348d3..73ba24bd 100644
--- a/chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js
+++ b/chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js
@@ -135,3 +135,22 @@
 TEST_F('OnboardingWelcomeModuleMetricsTest', 'All', function() {
   mocha.run();
 });
+
+OnboardingWelcomeSetAsDefaultTest = class extends OnboardingWelcomeBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://welcome/set_as_default/nux_set_as_default.html';
+  }
+
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'nux_set_as_default_test.js',
+      'test_nux_set_as_default_proxy.js',
+    ]);
+  }
+};
+
+TEST_F('OnboardingWelcomeSetAsDefaultTest', 'All', function() {
+  mocha.run();
+});
diff --git a/chromecast/media/cma/backend/filter_group.cc b/chromecast/media/cma/backend/filter_group.cc
index 67122abc..e08f759 100644
--- a/chromecast/media/cma/backend/filter_group.cc
+++ b/chromecast/media/cma/backend/filter_group.cc
@@ -20,27 +20,24 @@
 
 FilterGroup::FilterGroup(int num_channels,
                          const std::string& name,
-                         std::unique_ptr<PostProcessingPipeline> pipeline,
-                         const base::flat_set<std::string>& device_ids,
-                         const std::vector<FilterGroup*>& mixed_inputs)
+                         std::unique_ptr<PostProcessingPipeline> pipeline)
     : num_channels_(num_channels),
       name_(name),
-      device_ids_(device_ids),
-      mixed_inputs_(mixed_inputs),
       playout_channel_selection_(kChannelAll),
       output_samples_per_second_(0),
       frames_zeroed_(0),
       last_volume_(0.0),
       delay_frames_(0),
       content_type_(AudioContentType::kMedia),
-      post_processing_pipeline_(std::move(pipeline)) {
-  for (auto* const m : mixed_inputs) {
-    DCHECK_EQ(m->GetOutputChannelCount(), num_channels);
-  }
-}
+      post_processing_pipeline_(std::move(pipeline)) {}
 
 FilterGroup::~FilterGroup() = default;
 
+void FilterGroup::AddMixedInput(FilterGroup* input) {
+  mixed_inputs_.push_back(input);
+  DCHECK_EQ(input->GetOutputChannelCount(), num_channels_);
+}
+
 void FilterGroup::Initialize(int output_samples_per_second) {
   output_samples_per_second_ = output_samples_per_second;
   CHECK(post_processing_pipeline_->SetSampleRate(output_samples_per_second));
@@ -48,10 +45,6 @@
   active_inputs_.clear();
 }
 
-bool FilterGroup::CanProcessInput(const std::string& input_device_id) {
-  return !(device_ids_.find(input_device_id) == device_ids_.end());
-}
-
 void FilterGroup::AddInput(MixerInput* input) {
   active_inputs_.insert(input);
   if (mixed_) {
@@ -235,5 +228,15 @@
   post_processing_pipeline_->UpdatePlayoutChannel(playout_channel);
 }
 
+void FilterGroup::PrintTopology() const {
+  std::string input_groups;
+  for (const FilterGroup* mixed_input : mixed_inputs_) {
+    mixed_input->PrintTopology();
+    input_groups += mixed_input->name() + ", ";
+  }
+
+  LOG(INFO) << input_groups << " -> " << num_channels_ << "ch -> " << name_;
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/backend/filter_group.h b/chromecast/media/cma/backend/filter_group.h
index 6bc1cb6..960a4da3 100644
--- a/chromecast/media/cma/backend/filter_group.h
+++ b/chromecast/media/cma/backend/filter_group.h
@@ -37,32 +37,22 @@
 class FilterGroup {
  public:
   // |num_channels| indicates number of input audio channels.
-  // |type| indicates where in the pipeline this FilterGroup sits.
   // |name| is used for debug printing
   // |pipeline| - processing pipeline.
-  // |device_ids| is a set of strings that is used as a filter to determine
-  //   if an InputQueue belongs to this group (InputQueue->name() must exactly
-  //   match an entry in |device_ids| to be processed by this group).
-  // |mixed_inputs| are FilterGroups that will be mixed into this FilterGroup.
-  //   ex: the final mix ("mix") FilterGroup mixes all other filter groups.
-  // FilterGroups currently use either InputQueues OR FilterGroups as inputs,
-  //   but there is no technical limitation preventing mixing input classes.
-
   FilterGroup(int num_channels,
               const std::string& name,
-              std::unique_ptr<PostProcessingPipeline> pipeline,
-              const base::flat_set<std::string>& device_ids,
-              const std::vector<FilterGroup*>& mixed_inputs);
+              std::unique_ptr<PostProcessingPipeline> pipeline);
 
   ~FilterGroup();
 
+  // |input| will be recursively mixed into this FilterGroup's input buffer when
+  // MixAndFilter() is called. Registering a FilterGroup as an input to more
+  // than one FilterGroup will result in incorrect behavior.
+  void AddMixedInput(FilterGroup* input);
+
   // Sets the sample rate of the post-processors.
   void Initialize(int output_samples_per_second);
 
-  // Returns |true| if this FilterGroup is appropriate to process an input with
-  // the given |input_device_id|.
-  bool CanProcessInput(const std::string& input_device_id);
-
   // Adds/removes |input| from |active_inputs_|.
   void AddInput(MixerInput* input);
   void RemoveInput(MixerInput* input);
@@ -108,6 +98,9 @@
   // Get content type
   AudioContentType content_type() const { return content_type_; }
 
+  // Recursively print the layout of the pipeline.
+  void PrintTopology() const;
+
  private:
   // Resizes temp_ and mixed_ if they are too small to hold |num_frames| frames.
   // Returns |true| if |num_frames| is larger than all previous |num_frames|.
@@ -116,7 +109,6 @@
 
   const int num_channels_;
   const std::string name_;
-  const base::flat_set<std::string> device_ids_;
   std::vector<FilterGroup*> mixed_inputs_;
   base::flat_set<MixerInput*> active_inputs_;
 
diff --git a/chromecast/media/cma/backend/filter_group_unittest.cc b/chromecast/media/cma/backend/filter_group_unittest.cc
index a36c35f..ac8b068b 100644
--- a/chromecast/media/cma/backend/filter_group_unittest.cc
+++ b/chromecast/media/cma/backend/filter_group_unittest.cc
@@ -169,9 +169,7 @@
     EXPECT_CALL(*post_processor_, SetContentType(kDefaultContentType));
     EXPECT_CALL(*post_processor_, UpdatePlayoutChannel(kDefaultPlayoutChannel));
     filter_group_ = std::make_unique<FilterGroup>(
-        kNumInputChannels, "test_filter", std::move(post_processor),
-        base::flat_set<std::string>() /* device_ids */,
-        std::vector<FilterGroup*>());
+        kNumInputChannels, "test_filter", std::move(post_processor));
     filter_group_->Initialize(kInputSampleRate);
     filter_group_->AddInput(&input_);
     filter_group_->UpdatePlayoutChannel(kChannelAll);
diff --git a/chromecast/media/cma/backend/mixer_pipeline.cc b/chromecast/media/cma/backend/mixer_pipeline.cc
index 8207b9c..4f8656a8 100644
--- a/chromecast/media/cma/backend/mixer_pipeline.cc
+++ b/chromecast/media/cma/backend/mixer_pipeline.cc
@@ -32,15 +32,13 @@
 std::unique_ptr<FilterGroup> CreateFilterGroup(
     int input_channels,
     const std::string& name,
-    const base::ListValue* filter_list,
-    const base::flat_set<std::string>& device_ids,
-    const std::vector<FilterGroup*>& mixed_inputs,
+    const base::Value* filter_list,
     PostProcessingPipelineFactory* ppp_factory) {
   DCHECK(ppp_factory);
   auto pipeline =
       ppp_factory->CreatePipeline(name, filter_list, input_channels);
-  return std::make_unique<FilterGroup>(
-      input_channels, name, std::move(pipeline), device_ids, mixed_inputs);
+  return std::make_unique<FilterGroup>(input_channels, name,
+                                       std::move(pipeline));
 }
 
 }  // namespace
@@ -64,85 +62,100 @@
                                   PostProcessingPipelineFactory* factory) {
   DCHECK(config);
   DCHECK(factory);
-  base::flat_set<std::string> used_streams;
+  int mix_group_input_channels = -1;
+
+  // Create "stream" processor groups:
   for (auto& stream_pipeline : config->GetStreamPipelines()) {
-    const auto& device_ids = stream_pipeline.stream_types;
-    for (const std::string& stream_type : device_ids) {
-      if (!IsOutputDeviceId(stream_type)) {
-        LOG(ERROR) << stream_type
-                   << " is not a stream type. Stream types are listed "
-                   << "in chromecast/media/base/audio_device_ids.cc and "
-                   << "media/audio/audio_device_description.cc";
-        return false;
-      }
-      if (!used_streams.insert(stream_type).second) {
-        LOG(ERROR) << "Multiple instances of stream type '" << stream_type
-                   << "' in " << config->GetFilePath() << ".";
-        return false;
-      }
-      filter_groups_.push_back(CreateFilterGroup(
-          kNumInputChannels, *device_ids.begin() /* name */,
-          stream_pipeline.pipeline, device_ids,
-          std::vector<FilterGroup*>() /* mixed_inputs */, factory));
-      if (device_ids.find(::media::AudioDeviceDescription::kDefaultDeviceId) !=
-          device_ids.end()) {
-        default_stream_group_ = filter_groups_.back().get();
-      }
+    const base::Value* device_ids = stream_pipeline.stream_types;
+
+    DCHECK(!device_ids->GetList().empty());
+    DCHECK(device_ids->GetList()[0].is_string());
+    filter_groups_.push_back(CreateFilterGroup(
+        kNumInputChannels, device_ids->GetList()[0].GetString() /* name */,
+        stream_pipeline.pipeline, factory));
+
+    if (!SetGroupDeviceIds(device_ids, filter_groups_.back().get())) {
+      return false;
+    }
+
+    if (mix_group_input_channels == -1) {
+      mix_group_input_channels = filter_groups_.back()->GetOutputChannelCount();
+    } else if (mix_group_input_channels !=
+               filter_groups_.back()->GetOutputChannelCount()) {
+      LOG(ERROR)
+          << "All output stream mixers must have the same number of channels"
+          << filter_groups_.back()->name() << " has "
+          << filter_groups_.back()->GetOutputChannelCount()
+          << " but others have " << mix_group_input_channels;
+      return false;
     }
   }
 
-  if (!filter_groups_.empty()) {
-    std::vector<FilterGroup*> filter_group_ptrs(filter_groups_.size());
-    int mix_group_input_channels = filter_groups_[0]->GetOutputChannelCount();
-    for (size_t i = 0; i < filter_groups_.size(); ++i) {
-      if (mix_group_input_channels !=
-          filter_groups_[i]->GetOutputChannelCount()) {
-        LOG(ERROR)
-            << "All output stream mixers must have the same number of channels"
-            << filter_groups_[i]->name() << " has "
-            << filter_groups_[i]->GetOutputChannelCount() << " but others have "
-            << mix_group_input_channels;
-        return false;
-      }
-      filter_group_ptrs[i] = filter_groups_[i].get();
-    }
-
-    filter_groups_.push_back(CreateFilterGroup(
-        mix_group_input_channels, "mix", config->GetMixPipeline(),
-        base::flat_set<std::string>() /* device_ids */, filter_group_ptrs,
-        factory));
-  } else {
-    // Mix group directly mixes all inputs.
-    std::string kDefaultDeviceId =
-        ::media::AudioDeviceDescription::kDefaultDeviceId;
-    filter_groups_.push_back(CreateFilterGroup(
-        kNumInputChannels, "mix", config->GetMixPipeline(),
-        base::flat_set<std::string>({kDefaultDeviceId}),
-        std::vector<FilterGroup*>() /* mixed_inputs */, factory));
-    default_stream_group_ = filter_groups_.back().get();
+  if (mix_group_input_channels == -1) {
+    mix_group_input_channels = kNumInputChannels;
   }
 
-  loopback_output_group_ = filter_groups_.back().get();
+  // Create "mix" processor group:
+  const auto mix_pipeline = config->GetMixPipeline();
+  std::unique_ptr<FilterGroup> mix_filter = CreateFilterGroup(
+      mix_group_input_channels, "mix", mix_pipeline.pipeline, factory);
+  for (std::unique_ptr<FilterGroup>& group : filter_groups_) {
+    mix_filter->AddMixedInput(group.get());
+  }
+  if (!SetGroupDeviceIds(mix_pipeline.stream_types, mix_filter.get())) {
+    return false;
+  }
+  loopback_output_group_ = mix_filter.get();
+  filter_groups_.push_back(std::move(mix_filter));
 
-  filter_groups_.push_back(CreateFilterGroup(
-      loopback_output_group_->GetOutputChannelCount(), "linearize",
-      config->GetLinearizePipeline(),
-      base::flat_set<std::string>() /* device_ids */,
-      std::vector<FilterGroup*>({loopback_output_group_}), factory));
+  // Create "linearize" processor group:
+  const auto linearize_pipeline = config->GetLinearizePipeline();
+  filter_groups_.push_back(
+      CreateFilterGroup(loopback_output_group_->GetOutputChannelCount(),
+                        "linearize", linearize_pipeline.pipeline, factory));
   output_group_ = filter_groups_.back().get();
-
-  LOG(INFO) << "PostProcessor configuration:";
-  if (default_stream_group_ == loopback_output_group_) {
-    LOG(INFO) << "Stream layer: none";
-  } else {
-    LOG(INFO) << "Stream layer: "
-              << default_stream_group_->GetOutputChannelCount() << " channels";
+  output_group_->AddMixedInput(loopback_output_group_);
+  if (!SetGroupDeviceIds(linearize_pipeline.stream_types, output_group_)) {
+    return false;
   }
-  LOG(INFO) << "Mix filter: " << loopback_output_group_->GetOutputChannelCount()
-            << " channels";
-  LOG(INFO) << "Linearize filter: " << output_group_->GetOutputChannelCount()
-            << " channels";
 
+  // If no default group is provided, use the "mix" group.
+  if (stream_sinks_.find(::media::AudioDeviceDescription::kDefaultDeviceId) ==
+      stream_sinks_.end()) {
+    stream_sinks_[::media::AudioDeviceDescription::kDefaultDeviceId] =
+        loopback_output_group_;
+  }
+
+  output_group_->PrintTopology();
+
+  return true;
+}
+
+bool MixerPipeline::SetGroupDeviceIds(const base::Value* ids,
+                                      FilterGroup* filter_group) {
+  if (!ids) {
+    return true;
+  }
+  DCHECK(filter_group);
+  DCHECK(ids->is_list());
+
+  for (const base::Value& stream_type_val : ids->GetList()) {
+    DCHECK(stream_type_val.is_string());
+    const std::string& stream_type = stream_type_val.GetString();
+    if (!IsOutputDeviceId(stream_type)) {
+      LOG(ERROR) << stream_type
+                 << " is not a stream type. Stream types are listed "
+                 << "in chromecast/media/base/audio_device_ids.cc and "
+                 << "media/audio/audio_device_description.cc";
+      return false;
+    }
+    if (stream_sinks_.find(stream_type) != stream_sinks_.end()) {
+      LOG(ERROR) << "Multiple instances of stream type '" << stream_type
+                 << "' in cast_audio.json";
+      return false;
+    }
+    stream_sinks_[stream_type] = filter_group;
+  }
   return true;
 }
 
@@ -153,19 +166,12 @@
 }
 
 FilterGroup* MixerPipeline::GetInputGroup(const std::string& device_id) {
-  for (auto&& filter_group : filter_groups_) {
-    if (filter_group->CanProcessInput(device_id)) {
-      return filter_group.get();
-      break;
-    }
+  auto got = stream_sinks_.find(device_id);
+  if (got != stream_sinks_.end()) {
+    return got->second;
   }
 
-  if (default_stream_group_) {
-    return default_stream_group_;
-  }
-
-  NOTREACHED() << "Could not find a filter group to re-attach " << device_id;
-  return nullptr;
+  return stream_sinks_[::media::AudioDeviceDescription::kDefaultDeviceId];
 }
 
 void MixerPipeline::MixAndFilter(
diff --git a/chromecast/media/cma/backend/mixer_pipeline.h b/chromecast/media/cma/backend/mixer_pipeline.h
index 7a83621..779dd19 100644
--- a/chromecast/media/cma/backend/mixer_pipeline.h
+++ b/chromecast/media/cma/backend/mixer_pipeline.h
@@ -10,10 +10,15 @@
 #include <string>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "chromecast/public/media/audio_post_processor_shlib.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 
+namespace base {
+class Value;
+}  // namespace base
+
 namespace chromecast {
 namespace media {
 
@@ -82,8 +87,11 @@
   bool BuildPipeline(PostProcessingPipelineParser* config,
                      PostProcessingPipelineFactory* factory);
 
+  // Adds |ids| to the list of DeviceIds |filter_group| can process.
+  bool SetGroupDeviceIds(const base::Value* ids, FilterGroup* filter_group);
+
   std::vector<std::unique_ptr<FilterGroup>> filter_groups_;
-  FilterGroup* default_stream_group_ = nullptr;
+  base::flat_map<std::string, FilterGroup*> stream_sinks_;
   FilterGroup* loopback_output_group_ = nullptr;
   FilterGroup* output_group_ = nullptr;
 
diff --git a/chromecast/media/cma/backend/mock_post_processor_factory.cc b/chromecast/media/cma/backend/mock_post_processor_factory.cc
index 6f488d32..326ad79 100644
--- a/chromecast/media/cma/backend/mock_post_processor_factory.cc
+++ b/chromecast/media/cma/backend/mock_post_processor_factory.cc
@@ -13,11 +13,10 @@
 using testing::_;
 using testing::NiceMock;
 
-MockPostProcessor::MockPostProcessor(
-    MockPostProcessorFactory* factory,
-    const std::string& name,
-    const base::ListValue* filter_description_list,
-    int channels)
+MockPostProcessor::MockPostProcessor(MockPostProcessorFactory* factory,
+                                     const std::string& name,
+                                     const base::Value* filter_description_list,
+                                     int channels)
     : factory_(factory), name_(name), num_output_channels_(channels) {
   DCHECK(factory_);
   CHECK(factory_->instances.insert({name_, this}).second);
@@ -32,23 +31,32 @@
   }
 
   // Parse |filter_description_list| for parameters.
-  for (size_t i = 0; i < filter_description_list->GetSize(); ++i) {
-    const base::DictionaryValue* description_dict;
-    CHECK(filter_description_list->GetDictionary(i, &description_dict));
-    std::string solib;
-    CHECK(description_dict->GetString("processor", &solib));
-    // This will initially be called with the actual pipeline on creation.
-    // Ignore and wait for the call to ResetPostProcessorsForTest.
-    const std::string kDelayModuleSolib = "delay.so";
-    if (solib == kDelayModuleSolib) {
-      const base::DictionaryValue* processor_config_dict;
-      CHECK(description_dict->GetDictionary("config", &processor_config_dict));
-      int module_delay;
-      CHECK(processor_config_dict->GetInteger("delay", &module_delay));
-      rendering_delay_ += module_delay;
-      processor_config_dict->GetBoolean("ringing", &ringing_);
-      processor_config_dict->GetInteger("output_channels",
-                                        &num_output_channels_);
+  for (const base::Value& elem : filter_description_list->GetList()) {
+    CHECK(elem.is_dict());
+    const base::Value* processor_val =
+        elem.FindKeyOfType("processor", base::Value::Type::STRING);
+    CHECK(processor_val);
+    std::string solib = processor_val->GetString();
+
+    if (solib == "delay.so") {
+      const base::Value* processor_config_dict =
+          elem.FindKeyOfType("config", base::Value::Type::DICTIONARY);
+      CHECK(processor_config_dict);
+      const base::Value* delay_val = processor_config_dict->FindKeyOfType(
+          "delay", base::Value::Type::INTEGER);
+      CHECK(delay_val);
+      rendering_delay_ += delay_val->GetInt();
+      const base::Value* ringing_val = processor_config_dict->FindKeyOfType(
+          "ringing", base::Value::Type::BOOLEAN);
+      if (ringing_val) {
+        ringing_ = ringing_val->GetBool();
+      }
+
+      const base::Value* output_ch_val = processor_config_dict->FindKeyOfType(
+          "output_channels", base::Value::Type::INTEGER);
+      if (output_ch_val) {
+        num_output_channels_ = output_ch_val->GetInt();
+      }
     }
   }
 }
@@ -60,7 +68,7 @@
 std::unique_ptr<PostProcessingPipeline>
 MockPostProcessorFactory::CreatePipeline(
     const std::string& name,
-    const base::ListValue* filter_description_list,
+    const base::Value* filter_description_list,
     int channels) {
   return std::make_unique<testing::NiceMock<MockPostProcessor>>(
       this, name, filter_description_list, channels);
diff --git a/chromecast/media/cma/backend/mock_post_processor_factory.h b/chromecast/media/cma/backend/mock_post_processor_factory.h
index 20ba1e3..63d87cf 100644
--- a/chromecast/media/cma/backend/mock_post_processor_factory.h
+++ b/chromecast/media/cma/backend/mock_post_processor_factory.h
@@ -13,6 +13,10 @@
 #include "chromecast/media/cma/backend/post_processing_pipeline.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+namespace base {
+class Value;
+}  // namespace base
+
 namespace chromecast {
 namespace media {
 
@@ -21,7 +25,7 @@
  public:
   MockPostProcessor(MockPostProcessorFactory* factory,
                     const std::string& name,
-                    const base::ListValue* filter_description_list,
+                    const base::Value* filter_description_list,
                     int channels);
   ~MockPostProcessor() override;
   MOCK_METHOD4(
@@ -64,7 +68,7 @@
   ~MockPostProcessorFactory() override;
   std::unique_ptr<PostProcessingPipeline> CreatePipeline(
       const std::string& name,
-      const base::ListValue* filter_description_list,
+      const base::Value* filter_description_list,
       int channels) override;
 
   std::unordered_map<std::string, MockPostProcessor*> instances;
diff --git a/chromecast/media/cma/backend/post_processing_pipeline.h b/chromecast/media/cma/backend/post_processing_pipeline.h
index c1063fd1..55ee73a1 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline.h
+++ b/chromecast/media/cma/backend/post_processing_pipeline.h
@@ -11,7 +11,7 @@
 #include "chromecast/public/volume_control.h"
 
 namespace base {
-class ListValue;
+class Value;
 }  // namespace base
 
 namespace chromecast {
@@ -41,7 +41,7 @@
 
   virtual std::unique_ptr<PostProcessingPipeline> CreatePipeline(
       const std::string& name,
-      const base::ListValue* filter_description_list,
+      const base::Value* filter_description_list,
       int num_channels) = 0;
 };
 
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.cc b/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
index 3ff8c35..a39a935 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
+++ b/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
@@ -42,7 +42,7 @@
 std::unique_ptr<PostProcessingPipeline>
 PostProcessingPipelineFactoryImpl::CreatePipeline(
     const std::string& name,
-    const base::ListValue* filter_description_list,
+    const base::Value* filter_description_list,
     int num_channels) {
   return std::make_unique<PostProcessingPipelineImpl>(
       name, filter_description_list, num_channels);
@@ -50,7 +50,7 @@
 
 PostProcessingPipelineImpl::PostProcessingPipelineImpl(
     const std::string& name,
-    const base::ListValue* filter_description_list,
+    const base::Value* filter_description_list,
     int channels)
     : name_(name), sample_rate_(kNoSampleRate), num_output_channels_(channels) {
   if (!filter_description_list) {
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.h b/chromecast/media/cma/backend/post_processing_pipeline_impl.h
index 21f29e0..71e8255 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.h
+++ b/chromecast/media/cma/backend/post_processing_pipeline_impl.h
@@ -15,7 +15,7 @@
 #include "chromecast/public/volume_control.h"
 
 namespace base {
-class ListValue;
+class Value;
 }  // namespace base
 
 namespace chromecast {
@@ -28,7 +28,7 @@
 class PostProcessingPipelineImpl : public PostProcessingPipeline {
  public:
   PostProcessingPipelineImpl(const std::string& name,
-                             const base::ListValue* filter_description_list,
+                             const base::Value* filter_description_list,
                              int channels);
   ~PostProcessingPipelineImpl() override;
 
@@ -87,7 +87,7 @@
   // PostProcessingPipelineFactory interface.
   std::unique_ptr<PostProcessingPipeline> CreatePipeline(
       const std::string& name,
-      const base::ListValue* filter_description_list,
+      const base::Value* filter_description_list,
       int num_channels) override;
 };
 
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_parser.cc b/chromecast/media/cma/backend/post_processing_pipeline_parser.cc
index deac7d19..cb104c7 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_parser.cc
+++ b/chromecast/media/cma/backend/post_processing_pipeline_parser.cc
@@ -26,8 +26,8 @@
 }  // namespace
 
 StreamPipelineDescriptor::StreamPipelineDescriptor(
-    const base::ListValue* pipeline_in,
-    const base::flat_set<std::string>& stream_types_in)
+    const base::Value* pipeline_in,
+    const base::Value* stream_types_in)
     : pipeline(pipeline_in), stream_types(stream_types_in) {}
 
 StreamPipelineDescriptor::~StreamPipelineDescriptor() = default;
@@ -69,57 +69,60 @@
 std::vector<StreamPipelineDescriptor>
 PostProcessingPipelineParser::GetStreamPipelines() {
   std::vector<StreamPipelineDescriptor> descriptors;
-  const base::ListValue* pipelines_list;
-  if (!postprocessor_config_ ||
-      !postprocessor_config_->GetList(kOutputStreamsKey, &pipelines_list)) {
+  if (!postprocessor_config_) {
+    return descriptors;
+  }
+  const base::Value* pipelines_list = postprocessor_config_->FindKeyOfType(
+      kOutputStreamsKey, base::Value::Type::LIST);
+  if (!pipelines_list) {
     LOG(WARNING) << "No post-processors found for streams (key = "
                  << kOutputStreamsKey
                  << ").\n No stream-specific processing will occur.";
     return descriptors;
   }
-  for (size_t i = 0; i < pipelines_list->GetSize(); ++i) {
-    const base::DictionaryValue* pipeline_description_dict;
-    CHECK(pipelines_list->GetDictionary(i, &pipeline_description_dict));
+  for (const base::Value& pipeline_description_dict :
+       pipelines_list->GetList()) {
+    CHECK(pipeline_description_dict.is_dict());
 
-    const base::ListValue* processors_list;
-    CHECK(pipeline_description_dict->GetList(kProcessorsKey, &processors_list));
+    const base::Value* processors_list =
+        pipeline_description_dict.FindKeyOfType(kProcessorsKey,
+                                                base::Value::Type::LIST);
+    CHECK(processors_list);
 
-    const base::ListValue* streams_list;
-    CHECK(pipeline_description_dict->GetList(kStreamsKey, &streams_list));
-    base::flat_set<std::string> streams_set;
-    for (size_t stream = 0; stream < streams_list->GetSize(); ++stream) {
-      std::string stream_name;
-      CHECK(streams_list->GetString(stream, &stream_name));
-      CHECK(streams_set.insert(stream_name).second)
-          << "Duplicate stream type: " << stream_name;
-    }
+    const base::Value* streams_list = pipeline_description_dict.FindKeyOfType(
+        kStreamsKey, base::Value::Type::LIST);
+    CHECK(streams_list);
 
-    descriptors.emplace_back(processors_list, std::move(streams_set));
+    descriptors.emplace_back(processors_list, streams_list);
   }
   return descriptors;
 }
 
-const base::ListValue* PostProcessingPipelineParser::GetMixPipeline() {
+StreamPipelineDescriptor PostProcessingPipelineParser::GetMixPipeline() {
   return GetPipelineByKey(kMixPipelineKey);
 }
 
-const base::ListValue* PostProcessingPipelineParser::GetLinearizePipeline() {
+StreamPipelineDescriptor PostProcessingPipelineParser::GetLinearizePipeline() {
   return GetPipelineByKey(kLinearizePipelineKey);
 }
 
-const base::ListValue* PostProcessingPipelineParser::GetPipelineByKey(
+StreamPipelineDescriptor PostProcessingPipelineParser::GetPipelineByKey(
     const std::string& key) {
   const base::DictionaryValue* stream_dict;
   if (!postprocessor_config_ ||
       !postprocessor_config_->GetDictionary(key, &stream_dict)) {
     LOG(WARNING) << "No post-processor description found for \"" << key
                  << "\" in " << file_path_ << ". Using passthrough.";
-    return nullptr;
+    return StreamPipelineDescriptor(nullptr, nullptr);
   }
-  const base::ListValue* out_list;
-  CHECK(stream_dict->GetList(kProcessorsKey, &out_list));
+  const base::Value* processors_list =
+      stream_dict->FindKeyOfType(kProcessorsKey, base::Value::Type::LIST);
+  CHECK(processors_list);
 
-  return out_list;
+  const base::Value* streams_list =
+      stream_dict->FindKeyOfType(kStreamsKey, base::Value::Type::LIST);
+
+  return StreamPipelineDescriptor(processors_list, streams_list);
 }
 
 base::FilePath PostProcessingPipelineParser::GetFilePath() const {
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_parser.h b/chromecast/media/cma/backend/post_processing_pipeline_parser.h
index b5aadea..27e50fe 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_parser.h
+++ b/chromecast/media/cma/backend/post_processing_pipeline_parser.h
@@ -15,7 +15,7 @@
 
 namespace base {
 class DictionaryValue;
-class ListValue;
+class Value;
 }  // namespace base
 
 namespace chromecast {
@@ -29,11 +29,11 @@
   //   {"processor": "PATH_TO_SHARED_OBJECT",
   //    "config": "CONFIGURATION_STRING"},
   //    ... ]
-  const base::ListValue* pipeline;
-  base::flat_set<std::string> stream_types;
+  const base::Value* pipeline;
+  const base::Value* stream_types;
 
-  StreamPipelineDescriptor(const base::ListValue* pipeline_in,
-                           const base::flat_set<std::string>& stream_types_in);
+  StreamPipelineDescriptor(const base::Value* pipeline_in,
+                           const base::Value* stream_types_in);
   ~StreamPipelineDescriptor();
   StreamPipelineDescriptor(const StreamPipelineDescriptor& other);
   StreamPipelineDescriptor operator=(const StreamPipelineDescriptor& other) =
@@ -55,14 +55,14 @@
 
   // Gets the list of processors for the mix/linearize stages.
   // Same format as StreamPipelineDescriptor.pipeline
-  const base::ListValue* GetMixPipeline();
-  const base::ListValue* GetLinearizePipeline();
+  StreamPipelineDescriptor GetMixPipeline();
+  StreamPipelineDescriptor GetLinearizePipeline();
 
   // Returns the file path used to load this object.
   base::FilePath GetFilePath() const;
 
  private:
-  const base::ListValue* GetPipelineByKey(const std::string& key);
+  StreamPipelineDescriptor GetPipelineByKey(const std::string& key);
 
   const base::FilePath file_path_;
   std::unique_ptr<base::DictionaryValue> config_dict_;
diff --git a/chromecast/media/cma/backend/stream_mixer.cc b/chromecast/media/cma/backend/stream_mixer.cc
index efd6454b..ddffd252 100644
--- a/chromecast/media/cma/backend/stream_mixer.cc
+++ b/chromecast/media/cma/backend/stream_mixer.cc
@@ -486,8 +486,6 @@
   DCHECK(mixer_task_runner_->BelongsToCurrentThread());
   DCHECK(input_source);
 
-  LOG(INFO) << "Add input " << input_source;
-
   // If the new input is a primary one (or there were no inputs previously), we
   // may need to change the output sample rate to match the input sample rate.
   // We only change the output rate if it is not set to a fixed value.
@@ -507,6 +505,8 @@
   DCHECK(input_group) << "Could not find a processor for "
                       << input_source->device_id();
 
+  LOG(INFO) << "Add input " << input_source << " to " << input_group->name();
+
   auto input = std::make_unique<MixerInput>(
       input_source, output_samples_per_second_, frames_per_write_,
       GetTotalRenderingDelay(input_group), input_group);
diff --git a/chromeos/dbus/fake_shill_manager_client.cc b/chromeos/dbus/fake_shill_manager_client.cc
index ee5a479..489a89e8 100644
--- a/chromeos/dbus/fake_shill_manager_client.cc
+++ b/chromeos/dbus/fake_shill_manager_client.cc
@@ -54,51 +54,125 @@
   const base::Value* first_;
 };
 
-// Appends string entries from |service_list_in| whose entries in ServiceClient
-// have Type |match_type| to one of the output lists based on the entry's State.
-void AppendServicesForType(
-    const base::ListValue* service_list_in,
-    const char* match_type,
-    bool technology_enabled,
-    std::vector<std::string>* active_service_list_out,
-    std::vector<std::string>* inactive_service_list_out,
-    std::vector<std::string>* disabled_service_list_out) {
-  ShillServiceClient::TestInterface* service_client =
-      DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
-  for (base::ListValue::const_iterator iter = service_list_in->begin();
-       iter != service_list_in->end(); ++iter) {
-    std::string service_path;
-    if (!iter->GetAsString(&service_path))
-      continue;
-    const base::DictionaryValue* properties =
-        service_client->GetServiceProperties(service_path);
-    if (!properties) {
-      LOG(ERROR) << "Properties not found for service: " << service_path;
-      continue;
-    }
-    std::string type;
-    properties->GetString(shill::kTypeProperty, &type);
-    if (type != match_type)
-      continue;
-    bool visible = false;
-    if (technology_enabled)
-      properties->GetBoolean(shill::kVisibleProperty, &visible);
-    if (!visible) {
-      disabled_service_list_out->push_back(service_path);
-      continue;
-    }
-    std::string state;
-    properties->GetString(shill::kStateProperty, &state);
-    if (state == shill::kStateOnline ||
-        state == shill::kStateAssociation ||
-        state == shill::kStateConfiguration ||
-        state == shill::kStatePortal ||
-        state == shill::kStateReady) {
-      active_service_list_out->push_back(service_path);
-    } else {
-      inactive_service_list_out->push_back(service_path);
-    }
-  }
+bool GetBoolValue(const base::Value& dict, const char* key) {
+  const base::Value* value =
+      dict.FindKeyOfType(key, base::Value::Type::BOOLEAN);
+  return value ? value->GetBool() : false;
+}
+
+int GetIntValue(const base::Value& dict, const char* key) {
+  const base::Value* value =
+      dict.FindKeyOfType(key, base::Value::Type::INTEGER);
+  return value ? value->GetInt() : 0;
+}
+
+std::string GetStringValue(const base::Value& dict, const char* key) {
+  const base::Value* value = dict.FindKeyOfType(key, base::Value::Type::STRING);
+  return value ? value->GetString() : std::string();
+}
+
+int GetStateOrder(const base::Value& dict) {
+  std::string state = GetStringValue(dict, shill::kStateProperty);
+  if (state == shill::kStateOnline)
+    return 1;
+  if (state == shill::kStateReady)
+    return 2;
+  if (state == shill::kStatePortal)
+    return 3;
+  if (state == shill::kStateAssociation || state == shill::kStateConfiguration)
+    return 4;
+  return 5;
+}
+
+int GetTechnologyOrder(const base::Value& dict) {
+  std::string technology = GetStringValue(dict, shill::kTypeProperty);
+  // Note: In Shill, VPN is the highest priority network, but it is generally
+  // dependent on the underlying network and gets sorted after that network.
+  // For now, we simulate this by sorting VPN last. TODO(stevenjb): Support
+  // VPN dependencies.
+  if (technology == shill::kTypeVPN)
+    return 10;
+
+  if (technology == shill::kTypeEthernet)
+    return 1;
+  if (technology == shill::kTypeWifi)
+    return 2;
+  if (technology == shill::kTypeWimax)
+    return 3;
+  if (technology == shill::kTypeCellular)
+    return 4;
+  return 5;
+}
+
+int GetSecurityOrder(const base::Value& dict) {
+  std::string security = GetStringValue(dict, shill::kSecurityProperty);
+  // No security is listed last.
+  if (security == shill::kSecurityNone)
+    return 3;
+
+  // 8021x is listed first.
+  if (security == shill::kSecurity8021x)
+    return 1;
+
+  // All other security types are equal priority.
+  return 2;
+}
+
+// Matches Shill's Service::Compare function.
+bool CompareNetworks(const base::Value& a, const base::Value& b) {
+  // Connection State: Online, Connected, Portal, Connecting
+  int state_order_a = GetStateOrder(a);
+  int state_order_b = GetStateOrder(b);
+  if (state_order_a != state_order_b)
+    return state_order_a < state_order_b;
+
+  // Connectable (i.e. configured)
+  bool connectable_a = GetBoolValue(a, shill::kConnectableProperty);
+  bool connectable_b = GetBoolValue(b, shill::kConnectableProperty);
+  if (connectable_a != connectable_b)
+    return connectable_a;
+
+  // Note: VPN is normally sorted first because of dependencies, see comment
+  // in GetTechnologyOrder.
+
+  // Technology
+  int technology_order_a = GetTechnologyOrder(a);
+  int technology_order_b = GetTechnologyOrder(b);
+  if (technology_order_a != technology_order_b)
+    return technology_order_a < technology_order_b;
+
+  // Priority
+  int priority_a = GetIntValue(a, shill::kPriorityProperty);
+  int priority_b = GetIntValue(b, shill::kPriorityProperty);
+  if (priority_a != priority_b)
+    return priority_a > priority_b;
+
+  // TODO: Sort on: Managed
+
+  // AutoConnect
+  bool auto_connect_a = GetBoolValue(a, shill::kAutoConnectProperty);
+  bool auto_connect_b = GetBoolValue(b, shill::kAutoConnectProperty);
+  if (auto_connect_a != auto_connect_b)
+    return auto_connect_a;
+
+  // Security
+  int security_order_a = GetSecurityOrder(a);
+  int security_order_b = GetSecurityOrder(b);
+  if (security_order_a != security_order_b)
+    return security_order_a < security_order_b;
+
+  // TODO: Sort on: Profile: User profile < Device profile
+  // TODO: Sort on: Has ever connected
+
+  // SignalStrength
+  int strength_a = GetIntValue(a, shill::kSignalStrengthProperty);
+  int strength_b = GetIntValue(b, shill::kSignalStrengthProperty);
+  if (strength_a != strength_b)
+    return strength_a > strength_b;
+
+  // Arbitrary identifier: SSID
+  return GetStringValue(a, shill::kSSIDProperty) <
+         GetStringValue(b, shill::kSSIDProperty);
 }
 
 void LogErrorCallback(const std::string& error_name,
@@ -141,6 +215,8 @@
       ->SetDeviceProperty(device_path, name, value, /*notify_changed=*/false);
 }
 
+const char kPathKey[] = "path";
+
 const char kTechnologyUnavailable[] = "unavailable";
 const char kTechnologyInitializing[] = "initializing";
 const char kNetworkActivated[] = "activated";
@@ -229,7 +305,7 @@
     const std::string& type,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
-  base::ListValue* enabled_list = NULL;
+  base::ListValue* enabled_list = nullptr;
   if (!stub_properties_.GetListWithoutPathExpansion(
           shill::kAvailableTechnologiesProperty, &enabled_list)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
@@ -249,7 +325,7 @@
     const std::string& type,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
-  base::ListValue* enabled_list = NULL;
+  base::ListValue* enabled_list = nullptr;
   if (!stub_properties_.GetListWithoutPathExpansion(
           shill::kAvailableTechnologiesProperty, &enabled_list)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -297,13 +373,9 @@
   if (!existing_properties) {
     // Add a new service to the service client stub because none exists, yet.
     // This calls AddManagerService.
-    service_client->AddServiceWithIPConfig(service_path,
-                                           guid /* guid */,
-                                           guid /* name */,
-                                           type,
-                                           shill::kStateIdle,
-                                           ipconfig_path,
-                                           true /* visible */);
+    service_client->AddServiceWithIPConfig(
+        service_path, guid /* guid */, guid /* name */, type, shill::kStateIdle,
+        ipconfig_path, true /* visible */);
     existing_properties = service_client->GetServiceProperties(service_path);
   }
 
@@ -344,11 +416,9 @@
   ConfigureService(properties, callback, error_callback);
 }
 
-
-void FakeShillManagerClient::GetService(
-    const base::DictionaryValue& properties,
-    const ObjectPathCallback& callback,
-    const ErrorCallback& error_callback) {
+void FakeShillManagerClient::GetService(const base::DictionaryValue& properties,
+                                        const ObjectPathCallback& callback,
+                                        const ErrorCallback& error_callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(callback, dbus::ObjectPath()));
 }
@@ -380,8 +450,8 @@
 
 void FakeShillManagerClient::RemoveDevice(const std::string& device_path) {
   base::Value device_path_value(device_path);
-  if (GetListProperty(shill::kDevicesProperty)->Remove(
-      device_path_value, NULL)) {
+  if (GetListProperty(shill::kDevicesProperty)
+          ->Remove(device_path_value, nullptr)) {
     CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
   }
 }
@@ -395,28 +465,24 @@
                                            bool enabled) {
   if (GetListProperty(shill::kAvailableTechnologiesProperty)
           ->AppendIfNotPresent(std::make_unique<base::Value>(type))) {
-    CallNotifyObserversPropertyChanged(
-        shill::kAvailableTechnologiesProperty);
+    CallNotifyObserversPropertyChanged(shill::kAvailableTechnologiesProperty);
   }
   if (enabled &&
       GetListProperty(shill::kEnabledTechnologiesProperty)
           ->AppendIfNotPresent(std::make_unique<base::Value>(type))) {
-    CallNotifyObserversPropertyChanged(
-        shill::kEnabledTechnologiesProperty);
+    CallNotifyObserversPropertyChanged(shill::kEnabledTechnologiesProperty);
   }
 }
 
 void FakeShillManagerClient::RemoveTechnology(const std::string& type) {
   base::Value type_value(type);
-  if (GetListProperty(shill::kAvailableTechnologiesProperty)->Remove(
-      type_value, NULL)) {
-    CallNotifyObserversPropertyChanged(
-        shill::kAvailableTechnologiesProperty);
+  if (GetListProperty(shill::kAvailableTechnologiesProperty)
+          ->Remove(type_value, nullptr)) {
+    CallNotifyObserversPropertyChanged(shill::kAvailableTechnologiesProperty);
   }
-  if (GetListProperty(shill::kEnabledTechnologiesProperty)->Remove(
-      type_value, NULL)) {
-    CallNotifyObserversPropertyChanged(
-        shill::kEnabledTechnologiesProperty);
+  if (GetListProperty(shill::kEnabledTechnologiesProperty)
+          ->Remove(type_value, nullptr)) {
+    CallNotifyObserversPropertyChanged(shill::kEnabledTechnologiesProperty);
   }
 }
 
@@ -430,7 +496,7 @@
     }
   } else {
     if (GetListProperty(shill::kUninitializedTechnologiesProperty)
-            ->Remove(base::Value(type), NULL)) {
+            ->Remove(base::Value(type), nullptr)) {
       CallNotifyObserversPropertyChanged(
           shill::kUninitializedTechnologiesProperty);
     }
@@ -466,9 +532,8 @@
   SetProperty(key, value, base::DoNothing(), base::Bind(&LogErrorCallback));
 }
 
-void FakeShillManagerClient::AddManagerService(
-    const std::string& service_path,
-    bool notify_observers) {
+void FakeShillManagerClient::AddManagerService(const std::string& service_path,
+                                               bool notify_observers) {
   VLOG(2) << "AddManagerService: " << service_path;
   GetListProperty(shill::kServiceCompleteListProperty)
       ->AppendIfNotPresent(std::make_unique<base::Value>(service_path));
@@ -481,8 +546,8 @@
     const std::string& service_path) {
   VLOG(2) << "RemoveManagerService: " << service_path;
   base::Value service_path_value(service_path);
-  GetListProperty(shill::kServiceCompleteListProperty)->Remove(
-      service_path_value, NULL);
+  GetListProperty(shill::kServiceCompleteListProperty)
+      ->Remove(service_path_value, nullptr);
   CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
 }
 
@@ -505,63 +570,72 @@
 
 void FakeShillManagerClient::SortManagerServices(bool notify) {
   VLOG(1) << "SortManagerServices";
-  static const char* ordered_types[] = {shill::kTypeEthernet,
-                                        shill::kTypeEthernetEap,
-                                        shill::kTypeWifi,
-                                        shill::kTypeCellular,
-                                        shill::kTypeWimax,
-                                        shill::kTypeVPN};
 
-  base::ListValue* complete_list =
-      GetListProperty(shill::kServiceCompleteListProperty);
-  if (complete_list->empty())
+  // ServiceCompleteList contains string path values for each service.
+  base::Value* complete_path_list = stub_properties_.FindKeyOfType(
+      shill::kServiceCompleteListProperty, base::Value::Type::LIST);
+  if (!complete_path_list || complete_path_list->GetList().empty())
     return;
-  std::unique_ptr<base::ListValue> prev_complete_list(
-      complete_list->DeepCopy());
 
-  std::vector<std::string> active_services;
-  std::vector<std::string> inactive_services;
-  std::vector<std::string> disabled_services;
-  for (size_t i = 0; i < arraysize(ordered_types); ++i) {
-    AppendServicesForType(complete_list,
-                          ordered_types[i],
-                          TechnologyEnabled(ordered_types[i]),
-                          &active_services,
-                          &inactive_services,
-                          &disabled_services);
-  }
-  complete_list->Clear();
-  for (size_t i = 0; i < active_services.size(); ++i)
-    complete_list->AppendString(active_services[i]);
-  for (size_t i = 0; i < inactive_services.size(); ++i)
-    complete_list->AppendString(inactive_services[i]);
-  for (size_t i = 0; i < disabled_services.size(); ++i)
-    complete_list->AppendString(disabled_services[i]);
+  base::Value prev_complete_path_list = complete_path_list->Clone();
 
-  if (notify && !complete_list->Equals(prev_complete_list.get()))
-    CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
+  // Networks for disabled services get appended to the end without sorting.
+  std::vector<std::string> disabled_path_list;
 
-  // Set the first active service as the Default service.
-  std::string new_default_service;
-  if (!active_services.empty()) {
-    ShillServiceClient::TestInterface* service_client =
-        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
-    std::string service_path = active_services[0];
-    const base::DictionaryValue* properties =
-        service_client->GetServiceProperties(service_path);
+  // Build a list of dictionaries for each service in the list.
+  std::vector<base::Value> complete_dict_list;
+  for (const base::Value& value : complete_path_list->GetList()) {
+    std::string service_path = value.GetString();
+    const base::Value* properties = DBusThreadManager::Get()
+                                        ->GetShillServiceClient()
+                                        ->GetTestInterface()
+                                        ->GetServiceProperties(service_path);
     if (!properties) {
       LOG(ERROR) << "Properties not found for service: " << service_path;
-    } else {
-      std::string state;
-      properties->GetString(shill::kStateProperty, &state);
-      if (IsConnectedState(state))
-        new_default_service = service_path;
+      continue;
     }
+
+    std::string type = GetStringValue(*properties, shill::kTypeProperty);
+    if (!TechnologyEnabled(type)) {
+      disabled_path_list.push_back(service_path);
+      continue;
+    }
+
+    base::Value properties_copy = properties->Clone();
+    properties_copy.SetKey(kPathKey, base::Value(service_path));
+    complete_dict_list.emplace_back(std::move(properties_copy));
+  }
+
+  // Sort the service list using the same logic as Shill's Service::Compare.
+  std::sort(complete_dict_list.begin(), complete_dict_list.end(),
+            CompareNetworks);
+
+  // Rebuild |complete_path_list| with the new sort order.
+  complete_path_list->GetList().clear();
+  for (const base::Value& dict : complete_dict_list) {
+    std::string service_path = GetStringValue(dict, kPathKey);
+    complete_path_list->GetList().push_back(base::Value(service_path));
+  }
+  // Append disabled networks to the end of the complete path list.
+  for (const std::string& path : disabled_path_list)
+    complete_path_list->GetList().push_back(base::Value(path));
+
+  // Notify observers if the order changed.
+  if (notify && *complete_path_list != prev_complete_path_list)
+    CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
+
+  // Set the first connected service as the Default service. Note:
+  // |new_default_service| may be empty indicating no default network.
+  std::string new_default_service;
+  const base::Value& default_network = complete_dict_list[0];
+  if (IsConnectedState(
+          GetStringValue(default_network, shill::kStateProperty))) {
+    new_default_service = GetStringValue(default_network, kPathKey);
   }
   if (default_service_ != new_default_service) {
     default_service_ = new_default_service;
-    base::Value default_service_value(default_service_);
-    SetManagerProperty(shill::kDefaultServiceProperty, default_service_value);
+    SetManagerProperty(shill::kDefaultServiceProperty,
+                       base::Value(default_service_));
   }
 }
 
@@ -954,7 +1028,7 @@
 void FakeShillManagerClient::NotifyObserversPropertyChanged(
     const std::string& property) {
   VLOG(1) << "NotifyObserversPropertyChanged: " << property;
-  base::Value* value = NULL;
+  base::Value* value = nullptr;
   if (!stub_properties_.GetWithoutPathExpansion(property, &value)) {
     LOG(ERROR) << "Notify for unknown property: " << property;
     return;
@@ -996,18 +1070,16 @@
   return enabled;
 }
 
-void FakeShillManagerClient::SetTechnologyEnabled(
-    const std::string& type,
-    const base::Closure& callback,
-    bool enabled) {
+void FakeShillManagerClient::SetTechnologyEnabled(const std::string& type,
+                                                  const base::Closure& callback,
+                                                  bool enabled) {
   base::ListValue* enabled_list =
       GetListProperty(shill::kEnabledTechnologiesProperty);
   if (enabled)
     enabled_list->AppendIfNotPresent(std::make_unique<base::Value>(type));
   else
-    enabled_list->Remove(base::Value(type), NULL);
-  CallNotifyObserversPropertyChanged(
-      shill::kEnabledTechnologiesProperty);
+    enabled_list->Remove(base::Value(type), nullptr);
+  CallNotifyObserversPropertyChanged(shill::kEnabledTechnologiesProperty);
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   // May affect available services.
   SortManagerServices(true);
@@ -1198,10 +1270,8 @@
   if (type_arg == "eth")
     type_arg = shill::kTypeEthernet;
 
-  if (type_arg != shill::kTypeEthernet &&
-      type_arg != shill::kTypeWifi &&
-      type_arg != shill::kTypeCellular &&
-      type_arg != shill::kTypeWimax &&
+  if (type_arg != shill::kTypeEthernet && type_arg != shill::kTypeWifi &&
+      type_arg != shill::kTypeCellular && type_arg != shill::kTypeWimax &&
       type_arg != shill::kTypeVPN) {
     LOG(WARNING) << "Unrecognized Shill network type: " << type_arg;
     return false;
diff --git a/chromeos/dbus/fake_shill_service_client.cc b/chromeos/dbus/fake_shill_service_client.cc
index ece0aedb..0ee7fbd 100644
--- a/chromeos/dbus/fake_shill_service_client.cc
+++ b/chromeos/dbus/fake_shill_service_client.cc
@@ -38,26 +38,28 @@
 }
 
 void CallSortManagerServices() {
-  DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
-      SortManagerServices(true);
+  DBusThreadManager::Get()
+      ->GetShillManagerClient()
+      ->GetTestInterface()
+      ->SortManagerServices(true);
 }
 
 int GetInteractiveDelay() {
-  return DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
-      GetInteractiveDelay();
+  return DBusThreadManager::Get()
+      ->GetShillManagerClient()
+      ->GetTestInterface()
+      ->GetInteractiveDelay();
 }
 
 }  // namespace
 
-FakeShillServiceClient::FakeShillServiceClient() : weak_ptr_factory_(this) {
-}
+FakeShillServiceClient::FakeShillServiceClient() : weak_ptr_factory_(this) {}
 
 FakeShillServiceClient::~FakeShillServiceClient() = default;
 
 // ShillServiceClient overrides.
 
-void FakeShillServiceClient::Init(dbus::Bus* bus) {
-}
+void FakeShillServiceClient::Init(dbus::Bus* bus) {}
 
 void FakeShillServiceClient::AddPropertyChangedObserver(
     const dbus::ObjectPath& service_path,
@@ -74,7 +76,7 @@
 void FakeShillServiceClient::GetProperties(
     const dbus::ObjectPath& service_path,
     const DictionaryValueCallback& callback) {
-  base::DictionaryValue* nested_dict = NULL;
+  base::DictionaryValue* nested_dict = nullptr;
   std::unique_ptr<base::DictionaryValue> result_properties;
   DBusMethodCallStatus call_status;
   stub_services_.GetDictionaryWithoutPathExpansion(service_path.value(),
@@ -83,7 +85,7 @@
     result_properties.reset(nested_dict->DeepCopy());
     // Remove credentials that Shill wouldn't send.
     result_properties->RemoveWithoutPathExpansion(shill::kPassphraseProperty,
-                                                  NULL);
+                                                  nullptr);
     call_status = DBUS_METHOD_CALL_SUCCESS;
   } else {
     // This may happen if we remove services from the list.
@@ -116,8 +118,8 @@
     const base::DictionaryValue& properties,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
-  for (base::DictionaryValue::Iterator iter(properties);
-       !iter.IsAtEnd(); iter.Advance()) {
+  for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
+       iter.Advance()) {
     if (!SetServiceProperty(service_path.value(), iter.key(), iter.value())) {
       LOG(ERROR) << "Service not found: " << service_path.value();
       error_callback.Run("Error.InvalidService", "Invalid Service");
@@ -132,13 +134,13 @@
     const std::string& name,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
-  base::DictionaryValue* dict = NULL;
-  if (!stub_services_.GetDictionaryWithoutPathExpansion(
-      service_path.value(), &dict)) {
+  base::DictionaryValue* dict = nullptr;
+  if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path.value(),
+                                                        &dict)) {
     error_callback.Run("Error.InvalidService", "Invalid Service");
     return;
   }
-  dict->RemoveWithoutPathExpansion(name, NULL);
+  dict->RemoveWithoutPathExpansion(name, nullptr);
   // Note: Shill does not send notifications when properties are cleared.
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
@@ -168,7 +170,7 @@
                                      const base::Closure& callback,
                                      const ErrorCallback& error_callback) {
   VLOG(1) << "FakeShillServiceClient::Connect: " << service_path.value();
-  base::DictionaryValue* service_properties = NULL;
+  base::DictionaryValue* service_properties = nullptr;
   if (!stub_services_.GetDictionary(service_path.value(),
                                     &service_properties)) {
     LOG(ERROR) << "Service not found: " << service_path.value();
@@ -303,14 +305,16 @@
     const std::string& state,
     const std::string& ipconfig_path,
     bool visible) {
-  base::DictionaryValue* properties = SetServiceProperties(
-      service_path, guid, name, type, state, visible);
+  base::DictionaryValue* properties =
+      SetServiceProperties(service_path, guid, name, type, state, visible);
 
   if (!ipconfig_path.empty())
     properties->SetKey(shill::kIPConfigProperty, base::Value(ipconfig_path));
 
-  DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
-      AddManagerService(service_path, true);
+  DBusThreadManager::Get()
+      ->GetShillManagerClient()
+      ->GetTestInterface()
+      ->AddManagerService(service_path, true);
 }
 
 base::DictionaryValue* FakeShillServiceClient::SetServiceProperties(
@@ -359,20 +363,27 @@
                        base::Value(shill::kSecurityNone));
     properties->SetKey(shill::kModeProperty, base::Value(shill::kModeManaged));
   }
+
+  // Ethernet is always connectable;
+  if (type == shill::kTypeEthernet)
+    properties->SetKey(shill::kConnectableProperty, base::Value(true));
+
   return properties;
 }
 
 void FakeShillServiceClient::RemoveService(const std::string& service_path) {
-  stub_services_.RemoveWithoutPathExpansion(service_path, NULL);
+  stub_services_.RemoveWithoutPathExpansion(service_path, nullptr);
   connect_behavior_.erase(service_path);
-  DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
-      RemoveManagerService(service_path);
+  DBusThreadManager::Get()
+      ->GetShillManagerClient()
+      ->GetTestInterface()
+      ->RemoveManagerService(service_path);
 }
 
 bool FakeShillServiceClient::SetServiceProperty(const std::string& service_path,
                                                 const std::string& property,
                                                 const base::Value& value) {
-  base::DictionaryValue* dict = NULL;
+  base::DictionaryValue* dict = nullptr;
   if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path, &dict))
     return false;
 
@@ -397,7 +408,7 @@
     provider->SetKey(key, value.Clone());
     changed_property = shill::kProviderProperty;
   } else if (value.is_dict()) {
-    const base::DictionaryValue* new_dict = NULL;
+    const base::DictionaryValue* new_dict = nullptr;
     value.GetAsDictionary(&new_dict);
     CHECK(new_dict);
     std::unique_ptr<base::Value> cur_value;
@@ -416,6 +427,18 @@
     changed_property = property;
   }
 
+  // Make PSK networks connectable if 'Passphrase' is set.
+  if (changed_property == shill::kPassphraseProperty && value.is_string() &&
+      !value.GetString().empty()) {
+    new_properties.SetKey(shill::kPassphraseRequiredProperty,
+                          base::Value(false));
+    base::Value* security = dict->FindKey(shill::kSecurityClassProperty);
+    if (security && security->is_string() &&
+        security->GetString() == shill::kSecurityPsk) {
+      new_properties.SetKey(shill::kConnectableProperty, base::Value(true));
+    }
+  }
+
   dict->MergeDictionary(&new_properties);
 
   // Add or update the profile entry.
@@ -431,8 +454,9 @@
     }
   } else {
     std::string profile_path;
-    if (dict->GetStringWithoutPathExpansion(
-            shill::kProfileProperty, &profile_path) && !profile_path.empty()) {
+    if (dict->GetStringWithoutPathExpansion(shill::kProfileProperty,
+                                            &profile_path) &&
+        !profile_path.empty()) {
       profile_test->UpdateService(profile_path, service_path);
     }
   }
@@ -441,8 +465,10 @@
   if (property == shill::kStateProperty) {
     std::string state;
     value.GetAsString(&state);
-    DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
-        ServiceStateChanged(service_path, state);
+    DBusThreadManager::Get()
+        ->GetShillManagerClient()
+        ->GetTestInterface()
+        ->ServiceStateChanged(service_path, state);
   }
 
   // If the State or Visibility changes, the sort order of service lists may
@@ -464,37 +490,38 @@
 
 const base::DictionaryValue* FakeShillServiceClient::GetServiceProperties(
     const std::string& service_path) const {
-  const base::DictionaryValue* properties = NULL;
+  const base::DictionaryValue* properties = nullptr;
   stub_services_.GetDictionaryWithoutPathExpansion(service_path, &properties);
   return properties;
 }
 
 void FakeShillServiceClient::ClearServices() {
-  DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
-      ClearManagerServices();
+  DBusThreadManager::Get()
+      ->GetShillManagerClient()
+      ->GetTestInterface()
+      ->ClearManagerServices();
 
   stub_services_.Clear();
   connect_behavior_.clear();
 }
 
 void FakeShillServiceClient::SetConnectBehavior(const std::string& service_path,
-                                const base::Closure& behavior) {
+                                                const base::Closure& behavior) {
   connect_behavior_[service_path] = behavior;
 }
 
 void FakeShillServiceClient::NotifyObserversPropertyChanged(
     const dbus::ObjectPath& service_path,
     const std::string& property) {
-  base::DictionaryValue* dict = NULL;
+  base::DictionaryValue* dict = nullptr;
   std::string path = service_path.value();
   if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &dict)) {
     LOG(ERROR) << "Notify for unknown service: " << path;
     return;
   }
-  base::Value* value = NULL;
+  base::Value* value = nullptr;
   if (!dict->GetWithoutPathExpansion(property, &value)) {
-    LOG(ERROR) << "Notify for unknown property: "
-               << path << " : " << property;
+    LOG(ERROR) << "Notify for unknown property: " << path << " : " << property;
     return;
   }
   for (auto& observer : GetObserverList(service_path))
@@ -502,8 +529,9 @@
 }
 
 base::DictionaryValue* FakeShillServiceClient::GetModifiableServiceProperties(
-    const std::string& service_path, bool create_if_missing) {
-  base::DictionaryValue* properties = NULL;
+    const std::string& service_path,
+    bool create_if_missing) {
+  base::DictionaryValue* properties = nullptr;
   if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path,
                                                         &properties) &&
       create_if_missing) {
@@ -525,8 +553,8 @@
 
 void FakeShillServiceClient::SetOtherServicesOffline(
     const std::string& service_path) {
-  const base::DictionaryValue* service_properties = GetServiceProperties(
-      service_path);
+  const base::DictionaryValue* service_properties =
+      GetServiceProperties(service_path);
   if (!service_properties) {
     LOG(ERROR) << "Missing service: " << service_path;
     return;
@@ -534,8 +562,8 @@
   std::string service_type;
   service_properties->GetString(shill::kTypeProperty, &service_type);
   // Set all other services of the same type to offline (Idle).
-  for (base::DictionaryValue::Iterator iter(stub_services_);
-       !iter.IsAtEnd(); iter.Advance()) {
+  for (base::DictionaryValue::Iterator iter(stub_services_); !iter.IsAtEnd();
+       iter.Advance()) {
     std::string path = iter.key();
     if (path == service_path)
       continue;
@@ -563,7 +591,7 @@
 
 void FakeShillServiceClient::ContinueConnect(const std::string& service_path) {
   VLOG(1) << "FakeShillServiceClient::ContinueConnect: " << service_path;
-  base::DictionaryValue* service_properties = NULL;
+  base::DictionaryValue* service_properties = nullptr;
   if (!stub_services_.GetDictionary(service_path, &service_properties)) {
     LOG(ERROR) << "Service not found: " << service_path;
     return;
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
index 576b9858..1138fb77 100644
--- a/chromeos/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -432,7 +432,9 @@
   // The passphrase isn't sent again, because it's configured by the user and
   // Shill doesn't send it on GetProperties calls.
   expected_shill_properties->RemoveWithoutPathExpansion(
-      shill::kPassphraseProperty, NULL);
+      shill::kPassphraseProperty, nullptr);
+  expected_shill_properties->RemoveWithoutPathExpansion(
+      shill::kPassphraseRequiredProperty, nullptr);
 
   // Before setting policy, old_entry_path should exist.
   ASSERT_TRUE(GetShillProfileClient()->HasService("old_entry_path"));
@@ -527,7 +529,9 @@
   // The passphrase isn't sent again, because it's configured by the user and
   // Shill doesn't send it on GetProperties calls.
   expected_shill_properties->RemoveWithoutPathExpansion(
-      shill::kPassphraseProperty, NULL);
+      shill::kPassphraseProperty, nullptr);
+  expected_shill_properties->RemoveWithoutPathExpansion(
+      shill::kPassphraseRequiredProperty, nullptr);
 
   SetPolicy(::onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
   base::RunLoop().RunUntilIdle();
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index fd28bb4..b092034 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -1449,10 +1449,11 @@
 
   // Note: usually active networks will precede inactive networks, however
   // this may briefly be untrue during state transitions (e.g. a network may
-  // transition to idle before the list is updated). Also separate Cellular
-  // networks (see below).
-  ManagedStateList cellular, active, non_wifi_visible, wifi_visible, hidden,
-      new_networks;
+  // transition to idle before the list is updated). Also separate inactive
+  // Mobile and VPN networks (see below).
+  ManagedStateList active, non_wifi_visible, wifi_visible, hidden, new_networks;
+  int cellular_count = 0;
+  bool have_default_cellular = false;
   for (ManagedStateList::iterator iter = network_list_.begin();
        iter != network_list_.end(); ++iter) {
     NetworkState* network = (*iter)->AsNetworkState();
@@ -1463,30 +1464,36 @@
       continue;
     }
     if (NetworkTypePattern::Cellular().MatchesType(network->type())) {
-      cellular.push_back(std::move(*iter));
-      continue;
+      ++cellular_count;
+      if ((*iter)->AsNetworkState()->IsDefaultCellular())
+        have_default_cellular = true;
     }
     if (network->IsConnectingOrConnected()) {
       active.push_back(std::move(*iter));
       continue;
     }
-    if (network->visible()) {
-      if (NetworkTypePattern::WiFi().MatchesType(network->type()))
-        wifi_visible.push_back(std::move(*iter));
-      else
-        non_wifi_visible.push_back(std::move(*iter));
-    } else {
+    if (!network->visible()) {
       hidden.push_back(std::move(*iter));
+      continue;
     }
+    if (NetworkTypePattern::WiFi().MatchesType(network->type()))
+      wifi_visible.push_back(std::move(*iter));
+    else
+      non_wifi_visible.push_back(std::move(*iter));
   }
-  if (ensure_cellular)
-    EnsureCellularNetwork(&cellular);
-  // List active non Cellular network first.
+
+  // List active networks first (will always include Ethernet).
   network_list_ = std::move(active);
-  // Ethernet is always active so list any Cellular network next.
-  std::move(cellular.begin(), cellular.end(),
-            std::back_inserter(network_list_));
-  // List any other non WiFi visible networks (i.e. WiMAX).
+
+  // If a default Cellular network is required, add it next.
+  if (ensure_cellular && cellular_count == 0) {
+    std::unique_ptr<NetworkState> default_cellular =
+        MaybeCreateDefaultCellularNetwork();
+    if (default_cellular)
+      network_list_.push_back(std::move(default_cellular));
+  }
+
+  // List non wifi visible networks next (Mobile and VPN).
   std::move(non_wifi_visible.begin(), non_wifi_visible.end(),
             std::back_inserter(network_list_));
   // List WiFi networks last.
@@ -1498,6 +1505,11 @@
   std::move(new_networks.begin(), new_networks.end(),
             std::back_inserter(network_list_));
   network_list_sorted_ = true;
+
+  // If we have > 1 Cellular NetworkState and we have created a default Cellular
+  // NetworkState, remove it.
+  if (ensure_cellular && cellular_count > 1 && have_default_cellular)
+    RemoveDefaultCellularNetwork();
 }
 
 void NetworkStateHandler::UpdateNetworkStats() {
@@ -1622,40 +1634,30 @@
                                     portal_iter->second.name);
 }
 
-void NetworkStateHandler::EnsureCellularNetwork(
-    ManagedStateList* cellular_networks) {
+std::unique_ptr<NetworkState>
+NetworkStateHandler::MaybeCreateDefaultCellularNetwork() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK(!notifying_network_observers_);
   const DeviceState* device =
       GetDeviceStateByType(NetworkTypePattern::Cellular());
-  if (!device) {
-    cellular_networks->clear();
-    return;
-  }
-  if (cellular_networks->empty()) {
-    // If no SIM is present there will not be useful user facing Device
-    // information, so do not create a default Cellular network.
-    if (device->IsSimAbsent())
-      return;
-    // Create a default Cellular network. Properties from the associated Device
-    // will be provided to the UI.
-    std::unique_ptr<NetworkState> network =
-        NetworkState::CreateDefaultCellular(device->path());
-    network->set_name(device->GetName());
-    UpdateGuid(network.get());
-    cellular_networks->push_back(std::move(network));
-    return;
-  }
-  if (cellular_networks->size() == 1)
-    return;
-  // If we have > 1 Cellular NetworkState, then Shill provided a Cellular
-  // Service after the default Cellular NetworkState was created, so remove the
-  // default state.
-  for (auto iter = cellular_networks->begin(); iter != cellular_networks->end();
-       ++iter) {
+  // If no SIM is present there will not be useful user facing Device
+  // information, so do not create a default Cellular network.
+  if (!device || device->IsSimAbsent())
+    return nullptr;
+  // Create a default Cellular network. Properties from the associated Device
+  // will be provided to the UI.
+  std::unique_ptr<NetworkState> network =
+      NetworkState::CreateDefaultCellular(device->path());
+  network->set_name(device->GetName());
+  UpdateGuid(network.get());
+  return network;
+}
+
+void NetworkStateHandler::RemoveDefaultCellularNetwork() {
+  for (auto iter = network_list_.begin(); iter != network_list_.end(); ++iter) {
     if ((*iter)->AsNetworkState()->IsDefaultCellular()) {
-      cellular_networks->erase(iter);
-      break;  // There will only ever be one default Cellular network.
+      network_list_.erase(iter);
+      return;  // There will only ever be one default Cellular network.
     }
   }
 }
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index 89010fe..d7837990 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -479,10 +479,13 @@
   void UpdateCaptivePortalProvider(NetworkState* network);
 
   // Cellular networks may not have an associated Shill Service (e.g. when the
-  // SIM is locked or a mobile network is not available). To simplify the UI,
-  // if a Cellular Device exists |cellular_networks| will be modified to contain
-  // exactly one network, creating a default network if necessary.
-  void EnsureCellularNetwork(ManagedStateList* cellular_networks);
+  // SIM is locked or a mobile network is not available). This returns a new
+  // default cellular network if necessary.
+  std::unique_ptr<NetworkState> MaybeCreateDefaultCellularNetwork();
+
+  // Removes the default Cellular network if it exists. Called when there is
+  // more than one Cellular network in the list.
+  void RemoveDefaultCellularNetwork();
 
   // Sends NetworkListChanged() to observers and logs an event.
   void NotifyNetworkListChanged();
diff --git a/chromeos/network/shill_property_handler_unittest.cc b/chromeos/network/shill_property_handler_unittest.cc
index 6b991e4..a9f19bf 100644
--- a/chromeos/network/shill_property_handler_unittest.cc
+++ b/chromeos/network/shill_property_handler_unittest.cc
@@ -388,12 +388,12 @@
   EXPECT_EQ(1, listener_->property_updates(
       shill::kServiceCompleteListProperty)[kTestServicePath]);
 
-  // Change the visibility of a service. This will trigger a service list
-  // updates.
+  // Set the state of the service to Connected. This will trigger a service list
+  // update.
   listener_->reset_list_updates();
   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
-      dbus::ObjectPath(kTestServicePath), shill::kVisibleProperty,
-      base::Value(false), base::DoNothing(),
+      dbus::ObjectPath(kTestServicePath), shill::kStateProperty,
+      base::Value(shill::kStateReady), base::DoNothing(),
       base::Bind(&ErrorCallbackFunction));
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index 9a52559..6a71654d4 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -972,7 +972,7 @@
 
 void AssistantManagerServiceImpl::OnShowNotificationOnMainThread(
     const mojom::AssistantNotificationPtr& notification) {
-  service_->assistant_notification_controller()->AddNotification(
+  service_->assistant_notification_controller()->AddOrUpdateNotification(
       notification.Clone());
 }
 
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc
index 3ebcb11f..86e511f 100644
--- a/chromeos/services/assistant/public/features.cc
+++ b/chromeos/services/assistant/public/features.cc
@@ -28,6 +28,9 @@
 const base::Feature kTimerNotification{"ChromeOSAssistantTimerNotification",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kTimerTicks{"ChromeOSAssistantTimerTicks",
+                                base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool IsDspHotwordEnabled() {
   return base::FeatureList::IsEnabled(kEnableDspHotword);
 }
@@ -40,6 +43,10 @@
   return base::FeatureList::IsEnabled(kTimerNotification);
 }
 
+bool IsTimerTicksEnabled() {
+  return base::FeatureList::IsEnabled(kTimerTicks);
+}
+
 bool IsWarmerWelcomeEnabled() {
   return base::FeatureList::IsEnabled(kAssistantWarmerWelcomeFeature);
 }
diff --git a/chromeos/services/assistant/public/features.h b/chromeos/services/assistant/public/features.h
index b18d976..1e52c89 100644
--- a/chromeos/services/assistant/public/features.h
+++ b/chromeos/services/assistant/public/features.h
@@ -36,12 +36,22 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kTimerNotification;
 
+// Enables timer ticks. This feature causes alarms/timers tracked by the
+// AssistantAlarmTimerController to tick at a fixed interval, delivering updates
+// to AssistantAlarmTimerModelObservers of time remaining/elapsed since expiry.
+// When enabled in conjunction with |kTimerNotification|, Assistant alarm/timer
+// notifications will be updated at each tick.
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+extern const base::Feature kTimerTicks;
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsDspHotwordEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsStereoAudioInputEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsTimerNotificationEnabled();
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsTimerTicksEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsWarmerWelcomeEnabled();
 
 }  // namespace features
diff --git a/chromeos/test/data/network/policy/shill_managed_wifi1.json b/chromeos/test/data/network/policy/shill_managed_wifi1.json
index 469251c..4a4cc69 100644
--- a/chromeos/test/data/network/policy/shill_managed_wifi1.json
+++ b/chromeos/test/data/network/policy/shill_managed_wifi1.json
@@ -5,6 +5,7 @@
   "GUID": "policy2_wifi1",
   "Mode": "managed",
   "Passphrase": "user's passphrase",
+  "PassphraseRequired": false,
   "Profile": "/profile/user1/shill",
   "Security": "802_1x",
   "Type": "wifi",
diff --git a/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_wifi1.json b/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_wifi1.json
index 3253959..e032113 100644
--- a/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_wifi1.json
+++ b/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_wifi1.json
@@ -6,6 +6,7 @@
   "Mode": "managed",
   "Name": "policy_wifi1",
   "Passphrase": "policy's passphrase",
+  "PassphraseRequired": false,
   "Profile": "/profile/user1/shill",
   "SSID": "policy_wifi1",
   "SecurityClass": "psk",
diff --git a/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json b/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json
index e507d31..f824e36 100644
--- a/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json
+++ b/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json
@@ -4,6 +4,7 @@
   "Mode": "managed",
   "Name": "policy_wifi1",
   "Passphrase": "policy's passphrase",
+  "PassphraseRequired": false,
   "Profile": "/profile/user1/shill",
   "SSID": "policy_wifi1",
   "SecurityClass": "psk",
diff --git a/chromeos/test/data/network/policy/shill_policy_on_unmanaged_wifi1.json b/chromeos/test/data/network/policy/shill_policy_on_unmanaged_wifi1.json
index 3f856a1..14b198d 100644
--- a/chromeos/test/data/network/policy/shill_policy_on_unmanaged_wifi1.json
+++ b/chromeos/test/data/network/policy/shill_policy_on_unmanaged_wifi1.json
@@ -4,6 +4,7 @@
   "Mode": "managed",
   "Name": "policy_wifi1",
   "Passphrase": "user's passphrase",
+  "PassphraseRequired": false,
   "Profile": "/profile/user1/shill",
   "SSID": "policy_wifi1",
   "SecurityClass": "psk",
diff --git a/chromeos/test/data/network/policy/shill_unmanaged_wifi1.json b/chromeos/test/data/network/policy/shill_unmanaged_wifi1.json
index 9467416..04d564f 100644
--- a/chromeos/test/data/network/policy/shill_unmanaged_wifi1.json
+++ b/chromeos/test/data/network/policy/shill_unmanaged_wifi1.json
@@ -2,6 +2,7 @@
   "GUID": "{unmanaged_user_wifi1}",
   "Mode": "managed",
   "Passphrase": "user's passphrase",
+  "PassphraseRequired": false,
   "Profile": "/profile/user1/shill",
   "WiFi.HexSSID": "7769666931", // "wifi1"
   "SecurityClass": "psk",
diff --git a/chromeos/test/data/network/policy/shill_unmanaged_wifi2.json b/chromeos/test/data/network/policy/shill_unmanaged_wifi2.json
index b86da65..2c877e1 100644
--- a/chromeos/test/data/network/policy/shill_unmanaged_wifi2.json
+++ b/chromeos/test/data/network/policy/shill_unmanaged_wifi2.json
@@ -3,6 +3,7 @@
   "GUID": "wifi2",
   "Mode": "managed",
   "Passphrase": "user's passphrase",
+  "PassphraseRequired": false,
   "Profile": "/profile/user1/shill",
   "SecurityClass": "psk",
   "Type": "wifi",
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index bc3fc31..362668b8 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -220,7 +220,6 @@
                                                  &presentation_callbacks_);
   frame.metadata.frame_token = ++next_token_;
   if (!presentation_callbacks_.empty()) {
-    frame.metadata.request_presentation_feedback = true;
     DCHECK_EQ(active_presentation_callbacks_.count(*next_token_), 0u);
     active_presentation_callbacks_[*next_token_] =
         std::move(presentation_callbacks_);
diff --git a/components/safe_browsing/base_ui_manager.h b/components/safe_browsing/base_ui_manager.h
index 2321da8a..77a7ec8 100644
--- a/components/safe_browsing/base_ui_manager.h
+++ b/components/safe_browsing/base_ui_manager.h
@@ -46,6 +46,12 @@
   // protocol buffer.
   virtual void SendSerializedThreatDetails(const std::string& serialized);
 
+  // Updates the whitelist URL set for |web_contents|. Called on the UI thread.
+  void AddToWhitelistUrlSet(const GURL& whitelist_url,
+                            content::WebContents* web_contents,
+                            bool is_pending,
+                            SBThreatType threat_type);
+
   // This is a no-op in the base class, but should be overridden to report hits
   // to the unsafe contents (malware, phishing, unsafe download URL)
   // to the server. Can only be called on UI thread. Will only upload a hit
@@ -102,12 +108,6 @@
   friend class ChromePasswordProtectionService;
   virtual ~BaseUIManager();
 
-  // Updates the whitelist URL set for |web_contents|. Called on the UI thread.
-  void AddToWhitelistUrlSet(const GURL& whitelist_url,
-                            content::WebContents* web_contents,
-                            bool is_pending,
-                            SBThreatType threat_type);
-
   // Removes |whitelist_url| from the whitelist for |web_contents|.
   // Called on the UI thread.
   void RemoveWhitelistUrlSet(const GURL& whitelist_url,
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 1d7b421..f6c6984 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -16,6 +16,7 @@
     "close.icon",
     "close_rounded.icon",
     "edit.icon",
+    "error.icon",
     "ethernet.icon",
     "folder.icon",
     "folder_managed.icon",
diff --git a/components/vector_icons/error.icon b/components/vector_icons/error.icon
new file mode 100644
index 0000000..d018788
--- /dev/null
+++ b/components/vector_icons/error.icon
@@ -0,0 +1,23 @@
+// 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.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 8, 0.91f,
+CUBIC_TO, 4.07f, 0.91f, 0.89f, 4.1f, 0.89f, 8.03f,
+CUBIC_TO, 0.89f, 11.96f, 4.07f, 15.14f, 8, 15.14f,
+CUBIC_TO, 11.93f, 15.14f, 15.11f, 11.96f, 15.11f, 8.03f,
+CUBIC_TO, 15.11f, 4.1f, 11.93f, 0.91f, 8, 0.91f,
+CLOSE,
+MOVE_TO, 8.89f, 11.55f,
+LINE_TO, 7.11f, 11.55f,
+LINE_TO, 7.11f, 9.78f,
+LINE_TO, 8.89f, 9.78f,
+CLOSE,
+MOVE_TO, 8.89f, 8.89f,
+LINE_TO, 7.11f, 8.89f,
+LINE_TO, 7.11f, 4.45f,
+LINE_TO, 8.89f, 4.45f,
+CLOSE,
+MOVE_TO, 8.89f, 8.89f,
+CLOSE
diff --git a/components/viz/common/quads/compositor_frame_metadata.h b/components/viz/common/quads/compositor_frame_metadata.h
index 63411ee..e2f3fbc 100644
--- a/components/viz/common/quads/compositor_frame_metadata.h
+++ b/components/viz/common/quads/compositor_frame_metadata.h
@@ -137,11 +137,6 @@
   // wants to do something after a particular frame is processed.
   bool send_frame_token_to_embedder = false;
 
-  // Once the display compositor presents a frame with
-  // |request_presentation_feedback| flag turned on, a presentation feedback
-  // will be provided to CompositorFrameSinkClient.
-  bool request_presentation_feedback = true;
-
   // These limits can be used together with the scroll/scale fields above to
   // determine if scrolling/scaling in a particular direction is possible.
   float min_page_scale_factor = 0.f;
diff --git a/components/viz/host/host_frame_sink_manager_unittest.cc b/components/viz/host/host_frame_sink_manager_unittest.cc
index 703b16d4..9fcb12a7 100644
--- a/components/viz/host/host_frame_sink_manager_unittest.cc
+++ b/components/viz/host/host_frame_sink_manager_unittest.cc
@@ -271,7 +271,6 @@
 TEST_F(HostFrameSinkManagerLocalTest, CommunicateFrameToken) {
   FakeHostFrameSinkClient host_client_parent;
   FakeHostFrameSinkClient host_client_child;
-  uint32_t frame_token1 = 10u;
   FrameSinkId kParentFrameSink(3, 0);
   FrameSinkId kChildFrameSink1(65563, 0);
   const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
@@ -285,10 +284,11 @@
 
   CompositorFrame compositor_frame = CompositorFrameBuilder()
                                          .AddDefaultRenderPass()
-                                         .SetFrameToken(frame_token1)
                                          .SetSendFrameTokenToEmbedder(true)
                                          .SetActivationDependencies({child_id1})
                                          .Build();
+  uint32_t frame_token = compositor_frame.metadata.frame_token;
+  ASSERT_NE(frame_token, 0u);
   support->SubmitCompositorFrame(parent_id1.local_surface_id(),
                                  std::move(compositor_frame));
 
@@ -306,7 +306,7 @@
   EXPECT_FALSE(parent_surface->HasPendingFrame());
   // Since the frame is now activated, |frame_token| is sent to
   // HostFrameSinkClient.
-  EXPECT_EQ(10u, host_client_parent.last_frame_token_seen());
+  EXPECT_EQ(frame_token, host_client_parent.last_frame_token_seen());
 }
 
 // Verify that that creating two CompositorFrameSinkSupports works.
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 53618df..dcf7c638 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -397,18 +397,17 @@
   if (!skip_drawing_root_render_pass)
     DrawRenderPassAndExecuteCopyRequests(root_render_pass);
 
-  // Use a fence to synchronize display of the overlays. Note that gpu_fence_id
-  // may have the special value 0 ("no fence") if fences are not supported. In
-  // that case synchronization will happen through other means on the service
-  // side. We are currently using the output surface fence for all the overlays,
-  // which is functionally correct due to the position of this fence in the
-  // command stream.
+  // Use a fence to synchronize display of the main fb used by the output
+  // surface. Note that gpu_fence_id may have the special value 0 ("no fence")
+  // if fences are not supported. In that case synchronization will happen
+  // through other means on the service side.
   // TODO(afrantzis): Consider using per-overlay fences instead of the one
   // associated with the output surface when possible.
   if (!current_frame()->overlay_list.empty()) {
-    auto gpu_fence_id = output_surface_->UpdateGpuFence();
-    for (auto& overlay : current_frame()->overlay_list)
-      overlay.gpu_fence_id = gpu_fence_id;
+    for (auto& overlay : current_frame()->overlay_list) {
+      if (overlay.use_output_surface_for_resource)
+        overlay.gpu_fence_id = output_surface_->UpdateGpuFence();
+    }
   }
 
   FinishDrawingFrame();
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index 5223eaf6..f0f3ebc0 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -3282,7 +3282,6 @@
     CompositorFrame frame =
         CompositorFrameBuilder()
             .AddRenderPass(gfx::Rect(sub_surface_size), gfx::Rect())
-            .SetRequestPresentationFeedback(true)
             .Build();
     EXPECT_CALL(sub_client, DidReceiveCompositorFrameAck(_)).Times(1);
     frame_token_1 = frame.metadata.frame_token;
@@ -3332,7 +3331,6 @@
     CompositorFrame frame = CompositorFrameBuilder()
                                 .AddRenderPass(gfx::Rect(sub_surface_size),
                                                gfx::Rect(sub_surface_size))
-                                .SetRequestPresentationFeedback(true)
                                 .Build();
     frame_token_2 = frame.metadata.frame_token;
 
@@ -3352,7 +3350,6 @@
     CompositorFrame frame =
         CompositorFrameBuilder()
             .AddRenderPass(gfx::Rect(sub_surface_size), gfx::Rect())
-            .SetRequestPresentationFeedback(true)
             .Build();
 
     EXPECT_CALL(sub_client, DidReceiveCompositorFrameAck(_)).Times(1);
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 75dd5c9..3c24c62 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -4092,6 +4092,7 @@
 
   static constexpr unsigned kSurfaceOverlayTextureId = 33;
   static constexpr unsigned kGpuFenceId = 66;
+  static constexpr unsigned kGpuNoFenceId = 0;
 
   TestContextSupport* test_context_support_;
 
@@ -4105,7 +4106,7 @@
   MockOverlayScheduler overlay_scheduler;
 };
 
-TEST_F(GLRendererWithGpuFenceTest, GpuFenceIdIsUsedWithRootRenderPass) {
+TEST_F(GLRendererWithGpuFenceTest, GpuFenceIdIsUsedWithRootRenderPassOverlay) {
   gfx::Size viewport_size(100, 100);
   RenderPass* root_pass = cc::AddRenderPass(
       &render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
@@ -4119,7 +4120,8 @@
   DrawFrame(renderer_.get(), viewport_size);
 }
 
-TEST_F(GLRendererWithGpuFenceTest, GpuFenceIdIsUsedWithoutRootRenderPass) {
+TEST_F(GLRendererWithGpuFenceTest,
+       GpuFenceIdIsUsedOnlyForRootRenderPassOverlay) {
   gfx::Size viewport_size(100, 100);
   RenderPass* root_pass = cc::AddRenderPass(
       &render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
@@ -4134,14 +4136,12 @@
   gfx::PointF uv_top_left(0, 0);
   gfx::PointF uv_bottom_right(1, 1);
 
-  // Add a draw quad covering the whole viewport. This causes the root
-  // render pass to be skipped.
   TextureDrawQuad* overlay_quad =
       root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
-                       gfx::Rect(viewport_size), gfx::Rect(viewport_size),
-                       false, false, 1, SkBlendMode::kSrcOver, 0);
+                       gfx::Rect(50, 50), gfx::Rect(viewport_size), false,
+                       false, 1, SkBlendMode::kSrcOver, 0);
   overlay_quad->SetNew(
       shared_state, gfx::Rect(viewport_size), gfx::Rect(viewport_size),
       needs_blending, create_overlay_resource(), premultiplied_alpha,
@@ -4155,7 +4155,7 @@
       .Times(1);
   EXPECT_CALL(overlay_scheduler,
               Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _,
-                       gfx::Rect(viewport_size), _, _, kGpuFenceId))
+                       gfx::Rect(viewport_size), _, _, kGpuNoFenceId))
       .Times(1);
   DrawFrame(renderer_.get(), viewport_size);
 }
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 68f25c8..4851019 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -414,7 +414,7 @@
         shared_image_representation_factory_->ProduceSkia(
             metadata.mailbox_holder.mailbox);
     DCHECK(shared_image);
-    if (!shared_image->BeginReadAccess(backend_texture)) {
+    if (!shared_image->BeginReadAccess(sk_surface_.get(), backend_texture)) {
       DLOG(ERROR)
           << "Failed to begin read access for SharedImageRepresentationSkia";
       return;
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index baf56be..77454aa71 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -360,10 +360,10 @@
 
   ++ack_pending_count_;
 
-  base::ScopedClosureRunner frame_rejected_callback(base::BindOnce(
-      &CompositorFrameSinkSupport::DidRejectCompositorFrame,
-      weak_factory_.GetWeakPtr(), frame.metadata.frame_token,
-      frame.metadata.request_presentation_feedback, frame.resource_list));
+  base::ScopedClosureRunner frame_rejected_callback(
+      base::BindOnce(&CompositorFrameSinkSupport::DidRejectCompositorFrame,
+                     weak_factory_.GetWeakPtr(), frame.metadata.frame_token,
+                     frame.resource_list));
 
   compositor_frame_callback_ = std::move(callback);
   if (compositor_frame_callback_) {
@@ -488,11 +488,8 @@
 
   bool result = current_surface->QueueFrame(
       std::move(frame), frame_index, std::move(frame_rejected_callback),
-      frame.metadata.request_presentation_feedback
-          ? base::BindOnce(
-                &CompositorFrameSinkSupport::DidPresentCompositorFrame,
-                weak_factory_.GetWeakPtr(), frame.metadata.frame_token)
-          : Surface::PresentedCallback());
+      base::BindOnce(&CompositorFrameSinkSupport::DidPresentCompositorFrame,
+                     weak_factory_.GetWeakPtr(), frame.metadata.frame_token));
   if (!result) {
     TRACE_EVENT_INSTANT0("viz", "QueueFrame failed", TRACE_EVENT_SCOPE_THREAD);
     return SubmitResult::SURFACE_INVARIANTS_VIOLATION;
@@ -549,16 +546,13 @@
 
 void CompositorFrameSinkSupport::DidRejectCompositorFrame(
     uint32_t presentation_token,
-    bool request_presentation_feedback,
     std::vector<TransferableResource> frame_resource_list) {
   std::vector<ReturnedResource> resources =
       TransferableResource::ReturnResources(frame_resource_list);
   ReturnResources(resources);
   DidReceiveCompositorFrameAck();
-  if (request_presentation_feedback) {
-    DidPresentCompositorFrame(presentation_token,
-                              gfx::PresentationFeedback::Failure());
-  }
+  DidPresentCompositorFrame(presentation_token,
+                            gfx::PresentationFeedback::Failure());
 }
 
 void CompositorFrameSinkSupport::UpdateDisplayRootReference(
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index 0babe97..ef02c98 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -198,7 +198,6 @@
                                  const gfx::PresentationFeedback& feedback);
   void DidRejectCompositorFrame(
       uint32_t presentation_token,
-      bool request_presentation_feedback,
       std::vector<TransferableResource> frame_resource_list);
 
   // Update the display root reference with |surface|.
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 11570243..6bc4cf92 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -1120,12 +1120,12 @@
 TEST_F(CompositorFrameSinkSupportTest,
        OnFrameTokenUpdateAfterFirstSurfaceActivation) {
   LocalSurfaceId local_surface_id(1, kArbitraryToken);
-  uint32_t frame_token = 2u;
   auto frame = CompositorFrameBuilder()
                    .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token)
                    .SetSendFrameTokenToEmbedder(true)
                    .Build();
+  uint32_t frame_token = frame.metadata.frame_token;
+  ASSERT_NE(frame_token, 0u);
 
   testing::InSequence sequence;
   EXPECT_CALL(frame_sink_manager_client_, OnFirstSurfaceActivation(_));
diff --git a/components/viz/service/surfaces/surface_unittest.cc b/components/viz/service/surfaces/surface_unittest.cc
index 586b9ccb..7fbec7c 100644
--- a/components/viz/service/surfaces/surface_unittest.cc
+++ b/components/viz/service/surfaces/surface_unittest.cc
@@ -35,13 +35,14 @@
   auto support = std::make_unique<CompositorFrameSinkSupport>(
       &client, &frame_sink_manager, kArbitraryFrameSinkId, kIsRoot,
       kNeedsSyncPoints);
+  uint32_t frame_token = 0;
   {
     CompositorFrame frame =
         CompositorFrameBuilder()
             .AddRenderPass(gfx::Rect(kSurfaceSize), kDamageRect)
-            .SetFrameToken(1)
-            .SetRequestPresentationFeedback(true)
             .Build();
+    frame_token = frame.metadata.frame_token;
+    ASSERT_NE(frame_token, 0u);
     EXPECT_CALL(client, DidReceiveCompositorFrameAck(testing::_)).Times(1);
     support->SubmitCompositorFrame(local_surface_id, std::move(frame));
     testing::Mock::VerifyAndClearExpectations(&client);
@@ -53,13 +54,11 @@
     CompositorFrame frame =
         CompositorFrameBuilder()
             .AddRenderPass(gfx::Rect(kSurfaceSize), kDamageRect)
-            .SetFrameToken(2)
-            .SetRequestPresentationFeedback(true)
             .Build();
     EXPECT_CALL(client, DidReceiveCompositorFrameAck(testing::_)).Times(1);
     support->SubmitCompositorFrame(local_surface_id, std::move(frame));
     ASSERT_EQ(1u, support->presentation_feedbacks().size());
-    EXPECT_EQ(1u, support->presentation_feedbacks().begin()->first);
+    EXPECT_EQ(frame_token, support->presentation_feedbacks().begin()->first);
     testing::Mock::VerifyAndClearExpectations(&client);
   }
 }
diff --git a/components/viz/test/compositor_frame_helpers.cc b/components/viz/test/compositor_frame_helpers.cc
index 5ec1e0e7..86f6d86 100644
--- a/components/viz/test/compositor_frame_helpers.cc
+++ b/components/viz/test/compositor_frame_helpers.cc
@@ -115,12 +115,6 @@
   return *this;
 }
 
-CompositorFrameBuilder& CompositorFrameBuilder::SetFrameToken(
-    uint32_t frame_token) {
-  frame_->metadata.frame_token = frame_token;
-  return *this;
-}
-
 CompositorFrameBuilder& CompositorFrameBuilder::SetContentSourceId(
     uint32_t content_source_id) {
   frame_->metadata.content_source_id = content_source_id;
@@ -134,13 +128,6 @@
   return *this;
 }
 
-CompositorFrameBuilder& CompositorFrameBuilder::SetRequestPresentationFeedback(
-    bool request) {
-  DCHECK(frame_->metadata.frame_token);
-  frame_->metadata.request_presentation_feedback = request;
-  return *this;
-}
-
 CompositorFrame CompositorFrameBuilder::MakeInitCompositorFrame() const {
   static FrameTokenGenerator next_token;
   CompositorFrame frame;
diff --git a/components/viz/test/compositor_frame_helpers.h b/components/viz/test/compositor_frame_helpers.h
index 04826f41..eae9dfa 100644
--- a/components/viz/test/compositor_frame_helpers.h
+++ b/components/viz/test/compositor_frame_helpers.h
@@ -58,10 +58,8 @@
   CompositorFrameBuilder& SetActivationDependencies(
       std::vector<SurfaceId> activation_dependencies);
   CompositorFrameBuilder& SetDeadline(const FrameDeadline& deadline);
-  CompositorFrameBuilder& SetFrameToken(uint32_t frame_token);
   CompositorFrameBuilder& SetContentSourceId(uint32_t content_source_id);
   CompositorFrameBuilder& SetSendFrameTokenToEmbedder(bool send);
-  CompositorFrameBuilder& SetRequestPresentationFeedback(bool request);
 
  private:
   CompositorFrame MakeInitCompositorFrame() const;
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 0ca39d7..bce6285 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -2,9 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//tools/grit/grit_rule.gni")
 import("//build/config/nacl/config.gni")
 import("//ppapi/buildflags/buildflags.gni")
+import("//tools/grit/grit_rule.gni")
 
 # Applied by targets internal to content.
 config("content_implementation") {
@@ -128,7 +128,6 @@
     "//content/public/app:plugin_manifest",
     "//content/public/app:renderer_manifest",
     "//content/public/app:utility_manifest",
-    "//services/catalog:manifest",
   ]
 }
 
diff --git a/content/app/content_service_manager_main_delegate.cc b/content/app/content_service_manager_main_delegate.cc
index fc86a74..3a6bc4e 100644
--- a/content/app/content_service_manager_main_delegate.cc
+++ b/content/app/content_service_manager_main_delegate.cc
@@ -74,9 +74,9 @@
     config->is_broker_process = true;
 }
 
-std::unique_ptr<base::Value>
-ContentServiceManagerMainDelegate::CreateServiceCatalog() {
-  return nullptr;
+std::vector<service_manager::Manifest>
+ContentServiceManagerMainDelegate::GetServiceManifests() {
+  return std::vector<service_manager::Manifest>();
 }
 
 bool ContentServiceManagerMainDelegate::ShouldLaunchAsServiceProcess(
diff --git a/content/app/content_service_manager_main_delegate.h b/content/app/content_service_manager_main_delegate.h
index 6f32f97..864f2a5 100644
--- a/content/app/content_service_manager_main_delegate.h
+++ b/content/app/content_service_manager_main_delegate.h
@@ -30,7 +30,7 @@
   void ShutDownEmbedderProcess() override;
   service_manager::ProcessType OverrideProcessType() override;
   void OverrideMojoConfiguration(mojo::core::Configuration* config) override;
-  std::unique_ptr<base::Value> CreateServiceCatalog() override;
+  std::vector<service_manager::Manifest> GetServiceManifests() override;
   bool ShouldLaunchAsServiceProcess(
       const service_manager::Identity& identity) override;
   void AdjustServiceProcessCommandLine(
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 4075a29a8..3e4a430 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -872,8 +872,6 @@
     "frame_host/navigation_controller_impl.h",
     "frame_host/navigation_entry_impl.cc",
     "frame_host/navigation_entry_impl.h",
-    "frame_host/navigation_entry_screenshot_manager.cc",
-    "frame_host/navigation_entry_screenshot_manager.h",
     "frame_host/navigation_handle_impl.cc",
     "frame_host/navigation_handle_impl.h",
     "frame_host/navigation_request.cc",
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index bd16e1b..6b7f72e 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -149,7 +149,7 @@
 // static
 void ChildProcessLauncher::SetRegisteredFilesForService(
     const std::string& service_name,
-    catalog::RequiredFileMap required_files) {
+    std::map<std::string, base::FilePath> required_files) {
   ChildProcessLauncherHelper::SetRegisteredFilesForService(
       service_name, std::move(required_files));
 }
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index 26f1376..415d916d 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -210,7 +210,7 @@
   // for the service |service_name|.
   static void SetRegisteredFilesForService(
       const std::string& service_name,
-      catalog::RequiredFileMap required_files);
+      std::map<std::string, base::FilePath> required_files);
 
   // Resets all files registered by |SetRegisteredFilesForService|. Used to
   // support multiple shell context creation in unit_tests.
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h
index 4dbac12..9b93e1f 100644
--- a/content/browser/child_process_launcher_helper.h
+++ b/content/browser/child_process_launcher_helper.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_CHILD_PROCESS_LAUNCHER_HELPER_H_
 #define CONTENT_BROWSER_CHILD_PROCESS_LAUNCHER_HELPER_H_
 
+#include <map>
 #include <memory>
 
 #include "base/macros.h"
@@ -17,7 +18,6 @@
 #include "content/public/common/result_codes.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/system/invitation.h"
-#include "services/catalog/public/cpp/manifest_parsing_util.h"
 #include "services/service_manager/zygote/common/zygote_buildflags.h"
 
 #if !defined(OS_FUCHSIA)
@@ -182,7 +182,7 @@
 
   static void SetRegisteredFilesForService(
       const std::string& service_name,
-      catalog::RequiredFileMap required_files);
+      std::map<std::string, base::FilePath> required_files);
 
   static void ResetRegisteredFilesForTesting();
 
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc
index caacdf8..04bfd4ac 100644
--- a/content/browser/child_process_launcher_helper_android.cc
+++ b/content/browser/child_process_launcher_helper_android.cc
@@ -234,7 +234,7 @@
 // static
 void ChildProcessLauncherHelper::SetRegisteredFilesForService(
     const std::string& service_name,
-    catalog::RequiredFileMap required_files) {
+    std::map<std::string, base::FilePath> required_files) {
   SetFilesToShareForServicePosix(service_name, std::move(required_files));
 }
 
diff --git a/content/browser/child_process_launcher_helper_fuchsia.cc b/content/browser/child_process_launcher_helper_fuchsia.cc
index bd84693..06e1067 100644
--- a/content/browser/child_process_launcher_helper_fuchsia.cc
+++ b/content/browser/child_process_launcher_helper_fuchsia.cc
@@ -40,7 +40,7 @@
 // static
 void ChildProcessLauncherHelper::SetRegisteredFilesForService(
     const std::string& service_name,
-    catalog::RequiredFileMap required_files) {
+    std::map<std::string, base::FilePath> required_files) {
   // TODO(fuchsia): Implement this. (crbug.com/707031)
   NOTIMPLEMENTED();
 }
diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc
index c981f7f..c715a86d0 100644
--- a/content/browser/child_process_launcher_helper_linux.cc
+++ b/content/browser/child_process_launcher_helper_linux.cc
@@ -164,7 +164,7 @@
 // static
 void ChildProcessLauncherHelper::SetRegisteredFilesForService(
     const std::string& service_name,
-    catalog::RequiredFileMap required_files) {
+    std::map<std::string, base::FilePath> required_files) {
   SetFilesToShareForServicePosix(service_name, std::move(required_files));
 }
 
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc
index de7b7ff..d240f93 100644
--- a/content/browser/child_process_launcher_helper_mac.cc
+++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -254,7 +254,7 @@
 // static
 void ChildProcessLauncherHelper::SetRegisteredFilesForService(
     const std::string& service_name,
-    catalog::RequiredFileMap required_files) {
+    std::map<std::string, base::FilePath> required_files) {
   // No file passing from the manifest on Mac yet.
   DCHECK(required_files.empty());
 }
diff --git a/content/browser/child_process_launcher_helper_posix.cc b/content/browser/child_process_launcher_helper_posix.cc
index 15a9977..2ca43941 100644
--- a/content/browser/child_process_launcher_helper_posix.cc
+++ b/content/browser/child_process_launcher_helper_posix.cc
@@ -16,7 +16,6 @@
 #include "content/public/common/content_descriptors.h"
 #include "content/public/common/content_switches.h"
 #include "mojo/public/cpp/platform/platform_channel_endpoint.h"
-#include "services/catalog/public/cpp/manifest_parsing_util.h"
 #include "services/service_manager/embedder/shared_file_util.h"
 #include "services/service_manager/embedder/switches.h"
 
@@ -26,7 +25,7 @@
 namespace {
 
 using RequiredFilesByServiceMap =
-    std::map<std::string, catalog::RequiredFileMap>;
+    std::map<std::string, std::map<std::string, base::FilePath>>;
 
 RequiredFilesByServiceMap& GetRequiredFilesByServiceMap() {
   static auto* required_files_by_service = new RequiredFilesByServiceMap();
@@ -113,7 +112,8 @@
   const std::string& service_name = service_name_iter->second;
   auto files_iter = GetRequiredFilesByServiceMap().find(service_name);
   if (files_iter != GetRequiredFilesByServiceMap().end()) {
-    const catalog::RequiredFileMap& required_files_map = files_iter->second;
+    const std::map<std::string, base::FilePath>& required_files_map =
+        files_iter->second;
     base::GlobalDescriptors::Key key = kContentDynamicDescriptorStart;
     service_manager::SharedFileSwitchValueBuilder file_switch_value_builder;
     for (const auto& key_path_iter : required_files_map) {
@@ -137,8 +137,9 @@
   return files_to_register;
 }
 
-void SetFilesToShareForServicePosix(const std::string& service_name,
-                                    catalog::RequiredFileMap required_files) {
+void SetFilesToShareForServicePosix(
+    const std::string& service_name,
+    std::map<std::string, base::FilePath> required_files) {
   if (required_files.empty())
     return;
 
diff --git a/content/browser/child_process_launcher_helper_posix.h b/content/browser/child_process_launcher_helper_posix.h
index 956c6d3a..9622650 100644
--- a/content/browser/child_process_launcher_helper_posix.h
+++ b/content/browser/child_process_launcher_helper_posix.h
@@ -5,11 +5,11 @@
 #ifndef CONTENT_BROWSER_CHILD_PROCESS_LAUNCHER_HELPER_POSIX_H_
 #define CONTENT_BROWSER_CHILD_PROCESS_LAUNCHER_HELPER_POSIX_H_
 
+#include <map>
 #include <memory>
 
 #include "base/files/file.h"
 #include "base/files/memory_mapped_file.h"
-#include "services/catalog/public/cpp/manifest_parsing_util.h"
 
 namespace base {
 class CommandLine;
@@ -38,8 +38,9 @@
 
 // Called by the service manager to register the files that should be mapped for
 // a service in the child process.
-void SetFilesToShareForServicePosix(const std::string& service_name,
-                                    catalog::RequiredFileMap required_files);
+void SetFilesToShareForServicePosix(
+    const std::string& service_name,
+    std::map<std::string, base::FilePath> required_files);
 
 // Called from unit_tests in order to reset all previously registered files.
 void ResetFilesToShareForTestingPosix();
diff --git a/content/browser/child_process_launcher_helper_win.cc b/content/browser/child_process_launcher_helper_win.cc
index 4deb943..4aa0c71 100644
--- a/content/browser/child_process_launcher_helper_win.cc
+++ b/content/browser/child_process_launcher_helper_win.cc
@@ -121,7 +121,7 @@
 // static
 void ChildProcessLauncherHelper::SetRegisteredFilesForService(
     const std::string& service_name,
-    catalog::RequiredFileMap required_files) {
+    std::map<std::string, base::FilePath> required_files) {
   // No file passing from the manifest on Windows yet.
   DCHECK(required_files.empty());
 }
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 41d7b99..c3c9689 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -441,26 +441,8 @@
 }
 
 void ChildProcessSecurityPolicyImpl::Remove(int child_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::AutoLock lock(lock_);
-
-  auto state = security_state_.find(child_id);
-  if (state == security_state_.end())
-    return;
-
-  pending_remove_state_[child_id] = std::move(state->second);
   security_state_.erase(child_id);
-
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&ChildProcessSecurityPolicyImpl::RemovePendingIDOnIOThread,
-                     base::Unretained(this), child_id));
-}
-
-void ChildProcessSecurityPolicyImpl::RemovePendingIDOnIOThread(int child_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  base::AutoLock lock(lock_);
-  pending_remove_state_.erase(child_id);
 }
 
 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme(
@@ -1169,20 +1151,21 @@
       SiteInstanceImpl::DetermineProcessLockURL(nullptr, url);
 
   base::AutoLock lock(lock_);
-  SecurityState* security_state = GetSecurityState(child_id);
-
-  bool can_access = security_state && security_state->CanAccessDataForOrigin(
-                                          expected_process_lock);
+  auto state = security_state_.find(child_id);
+  if (state == security_state_.end()) {
+    // TODO(nick): Returning true instead of false here is a temporary
+    // workaround for https://crbug.com/600441
+    return true;
+  }
+  bool can_access =
+      state->second->CanAccessDataForOrigin(expected_process_lock);
   if (!can_access) {
     // Returning false here will result in a renderer kill.  Set some crash
     // keys that will help understand the circumstances of that kill.
     base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
                                    expected_process_lock.spec());
-
     base::debug::SetCrashKeyString(bad_message::GetKilledProcessOriginLockKey(),
-                                   security_state
-                                       ? security_state->origin_lock().spec()
-                                       : "(child id not found)");
+                                   state->second->origin_lock().spec());
 
     static auto* requested_origin_key = base::debug::AllocateCrashKeyString(
         "requested_origin", base::debug::CrashKeySize::Size64);
@@ -1384,22 +1367,4 @@
     isolated_origins_.erase(key);
 }
 
-ChildProcessSecurityPolicyImpl::SecurityState*
-ChildProcessSecurityPolicyImpl::GetSecurityState(int child_id) {
-  auto itr = security_state_.find(child_id);
-  if (itr != security_state_.end())
-    return itr->second.get();
-
-  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    // Checking to see if |child_id| is in the pending removal map since this
-    // may be a call that was already on the IO thread task queue when the
-    // Remove() call occurred on the UI thread.
-    itr = pending_remove_state_.find(child_id);
-    if (itr != pending_remove_state_.end())
-      return itr->second.get();
-  }
-
-  return nullptr;
-}
-
 }  // namespace content
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index 271a5685..82d5dd4 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -162,10 +162,6 @@
 
   // Upon destruction, child processess should unregister themselves by caling
   // this method exactly once.
-  //
-  // Note: IO thread is expected to keep pre-Remove() permissions until
-  // RemovePendingIDOnIOThread() runs on the IO thread. The UI thread is
-  // expected to have no permissions after Remove() returns.
   void Remove(int child_id);
 
   // Whenever the browser processes commands the child process to commit a URL,
@@ -371,14 +367,6 @@
       const std::string& filesystem_id,
       int permission);
 
-  // Removes |child_id| from |pending_remove_state_| on the IO thread.
-  void RemovePendingIDOnIOThread(int child_id);
-
-  // Gets the SecurityState object associated with |child_id|.
-  // Note: Returned object is only valid for the duration the caller holds
-  // |lock_|.
-  SecurityState* GetSecurityState(int child_id) EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
   // You must acquire this lock before reading or writing any members of this
   // class.  You must not block while holding this lock.
   base::Lock lock_;
@@ -400,13 +388,6 @@
   // not escape this class.
   SecurityStateMap security_state_ GUARDED_BY(lock_);
 
-  // This map holds the SecurityState for a child process after Remove()
-  // is called on the UI thread and until RemovePendingIDOnIOThread() is
-  // called on the IO thread. This is necessary to provide consistent
-  // security decisions and avoid races between the UI & IO threads during
-  // child process shutdown.
-  SecurityStateMap pending_remove_state_ GUARDED_BY(lock_);
-
   FileSystemPermissionPolicyMap file_system_policy_map_ GUARDED_BY(lock_);
 
   // Tracks origins for which the entire origin should be treated as a site
diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc
index 3d43ebc..3101bc1 100644
--- a/content/browser/child_process_security_policy_unittest.cc
+++ b/content/browser/child_process_security_policy_unittest.cc
@@ -7,8 +7,6 @@
 
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/test/bind_test_util.h"
 #include "base/test/mock_log.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/site_instance_impl.h"
@@ -61,9 +59,7 @@
 
 class ChildProcessSecurityPolicyTest : public testing::Test {
  public:
-  ChildProcessSecurityPolicyTest()
-      : thread_bundle_(TestBrowserThreadBundle::REAL_IO_THREAD),
-        old_browser_client_(nullptr) {}
+  ChildProcessSecurityPolicyTest() : old_browser_client_(nullptr) {}
 
   void SetUp() override {
     old_browser_client_ = SetBrowserClientForTesting(&test_browser_client_);
@@ -997,85 +993,6 @@
   EXPECT_FALSE(p->HasWebUIBindings(kRendererID));
 }
 
-TEST_F(ChildProcessSecurityPolicyTest, RemoveRace_CanAccessDataForOrigin) {
-  ChildProcessSecurityPolicyImpl* p =
-      ChildProcessSecurityPolicyImpl::GetInstance();
-
-  GURL url("file:///etc/passwd");
-
-  p->Add(kRendererID);
-
-  base::WaitableEvent ready_for_remove_event;
-  base::WaitableEvent remove_called_event;
-  base::WaitableEvent pending_remove_complete_event;
-
-  bool io_before_remove = false;
-  bool io_while_remove_pending = false;
-  bool io_after_remove_complete = false;
-  bool ui_before_remove = false;
-  bool ui_while_remove_pending = false;
-  bool ui_after_remove_complete = false;
-
-  // Post a task that will run on the IO thread before the task that
-  // Remove() will post to the IO thread.
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO}, base::BindLambdaForTesting([&]() {
-        // Capture state on the IO thread before Remove() is called.
-        io_before_remove = p->CanAccessDataForOrigin(kRendererID, url);
-
-        // Tell the UI thread we are ready for Remove() to be called.
-        ready_for_remove_event.Signal();
-
-        // Wait for Remove() to be called on the UI thread.
-        remove_called_event.Wait();
-
-        // Capture state after Remove() is called, but before its task on
-        // the IO thread runs.
-        io_while_remove_pending = p->CanAccessDataForOrigin(kRendererID, url);
-      }));
-
-  ready_for_remove_event.Wait();
-
-  ui_before_remove = p->CanAccessDataForOrigin(kRendererID, url);
-
-  p->Remove(kRendererID);
-
-  // Post a task to run after the task Remove() posted on the IO thread.
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO}, base::BindLambdaForTesting([&]() {
-        io_after_remove_complete = p->CanAccessDataForOrigin(kRendererID, url);
-
-        // Tell the UI thread that the task from Remove() has completed on the
-        // IO thread.
-        pending_remove_complete_event.Signal();
-      }));
-
-  // Capture state after Remove() has been called, but before its IO thread
-  // task has run. We know the IO thread task hasn't run yet because the
-  // task we posted before the Remove() call is waiting for us to signal
-  // |remove_called_event|.
-  ui_while_remove_pending = p->CanAccessDataForOrigin(kRendererID, url);
-
-  // Unblock the IO thread so the pending remove events can run.
-  remove_called_event.Signal();
-
-  pending_remove_complete_event.Wait();
-
-  ui_after_remove_complete = p->CanAccessDataForOrigin(kRendererID, url);
-
-  // Verify expected states at various parts of the removal.
-  // Note: IO thread is expected to keep pre-Remove() permissions until its
-  // remove task runs on the IO thread. The UI thread is expected to have no
-  // permissions after Remove() returns.
-  EXPECT_TRUE(io_before_remove);
-  EXPECT_TRUE(io_while_remove_pending);
-  EXPECT_FALSE(io_after_remove_complete);
-
-  EXPECT_TRUE(ui_before_remove);
-  EXPECT_FALSE(ui_while_remove_pending);
-  EXPECT_FALSE(ui_after_remove_complete);
-}
-
 // Test the granting of origin permissions, and their interactions with
 // granting scheme permissions.
 TEST_F(ChildProcessSecurityPolicyTest, OriginGranting) {
diff --git a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
index ebf479c..c701b61 100644
--- a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/services/leveldb/public/cpp/util.h"
-#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/dom_storage/session_storage_database.h"
 #include "content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h"
 #include "content/browser/dom_storage/test/fake_leveldb_service.h"
@@ -63,13 +62,9 @@
     features_.InitAndEnableFeature(blink::features::kOnionSoupDOMStorage);
     mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
         &SessionStorageContextMojoTest::OnBadMessage, base::Unretained(this)));
-
-    ChildProcessSecurityPolicyImpl::GetInstance()->Add(kTestProcessId);
   }
 
   void TearDown() override {
-    ChildProcessSecurityPolicyImpl::GetInstance()->Remove(kTestProcessId);
-
     mojo::core::SetDefaultProcessErrorCallback(
         mojo::core::ProcessErrorCallback());
   }
diff --git a/content/browser/dom_storage/test/mojo_test_with_file_service.h b/content/browser/dom_storage/test/mojo_test_with_file_service.h
index 8ae2bbb..77d6eae 100644
--- a/content/browser/dom_storage/test/mojo_test_with_file_service.h
+++ b/content/browser/dom_storage/test/mojo_test_with_file_service.h
@@ -10,7 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "base/test/scoped_task_environment.h"
 #include "services/file/file_service.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -34,10 +34,10 @@
     return test_connector_factory_.GetDefaultConnector();
   }
 
-  void RunUntilIdle() { thread_bundle_.RunUntilIdle(); }
+  void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
 
  private:
-  TestBrowserThreadBundle thread_bundle_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   service_manager::TestConnectorFactory test_connector_factory_;
   file::FileService file_service_;
   base::ScopedTempDir temp_path_;
diff --git a/content/browser/fileapi/browser_file_system_helper_unittest.cc b/content/browser/fileapi/browser_file_system_helper_unittest.cc
index 67e528b5..1b0cff4 100644
--- a/content/browser/fileapi/browser_file_system_helper_unittest.cc
+++ b/content/browser/fileapi/browser_file_system_helper_unittest.cc
@@ -13,7 +13,6 @@
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
 #include "content/public/common/drop_data.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/filename_util.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "storage/browser/fileapi/file_system_options.h"
@@ -34,7 +33,6 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  TestBrowserThreadBundle thread_bundle;
   ChildProcessSecurityPolicyImpl* p =
       ChildProcessSecurityPolicyImpl::GetInstance();
   p->Add(kRendererID);
@@ -138,7 +136,6 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  TestBrowserThreadBundle thread_bundle;
   ChildProcessSecurityPolicyImpl* p =
       ChildProcessSecurityPolicyImpl::GetInstance();
   p->Add(kRendererID);
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 424158e..2a983133 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -57,7 +57,6 @@
 #include "content/browser/frame_host/debug_urls.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
-#include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigator.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"  // Temporary
@@ -478,7 +477,6 @@
       in_navigate_to_pending_entry_(false),
       pending_reload_(ReloadType::NONE),
       get_timestamp_callback_(base::Bind(&base::Time::Now)),
-      screenshot_manager_(new NavigationEntryScreenshotManager(this)),
       last_committed_reload_type_(ReloadType::NONE) {
   DCHECK(browser_context_);
 }
@@ -740,18 +738,6 @@
   return GetCurrentEntryIndex() + offset;
 }
 
-void NavigationControllerImpl::TakeScreenshot() {
-  screenshot_manager_->TakeScreenshot();
-}
-
-void NavigationControllerImpl::SetScreenshotManager(
-    std::unique_ptr<NavigationEntryScreenshotManager> manager) {
-  if (manager.get())
-    screenshot_manager_ = std::move(manager);
-  else
-    screenshot_manager_.reset(new NavigationEntryScreenshotManager(this));
-}
-
 bool NavigationControllerImpl::CanGoBack() const {
   return CanGoToOffset(-1);
 }
@@ -2186,10 +2172,6 @@
       std::move(request), ReloadType::NONE, RestoreType::NONE);
 }
 
-void NavigationControllerImpl::ClearAllScreenshots() {
-  screenshot_manager_->ClearAllScreenshots();
-}
-
 void NavigationControllerImpl::SetSessionStorageNamespace(
     const std::string& partition_id,
     SessionStorageNamespace* session_storage_namespace) {
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index e7e2d32..0023690 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -30,7 +30,6 @@
 enum class WasActivatedOption;
 class FrameTreeNode;
 class RenderFrameHostImpl;
-class NavigationEntryScreenshotManager;
 class SiteInstance;
 struct LoadCommittedDetails;
 
@@ -119,8 +118,6 @@
       const std::string& extra_headers,
       scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory);
 
-  void ClearAllScreenshots() override;
-
   // Whether this is the initial navigation in an unmodified new tab.  In this
   // case, we know there is no content displayed in the page.
   bool IsUnmodifiedBlankTab() const;
@@ -224,14 +221,6 @@
   void SetGetTimestampCallbackForTest(
       const base::Callback<base::Time()>& get_timestamp_callback);
 
-  // Takes a screenshot of the page at the current state.
-  void TakeScreenshot();
-
-  // Sets the screenshot manager for this NavigationControllerImpl. Setting a
-  // NULL manager recreates the default screenshot manager and uses that.
-  void SetScreenshotManager(
-      std::unique_ptr<NavigationEntryScreenshotManager> manager);
-
   // Discards only the pending entry. |was_failure| should be set if the pending
   // entry is being discarded because it failed to load.
   void DiscardPendingEntry(bool was_failure);
@@ -252,8 +241,6 @@
  private:
   friend class RestoreHelper;
 
-  FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest,
-                           PurgeScreenshot);
   FRIEND_TEST_ALL_PREFIXES(TimeSmoother, Basic);
   FRIEND_TEST_ALL_PREFIXES(TimeSmoother, SingleDuplicate);
   FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ManyDuplicates);
@@ -539,8 +526,6 @@
   // the wrong order in the history view.
   TimeSmoother time_smoother_;
 
-  std::unique_ptr<NavigationEntryScreenshotManager> screenshot_manager_;
-
   // Used for tracking consecutive reload requests.  If the last user-initiated
   // navigation (either browser-initiated or renderer-initiated with a user
   // gesture) was a reload, these hold the ReloadType and timestamp.  Otherwise
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 2c11419..e22d7d50 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -26,7 +26,6 @@
 #include "content/browser/browser_url_handler_impl.h"
 #include "content/browser/frame_host/frame_navigation_entry.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
-#include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/navigator.h"
@@ -83,50 +82,6 @@
                 a_bitmap.computeByteSize()) == 0;
 }
 
-class MockScreenshotManager : public content::NavigationEntryScreenshotManager {
- public:
-  explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
-      : content::NavigationEntryScreenshotManager(owner),
-        encoding_screenshot_in_progress_(false) {
-  }
-
-  ~MockScreenshotManager() override {}
-
-  void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
-    SkBitmap bitmap;
-    bitmap.allocPixels(SkImageInfo::Make(
-        1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
-    bitmap.eraseARGB(0, 0, 0, 0);
-    encoding_screenshot_in_progress_ = true;
-    OnScreenshotTaken(entry->GetUniqueID(), bitmap);
-    WaitUntilScreenshotIsReady();
-  }
-
-  int GetScreenshotCount() {
-    return content::NavigationEntryScreenshotManager::GetScreenshotCount();
-  }
-
-  void WaitUntilScreenshotIsReady() {
-    if (!encoding_screenshot_in_progress_)
-      return;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-  }
-
- private:
-  void OnScreenshotSet(content::NavigationEntryImpl* entry) override {
-    encoding_screenshot_in_progress_ = false;
-    NavigationEntryScreenshotManager::OnScreenshotSet(entry);
-    if (message_loop_runner_.get())
-      message_loop_runner_->Quit();
-  }
-
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  bool encoding_screenshot_in_progress_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
-};
-
 int64_t GenerateSequenceNumber() {
   // Based on how Blink generates sequence numbers.
   static int64_t next_number = base::Time::Now().ToDoubleT() * 1000000;
@@ -4747,93 +4702,6 @@
   EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image));
 }
 
-// The test crashes on android: http://crbug.com/170449
-#if defined(OS_ANDROID)
-#define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
-#else
-#define MAYBE_PurgeScreenshot PurgeScreenshot
-#endif
-// Tests that screenshot are purged correctly.
-TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  NavigationEntryImpl* entry;
-
-  // Navigate enough times to make sure that some screenshots are purged.
-  for (int i = 0; i < 12; ++i) {
-    const GURL url(base::StringPrintf("http://foo%d/", i));
-    NavigateAndCommit(url);
-    EXPECT_EQ(i, controller.GetCurrentEntryIndex());
-  }
-
-  MockScreenshotManager* screenshot_manager =
-      new MockScreenshotManager(&controller);
-  controller.SetScreenshotManager(base::WrapUnique(screenshot_manager));
-  for (int i = 0; i < controller.GetEntryCount(); ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    screenshot_manager->TakeScreenshotFor(entry);
-    EXPECT_TRUE(entry->screenshot().get());
-  }
-
-  NavigateAndCommit(GURL("https://foo/"));
-  EXPECT_EQ(13, controller.GetEntryCount());
-  entry = controller.GetEntryAtIndex(11);
-  screenshot_manager->TakeScreenshotFor(entry);
-
-  for (int i = 0; i < 2; ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not purged";
-  }
-
-  for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
-  }
-
-  // Navigate to index 5 and then try to assign screenshot to all entries.
-  controller.GoToIndex(5);
-  contents()->CommitPendingNavigation();
-  EXPECT_EQ(5, controller.GetCurrentEntryIndex());
-  for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    screenshot_manager->TakeScreenshotFor(entry);
-  }
-
-  for (int i = 10; i <= 12; ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not purged";
-    screenshot_manager->TakeScreenshotFor(entry);
-  }
-
-  // Navigate to index 7 and assign screenshot to all entries.
-  controller.GoToIndex(7);
-  contents()->CommitPendingNavigation();
-  EXPECT_EQ(7, controller.GetCurrentEntryIndex());
-  for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    screenshot_manager->TakeScreenshotFor(entry);
-  }
-
-  for (int i = 0; i < 2; ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not purged";
-  }
-
-  // Clear all screenshots.
-  EXPECT_EQ(13, controller.GetEntryCount());
-  EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
-  controller.ClearAllScreenshots();
-  EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
-  for (int i = 0; i < controller.GetEntryCount(); ++i) {
-    entry = controller.GetEntryAtIndex(i);
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not cleared";
-  }
-}
-
 TEST_F(NavigationControllerTest, PushStateUpdatesTitleAndFavicon) {
   // Navigate.
   NavigationSimulator::NavigateAndCommitFromDocument(GURL("http://foo"),
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index 6a8cdf37..f65390e 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -15,7 +15,6 @@
 #include "base/files/file_path.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -664,7 +663,6 @@
   copy->timestamp_ = timestamp_;
   copy->http_status_code_ = http_status_code_;
   // ResetForCommit: post_data_
-  copy->screenshot_ = screenshot_;
   copy->extra_headers_ = extra_headers_;
   copy->base_url_for_data_url_ = base_url_for_data_url_;
 #if defined(OS_ANDROID)
@@ -925,13 +923,6 @@
   }
 }
 
-void NavigationEntryImpl::SetScreenshotPNGData(
-    scoped_refptr<base::RefCountedBytes> png_data) {
-  screenshot_ = png_data;
-  if (screenshot_.get())
-    UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_->size());
-}
-
 GURL NavigationEntryImpl::GetHistoryURLForDataURL() const {
   return GetBaseURLForDataURL().is_empty() ? GURL() : GetVirtualURL();
 }
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
index 61af0b2..89d2fb5 100644
--- a/content/browser/frame_host/navigation_entry_impl.h
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -370,11 +370,6 @@
     should_replace_entry_ = should_replace_entry;
   }
 
-  void SetScreenshotPNGData(scoped_refptr<base::RefCountedBytes> png_data);
-  const scoped_refptr<base::RefCountedBytes> screenshot() const {
-    return screenshot_;
-  }
-
   // Whether this (pending) navigation should clear the session history. Resets
   // to false after commit.
   bool should_clear_history_list() const {
@@ -463,15 +458,6 @@
   // compiler provided copy constructor.  Cleared in |ResetForCommit|.
   scoped_refptr<network::ResourceRequestBody> post_data_;
 
-  // This is also a transient member (i.e. is not persisted with session
-  // restore). The screenshot of a page is taken when navigating away from the
-  // page. This screenshot is displayed during an overscroll-navigation
-  // gesture. |screenshot_| will be NULL when the screenshot is not available
-  // (e.g. after a session restore, or if taking the screenshot of a page
-  // failed). The UI is responsible for dealing with missing screenshots
-  // appropriately (e.g. display a placeholder image instead).
-  scoped_refptr<base::RefCountedBytes> screenshot_;
-
   // This member is not persisted with session restore.
   std::string extra_headers_;
 
diff --git a/content/browser/frame_host/navigation_entry_screenshot_manager.cc b/content/browser/frame_host/navigation_entry_screenshot_manager.cc
deleted file mode 100644
index 5930c7d..0000000
--- a/content/browser/frame_host/navigation_entry_screenshot_manager.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
-
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/task/post_task.h"
-#include "content/browser/frame_host/navigation_controller_impl.h"
-#include "content/browser/frame_host/navigation_entry_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/public/browser/overscroll_configuration.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/common/content_switches.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/effects/SkLumaColorFilter.h"
-#include "ui/gfx/codec/png_codec.h"
-
-namespace {
-
-// Minimum delay between taking screenshots.
-const int kMinScreenshotIntervalMS = 1000;
-
-}
-
-namespace content {
-
-// Encodes the A8 SkBitmap to grayscale PNG in a worker thread.
-class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
- public:
-  ScreenshotData() {
-  }
-
-  void EncodeScreenshot(const SkBitmap& bitmap, base::OnceClosure callback) {
-    base::PostTaskWithTraitsAndReply(
-        FROM_HERE, {base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-        base::BindOnce(&ScreenshotData::EncodeOnWorker, this, bitmap),
-        std::move(callback));
-  }
-
-  scoped_refptr<base::RefCountedBytes> data() const { return data_; }
-
- private:
-  friend class base::RefCountedThreadSafe<ScreenshotData>;
-  virtual ~ScreenshotData() {
-  }
-
-  void EncodeOnWorker(const SkBitmap& bitmap) {
-    // Convert |bitmap| to alpha-only |grayscale_bitmap|.
-    SkBitmap grayscale_bitmap;
-    if (grayscale_bitmap.tryAllocPixels(
-            SkImageInfo::MakeA8(bitmap.width(), bitmap.height()))) {
-      SkCanvas canvas(grayscale_bitmap);
-#if defined(MEMORY_SANITIZER)
-      // This is needed because Skia will operate over uninitialized memory
-      // outside the visible region (with non-visible effects).
-      canvas.clear(SK_ColorBLACK);
-#endif
-      SkPaint paint;
-      paint.setColorFilter(SkLumaColorFilter::Make());
-      canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
-      canvas.flush();
-    }
-    if (!grayscale_bitmap.readyToDraw())
-      return;
-
-    // Encode the A8 bitmap to grayscale PNG treating alpha as color intensity.
-    std::vector<unsigned char> data;
-    if (gfx::PNGCodec::EncodeA8SkBitmap(grayscale_bitmap, &data))
-      data_ = base::RefCountedBytes::TakeVector(&data);
-  }
-
-  scoped_refptr<base::RefCountedBytes> data_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreenshotData);
-};
-
-NavigationEntryScreenshotManager::NavigationEntryScreenshotManager(
-    NavigationControllerImpl* owner)
-    : owner_(owner),
-      min_screenshot_interval_ms_(kMinScreenshotIntervalMS),
-      screenshot_factory_(this) {
-
-}
-
-NavigationEntryScreenshotManager::~NavigationEntryScreenshotManager() {
-}
-
-void NavigationEntryScreenshotManager::TakeScreenshot() {
-  if (OverscrollConfig::GetHistoryNavigationMode() !=
-      OverscrollConfig::HistoryNavigationMode::kParallaxUi) {
-    return;
-  }
-
-  NavigationEntryImpl* entry = owner_->GetLastCommittedEntry();
-  if (!entry)
-    return;
-
-  if (!owner_->delegate()->CanOverscrollContent())
-    return;
-
-  RenderViewHost* render_view_host = owner_->delegate()->GetRenderViewHost();
-  DCHECK(render_view_host && render_view_host->GetWidget());
-  content::RenderWidgetHostView* view =
-      render_view_host->GetWidget()->GetView();
-  if (!view)
-    return;
-
-  // Make sure screenshots aren't taken too frequently.
-  base::Time now = base::Time::Now();
-  if (now - last_screenshot_time_ <
-          base::TimeDelta::FromMilliseconds(min_screenshot_interval_ms_)) {
-    return;
-  }
-
-  WillTakeScreenshot(render_view_host);
-
-  last_screenshot_time_ = now;
-
-  // This screenshot is destined for the UI, so size the result to the actual
-  // on-screen size of the view (and not its device-rendering size).
-  const gfx::Size view_size_on_screen = view->GetViewBounds().size();
-  view->CopyFromSurface(
-      gfx::Rect(), view_size_on_screen,
-      base::BindOnce(&NavigationEntryScreenshotManager::OnScreenshotTaken,
-                     screenshot_factory_.GetWeakPtr(), entry->GetUniqueID()));
-}
-
-// Implemented here and not in NavigationEntry because this manager keeps track
-// of the total number of screen shots across all entries.
-void NavigationEntryScreenshotManager::ClearAllScreenshots() {
-  int count = owner_->GetEntryCount();
-  for (int i = 0; i < count; ++i) {
-    ClearScreenshot(owner_->GetEntryAtIndex(i));
-  }
-  DCHECK_EQ(GetScreenshotCount(), 0);
-}
-
-void NavigationEntryScreenshotManager::SetMinScreenshotIntervalMS(
-    int interval_ms) {
-  DCHECK_GE(interval_ms, 0);
-  min_screenshot_interval_ms_ = interval_ms;
-}
-
-void NavigationEntryScreenshotManager::OnScreenshotTaken(
-    int unique_id,
-    const SkBitmap& bitmap) {
-  NavigationEntryImpl* entry = owner_->GetEntryWithUniqueID(unique_id);
-  if (!entry) {
-    LOG(ERROR) << "Invalid entry with unique id: " << unique_id;
-    return;
-  }
-
-  if (bitmap.drawsNothing()) {
-    if (!ClearScreenshot(entry))
-      OnScreenshotSet(entry);
-    return;
-  }
-
-  scoped_refptr<ScreenshotData> screenshot = new ScreenshotData();
-  screenshot->EncodeScreenshot(
-      bitmap, base::BindOnce(
-                  &NavigationEntryScreenshotManager::OnScreenshotEncodeComplete,
-                  screenshot_factory_.GetWeakPtr(), unique_id, screenshot));
-}
-
-int NavigationEntryScreenshotManager::GetScreenshotCount() const {
-  int screenshot_count = 0;
-  int entry_count = owner_->GetEntryCount();
-  for (int i = 0; i < entry_count; ++i) {
-    NavigationEntryImpl* entry = owner_->GetEntryAtIndex(i);
-    if (entry->screenshot().get())
-      screenshot_count++;
-  }
-  return screenshot_count;
-}
-
-void NavigationEntryScreenshotManager::OnScreenshotEncodeComplete(
-    int unique_id,
-    scoped_refptr<ScreenshotData> screenshot) {
-  NavigationEntryImpl* entry = owner_->GetEntryWithUniqueID(unique_id);
-  if (!entry)
-    return;
-  scoped_refptr<base::RefCountedBytes> data = screenshot->data();
-  if (!data)
-    return;
-  entry->SetScreenshotPNGData(std::move(data));
-  OnScreenshotSet(entry);
-}
-
-void NavigationEntryScreenshotManager::OnScreenshotSet(
-    NavigationEntryImpl* entry) {
-  if (entry->screenshot().get())
-    PurgeScreenshotsIfNecessary();
-}
-
-bool NavigationEntryScreenshotManager::ClearScreenshot(
-    NavigationEntryImpl* entry) {
-  if (!entry->screenshot().get())
-    return false;
-
-  entry->SetScreenshotPNGData(nullptr);
-  return true;
-}
-
-void NavigationEntryScreenshotManager::PurgeScreenshotsIfNecessary() {
-  // Allow only a certain number of entries to keep screenshots.
-  const int kMaxScreenshots = 10;
-  int screenshot_count = GetScreenshotCount();
-  if (screenshot_count < kMaxScreenshots)
-    return;
-
-  const int current = owner_->GetCurrentEntryIndex();
-  const int num_entries = owner_->GetEntryCount();
-  int available_slots = kMaxScreenshots;
-  if (owner_->GetEntryAtIndex(current)->screenshot().get()) {
-    --available_slots;
-  }
-
-  // Keep screenshots closer to the current navigation entry, and purge the ones
-  // that are farther away from it. So in each step, look at the entries at
-  // each offset on both the back and forward history, and start counting them
-  // to make sure that the correct number of screenshots are kept in memory.
-  // Note that it is possible for some entries to be missing screenshots (e.g.
-  // when taking the screenshot failed for some reason). So there may be a state
-  // where there are a lot of entries in the back history, but none of them has
-  // any screenshot. In such cases, keep the screenshots for |kMaxScreenshots|
-  // entries in the forward history list.
-  int back = current - 1;
-  int forward = current + 1;
-  while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
-    if (back >= 0) {
-      NavigationEntryImpl* entry = owner_->GetEntryAtIndex(back);
-      if (entry->screenshot().get())
-        --available_slots;
-      --back;
-    }
-
-    if (available_slots > 0 && forward < num_entries) {
-      NavigationEntryImpl* entry = owner_->GetEntryAtIndex(forward);
-      if (entry->screenshot().get())
-        --available_slots;
-      ++forward;
-    }
-  }
-
-  // Purge any screenshot at |back| or lower indices, and |forward| or higher
-  // indices.
-  while (screenshot_count > kMaxScreenshots && back >= 0) {
-    NavigationEntryImpl* entry = owner_->GetEntryAtIndex(back);
-    if (ClearScreenshot(entry))
-      --screenshot_count;
-    --back;
-  }
-
-  while (screenshot_count > kMaxScreenshots && forward < num_entries) {
-    NavigationEntryImpl* entry = owner_->GetEntryAtIndex(forward);
-    if (ClearScreenshot(entry))
-      --screenshot_count;
-    ++forward;
-  }
-  CHECK_GE(screenshot_count, 0);
-  CHECK_LE(screenshot_count, kMaxScreenshots);
-}
-
-}  // namespace content
diff --git a/content/browser/frame_host/navigation_entry_screenshot_manager.h b/content/browser/frame_host/navigation_entry_screenshot_manager.h
deleted file mode 100644
index dab9e99..0000000
--- a/content/browser/frame_host/navigation_entry_screenshot_manager.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_FRAME_HOST_NAVIGATION_ENTRY_SCREENSHOT_MANAGER_H_
-#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_ENTRY_SCREENSHOT_MANAGER_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "content/common/content_export.h"
-
-class SkBitmap;
-
-namespace content {
-
-class NavigationControllerImpl;
-class NavigationEntryImpl;
-class RenderViewHost;
-class ScreenshotData;
-
-// NavigationEntryScreenshotManager takes care of taking image-captures for the
-// current navigation entry of a NavigationControllerImpl, and managing these
-// captured images. These image-captures are used for history navigation using
-// overscroll gestures.
-class CONTENT_EXPORT NavigationEntryScreenshotManager {
- public:
-  explicit NavigationEntryScreenshotManager(
-      NavigationControllerImpl* controller);
-  virtual ~NavigationEntryScreenshotManager();
-
-  // Takes a screenshot of the last-committed entry of the controller.
-  void TakeScreenshot();
-
-  // Clears screenshots of all navigation entries.
-  void ClearAllScreenshots();
-
- protected:
-  // Overridden by tests to be notified when a screenshot will be taken. Tests
-  // can override OnScreenshotSet() to be notified after the screenshot is
-  // taken.
-  virtual void WillTakeScreenshot(RenderViewHost* host) {}
-
-  // Called after a screenshot has been set on an NavigationEntryImpl.
-  // Overridden in tests to get notified of when a screenshot is set.
-  virtual void OnScreenshotSet(NavigationEntryImpl* entry);
-
-  NavigationControllerImpl* owner() { return owner_; }
-
-  void SetMinScreenshotIntervalMS(int interval_ms);
-
-  // The callback invoked when taking the screenshot of the page is complete.
-  // This sets the screenshot on the navigation entry.
-  void OnScreenshotTaken(int unique_id, const SkBitmap& bitmap);
-
-  // Returns the number of entries with screenshots.
-  int GetScreenshotCount() const;
-
- private:
-  // This is called when the screenshot data has beene encoded to PNG in a
-  // worker thread.
-  void OnScreenshotEncodeComplete(int unique_id,
-                                  scoped_refptr<ScreenshotData> data);
-
-  // Removes the screenshot for the entry, returning true if the entry had a
-  // screenshot.
-  bool ClearScreenshot(NavigationEntryImpl* entry);
-
-  // The screenshots in the NavigationEntryImpls can accumulate and consume a
-  // large amount of memory. This function makes sure that the memory
-  // consumption is within a certain limit.
-  void PurgeScreenshotsIfNecessary();
-
-  // The navigation controller that owns this screenshot-manager.
-  NavigationControllerImpl* owner_;
-
-  base::Time last_screenshot_time_;
-  int min_screenshot_interval_ms_;
-
-  // Taking a screenshot and encoding them can be async. So use a weakptr for
-  // the callback to make sure that the screenshot/encoding completion callback
-  // does not trigger on a destroyed NavigationEntryScreenshotManager.
-  base::WeakPtrFactory<NavigationEntryScreenshotManager> screenshot_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(NavigationEntryScreenshotManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_ENTRY_SCREENSHOT_MANAGER_H_
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 69dacd0f..f4c38a2 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -197,21 +197,6 @@
 
   if (ui::PageTransitionIsMainFrame(params.transition)) {
     if (delegate_) {
-      // When overscroll navigation gesture is enabled, a screenshot of the page
-      // in its current state is taken so that it can be used during the
-      // nav-gesture. It is necessary to take the screenshot here, before
-      // calling RenderFrameHostManager::DidNavigateMainFrame, because that can
-      // change WebContents::GetRenderViewHost to return the new host, instead
-      // of the one that may have just been swapped out.
-      if (delegate_->CanOverscrollContent()) {
-        // Don't take screenshots if we are staying on the same document. We
-        // want same-document navigations to be super fast, and taking a
-        // screenshot currently blocks GPU for a longer time than we are willing
-        // to tolerate in this use case.
-        if (!was_within_same_document)
-          controller_->TakeScreenshot();
-      }
-
       // Run tasks that must execute just before the commit.
       delegate_->DidNavigateMainFramePreCommit(is_same_document_navigation);
     }
diff --git a/content/browser/network_service_client_unittest.cc b/content/browser/network_service_client_unittest.cc
index de2c0047..5d6e02160 100644
--- a/content/browser/network_service_client_unittest.cc
+++ b/content/browser/network_service_client_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/test/test_file_util.h"
 #include "build/build_config.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -77,7 +76,7 @@
   }
 
  protected:
-  TestBrowserThreadBundle scoped_task_environment_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   network::mojom::NetworkServiceClientPtr client_ptr_;
   NetworkServiceClient client_;
   base::ScopedTempDir temp_dir_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 1499d28..cca56202 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3083,7 +3083,6 @@
     switches::kVModule,
     // Please keep these in alphabetical order. Compositor switches here should
     // also be added to chrome/browser/chromeos/login/chrome_restart_request.cc.
-    cc::switches::kAlwaysRequestPresentationTime,
     cc::switches::kCheckDamageEarly,
     cc::switches::kDisableCheckerImaging,
     cc::switches::kDisableCompositedAntialiasing,
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 7a77e94..6ebfa9c 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -2076,7 +2076,6 @@
 // Check that if messages of a frame arrive earlier than the frame itself, we
 // queue the messages until the frame arrives and then process them.
 TEST_F(RenderWidgetHostTest, FrameToken_MessageThenFrame) {
-  const uint32_t frame_token = 99;
   const viz::LocalSurfaceId local_surface_id(1,
                                              base::UnguessableToken::Create());
   std::vector<IPC::Message> messages;
@@ -2085,16 +2084,17 @@
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
+  auto frame = viz::CompositorFrameBuilder()
+                   .AddDefaultRenderPass()
+                   .SetSendFrameTokenToEmbedder(true)
+                   .Build();
+  const uint32_t frame_token = frame.metadata.frame_token;
+
   host_->OnMessageReceived(
       WidgetHostMsg_FrameSwapMessages(0, frame_token, messages));
   EXPECT_EQ(1u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
-  auto frame = viz::CompositorFrameBuilder()
-                   .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token)
-                   .SetSendFrameTokenToEmbedder(true)
-                   .Build();
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
@@ -2104,7 +2104,6 @@
 // Check that if a frame arrives earlier than its messages, we process the
 // messages immedtiately.
 TEST_F(RenderWidgetHostTest, FrameToken_FrameThenMessage) {
-  const uint32_t frame_token = 99;
   const viz::LocalSurfaceId local_surface_id(1,
                                              base::UnguessableToken::Create());
   std::vector<IPC::Message> messages;
@@ -2115,9 +2114,9 @@
 
   auto frame = viz::CompositorFrameBuilder()
                    .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token)
                    .SetSendFrameTokenToEmbedder(true)
                    .Build();
+  const uint32_t frame_token = frame.metadata.frame_token;
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
@@ -2132,8 +2131,6 @@
 // Check that if messages of multiple frames arrive before the frames, we
 // process each message once it frame arrives.
 TEST_F(RenderWidgetHostTest, FrameToken_MultipleMessagesThenTokens) {
-  const uint32_t frame_token1 = 99;
-  const uint32_t frame_token2 = 100;
   const viz::LocalSurfaceId local_surface_id(1,
                                              base::UnguessableToken::Create());
   std::vector<IPC::Message> messages1;
@@ -2144,6 +2141,17 @@
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
+  auto frame1 = viz::CompositorFrameBuilder()
+                    .AddDefaultRenderPass()
+                    .SetSendFrameTokenToEmbedder(true)
+                    .Build();
+  const uint32_t frame_token1 = frame1.metadata.frame_token;
+  auto frame2 = viz::CompositorFrameBuilder()
+                    .AddDefaultRenderPass()
+                    .SetSendFrameTokenToEmbedder(true)
+                    .Build();
+  const uint32_t frame_token2 = frame2.metadata.frame_token;
+
   host_->OnMessageReceived(
       WidgetHostMsg_FrameSwapMessages(0, frame_token1, messages1));
   EXPECT_EQ(1u, host_->frame_token_message_queue_->size());
@@ -2154,22 +2162,11 @@
   EXPECT_EQ(2u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
-  auto frame = viz::CompositorFrameBuilder()
-                   .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token1)
-                   .SetSendFrameTokenToEmbedder(true)
-                   .Build();
-  host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
+  host_->SubmitCompositorFrame(local_surface_id, std::move(frame1),
                                base::nullopt, 0);
   EXPECT_EQ(1u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(1u, host_->processed_frame_messages_count());
-
-  frame = viz::CompositorFrameBuilder()
-              .AddDefaultRenderPass()
-              .SetFrameToken(frame_token2)
-              .SetSendFrameTokenToEmbedder(true)
-              .Build();
-  host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
+  host_->SubmitCompositorFrame(local_surface_id, std::move(frame2),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(2u, host_->processed_frame_messages_count());
@@ -2178,8 +2175,6 @@
 // Check that if multiple frames arrive before their messages, each message is
 // processed immediately as soon as it arrives.
 TEST_F(RenderWidgetHostTest, FrameToken_MultipleTokensThenMessages) {
-  const uint32_t frame_token1 = 99;
-  const uint32_t frame_token2 = 100;
   const viz::LocalSurfaceId local_surface_id(1,
                                              base::UnguessableToken::Create());
   std::vector<IPC::Message> messages1;
@@ -2192,9 +2187,9 @@
 
   auto frame = viz::CompositorFrameBuilder()
                    .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token1)
                    .SetSendFrameTokenToEmbedder(true)
                    .Build();
+  const uint32_t frame_token1 = frame.metadata.frame_token;
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
@@ -2202,9 +2197,9 @@
 
   frame = viz::CompositorFrameBuilder()
               .AddDefaultRenderPass()
-              .SetFrameToken(frame_token2)
               .SetSendFrameTokenToEmbedder(true)
               .Build();
+  const uint32_t frame_token2 = frame.metadata.frame_token;
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
@@ -2224,8 +2219,7 @@
 // Check that if one frame is lost but its messages arrive, we process the
 // messages on the arrival of the next frame.
 TEST_F(RenderWidgetHostTest, FrameToken_DroppedFrame) {
-  const uint32_t frame_token1 = 99;
-  const uint32_t frame_token2 = 100;
+  const uint32_t frame_token1 = 1;
   const viz::LocalSurfaceId local_surface_id(1,
                                              base::UnguessableToken::Create());
   std::vector<IPC::Message> messages1;
@@ -2241,16 +2235,16 @@
   EXPECT_EQ(1u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
+  auto frame = viz::CompositorFrameBuilder()
+                   .AddDefaultRenderPass()
+                   .SetSendFrameTokenToEmbedder(true)
+                   .Build();
+  const uint32_t frame_token2 = frame.metadata.frame_token;
   host_->OnMessageReceived(
       WidgetHostMsg_FrameSwapMessages(0, frame_token2, messages2));
   EXPECT_EQ(2u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
-  auto frame = viz::CompositorFrameBuilder()
-                   .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token2)
-                   .SetSendFrameTokenToEmbedder(true)
-                   .Build();
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
@@ -2260,9 +2254,6 @@
 // Check that if the renderer crashes, we drop all queued messages and allow
 // smaller frame tokens to be sent by the renderer.
 TEST_F(RenderWidgetHostTest, FrameToken_RendererCrash) {
-  const uint32_t frame_token1 = 99;
-  const uint32_t frame_token2 = 50;
-  const uint32_t frame_token3 = 30;
   const viz::LocalSurfaceId local_surface_id(1,
                                              base::UnguessableToken::Create());
   std::vector<IPC::Message> messages1;
@@ -2282,6 +2273,11 @@
   // then a crash occurs when we attempt to destroy it again in TearDown().
   host_->SetView(nullptr);
 
+  auto frame = viz::CompositorFrameBuilder()
+                   .AddDefaultRenderPass()
+                   .SetSendFrameTokenToEmbedder(true)
+                   .Build();
+  const uint32_t frame_token1 = frame.metadata.frame_token;
   host_->OnMessageReceived(
       WidgetHostMsg_FrameSwapMessages(0, frame_token1, messages1));
   EXPECT_EQ(1u, host_->frame_token_message_queue_->size());
@@ -2292,11 +2288,11 @@
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
   host_->Init();
 
-  auto frame = viz::CompositorFrameBuilder()
-                   .AddDefaultRenderPass()
-                   .SetFrameToken(frame_token2)
-                   .SetSendFrameTokenToEmbedder(true)
-                   .Build();
+  frame = viz::CompositorFrameBuilder()
+              .AddDefaultRenderPass()
+              .SetSendFrameTokenToEmbedder(true)
+              .Build();
+  const uint32_t frame_token2 = frame.metadata.frame_token;
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
                                base::nullopt, 0);
   EXPECT_EQ(0u, host_->frame_token_message_queue_->size());
@@ -2309,13 +2305,12 @@
   host_->Init();
 
   host_->OnMessageReceived(
-      WidgetHostMsg_FrameSwapMessages(0, frame_token3, messages3));
+      WidgetHostMsg_FrameSwapMessages(0, frame_token2, messages3));
   EXPECT_EQ(1u, host_->frame_token_message_queue_->size());
   EXPECT_EQ(0u, host_->processed_frame_messages_count());
 
   frame = viz::CompositorFrameBuilder()
               .AddDefaultRenderPass()
-              .SetFrameToken(frame_token3)
               .SetSendFrameTokenToEmbedder(true)
               .Build();
   host_->SubmitCompositorFrame(local_surface_id, std::move(frame),
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 0f8d4ba4..5d5630c 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -56,8 +56,6 @@
 #include "mojo/public/cpp/system/invitation.h"
 #include "services/audio/public/mojom/constants.mojom.h"
 #include "services/audio/service_factory.h"
-#include "services/catalog/public/cpp/manifest_parsing_util.h"
-#include "services/catalog/public/mojom/constants.mojom.h"
 #include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "services/device/device_service.h"
 #include "services/device/public/mojom/constants.mojom.h"
@@ -73,7 +71,6 @@
 #include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
 #include "services/resource_coordinator/resource_coordinator_service.h"
 #include "services/service_manager/connect_params.h"
-#include "services/service_manager/embedder/manifest_utils.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/constants.h"
 #include "services/service_manager/public/cpp/manifest.h"
@@ -564,7 +561,6 @@
         {mojom::kPluginServiceName, IDR_MOJO_CONTENT_PLUGIN_MANIFEST},
         {mojom::kRendererServiceName, IDR_MOJO_CONTENT_RENDERER_MANIFEST},
         {mojom::kUtilityServiceName, IDR_MOJO_CONTENT_UTILITY_MANIFEST},
-        {catalog::mojom::kServiceName, IDR_MOJO_CATALOG_MANIFEST},
     };
     std::vector<service_manager::Manifest> manifests;
     for (const auto& manifest_info : kManifestInfo) {
diff --git a/content/content_resources.grd b/content/content_resources.grd
index 6578475..44307b2 100644
--- a/content/content_resources.grd
+++ b/content/content_resources.grd
@@ -26,7 +26,6 @@
       <include name="IDR_INDEXED_DB_INTERNALS_CSS" file="browser/resources/indexed_db/indexeddb_internals.css" flattenhtml="true" compress="gzip" type="BINDATA" />
       <include name="IDR_MEDIA_INTERNALS_HTML" file="browser/resources/media/media_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
       <include name="IDR_MEDIA_INTERNALS_JS" file="browser/resources/media/media_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
-      <include name="IDR_MOJO_CATALOG_MANIFEST" file="../services/catalog/manifest.json" type="BINDATA" />
       <include name="IDR_MOJO_CONTENT_BROWSER_MANIFEST" file="${root_gen_dir}/content/public/app/browser_manifest.json" use_base_dir="false" type="BINDATA" />
       <include name="IDR_MOJO_CONTENT_GPU_MANIFEST" file="${root_gen_dir}/content/public/app/gpu_manifest.json" use_base_dir="false" type="BINDATA" />
       <include name="IDR_MOJO_CONTENT_PACKAGED_SERVICES_MANIFEST" file="${root_gen_dir}/content/public/app/packaged_services_manifest.json" use_base_dir="false" type="BINDATA" />
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index f5bf19a..75bda56 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -480,10 +480,6 @@
   virtual void DeleteNavigationEntries(
       const DeletionPredicate& deletionPredicate) = 0;
 
-  // Clears all screenshots associated with navigation entries in this
-  // controller. Useful to reduce memory consumption in low-memory situations.
-  virtual void ClearAllScreenshots() = 0;
-
  private:
   // This interface should only be implemented inside content.
   friend class NavigationControllerImpl;
diff --git a/content/renderer/compositor/layer_tree_view.cc b/content/renderer/compositor/layer_tree_view.cc
index e2364d4..263bd26 100644
--- a/content/renderer/compositor/layer_tree_view.cc
+++ b/content/renderer/compositor/layer_tree_view.cc
@@ -110,10 +110,8 @@
 
 void ReportTimeSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) {
   DCHECK_GT(metadata->frame_token, 0u);
-  // Request a presentation timestamp for this frame. The interval between the
-  // current swap and its presentation time is reported in UMA (see
-  // corresponding code in DidSwap() below).
-  metadata->request_presentation_feedback = true;
+  // The interval between the current swap and its presentation time is reported
+  // in UMA (see corresponding code in DidSwap() below).
   frame_token_ = metadata->frame_token;
 }
 
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
index ba4ac31..15514e08 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
@@ -138,6 +138,7 @@
 void GpuVideoAcceleratorFactoriesImpl::OnSupportedDecoderConfigs(
     std::vector<media::mojom::SupportedVideoDecoderConfigPtr>
         supported_configs) {
+  base::AutoLock lock(supported_decoder_configs_lock_);
   supported_decoder_configs_ = std::move(supported_configs);
   video_decoder_.reset();
 }
@@ -191,6 +192,8 @@
 
 bool GpuVideoAcceleratorFactoriesImpl::IsDecoderConfigSupported(
     const media::VideoDecoderConfig& config) {
+  base::AutoLock lock(supported_decoder_configs_lock_);
+
   // If GetSupportedConfigs() has not completed (or was never started), report
   // that all configs are supported. Clients will find out that configs are not
   // supported when VideoDecoder::Initialize() fails.
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
index 7190217..4239d7f 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
@@ -16,6 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/unguessable_token.h"
 #include "content/child/thread_safe_sender.h"
@@ -191,8 +192,9 @@
 
   // SupportedDecoderConfigs state.
   mojo::InterfacePtr<media::mojom::VideoDecoder> video_decoder_;
+  base::Lock supported_decoder_configs_lock_;
   base::Optional<std::vector<media::mojom::SupportedVideoDecoderConfigPtr>>
-      supported_decoder_configs_;
+      supported_decoder_configs_ GUARDED_BY(supported_decoder_configs_lock_);
 
   // For sending requests to allocate shared memory in the Browser process.
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
diff --git a/content/renderer/media/stream/apply_constraints_processor.cc b/content/renderer/media/stream/apply_constraints_processor.cc
index 53694fc9..a69f106 100644
--- a/content/renderer/media/stream/apply_constraints_processor.cc
+++ b/content/renderer/media/stream/apply_constraints_processor.cc
@@ -110,13 +110,8 @@
   const MediaStreamDevice& device_info = video_source_->device();
   if (device_info.type == MEDIA_DEVICE_VIDEO_CAPTURE) {
     ProcessVideoDeviceRequest();
-  } else if (video_source_->GetCurrentFormat()) {
-    // Non-device capture just requires adjusting track settings.
-    FinalizeVideoRequest();
   } else {
-    // It is impossible to enforce minimum constraints for sources that do not
-    // provide the video format, so reject applyConstraints() in this case.
-    CannotApplyConstraints("applyConstraints not supported for this track");
+    FinalizeVideoRequest();
   }
 }
 
@@ -222,9 +217,14 @@
   if (AbortIfVideoRequestStateInvalid())
     return;
 
-  DCHECK(video_source_->GetCurrentFormat());
-  VideoCaptureSettings settings =
-      SelectVideoSettings({*video_source_->GetCurrentFormat()});
+  media::VideoCaptureFormat format;
+  if (video_source_->GetCurrentFormat()) {
+    format = *video_source_->GetCurrentFormat();
+  } else {
+    format = GetCurrentVideoTrack()->GetComputedSourceFormat();
+  }
+  VideoCaptureSettings settings = SelectVideoSettings({format});
+
   if (settings.HasValue()) {
     video_source_->ReconfigureTrack(GetCurrentVideoTrack(),
                                     settings.track_adapter_settings());
@@ -254,7 +254,6 @@
                               : media::MEDIA_VIDEO_FACING_NONE;
   device_capabilities->formats = std::move(formats);
 
-  DCHECK(video_source_->GetCurrentCaptureParams());
   VideoDeviceCaptureCapabilities video_capabilities;
   video_capabilities.noise_reduction_capabilities.push_back(
       GetCurrentVideoTrack()->noise_reduction());
diff --git a/content/renderer/media/stream/media_stream_types.h b/content/renderer/media/stream/media_stream_types.h
index beab906..fd6d60cd 100644
--- a/content/renderer/media/stream/media_stream_types.h
+++ b/content/renderer/media/stream/media_stream_types.h
@@ -5,10 +5,15 @@
 #ifndef CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_TYPES_H_
 #define CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_TYPES_H_
 
+#include "media/capture/video_capture_types.h"
+
 namespace content {
 
 using VideoTrackSettingsCallback =
-    base::RepeatingCallback<void(int width, int height, double frame_rate)>;
+    base::RepeatingCallback<void(gfx::Size frame_size, double frame_rate)>;
+
+using VideoTrackFormatCallback =
+    base::RepeatingCallback<void(const media::VideoCaptureFormat&)>;
 
 }  // namespace content
 
diff --git a/content/renderer/media/stream/media_stream_video_source.cc b/content/renderer/media/stream/media_stream_video_source.cc
index d4e3b1f..a42d09d 100644
--- a/content/renderer/media/stream/media_stream_video_source.cc
+++ b/content/renderer/media/stream/media_stream_video_source.cc
@@ -49,6 +49,7 @@
     const VideoTrackAdapterSettings& track_adapter_settings,
     const VideoCaptureDeliverFrameCB& frame_callback,
     const VideoTrackSettingsCallback& settings_callback,
+    const VideoTrackFormatCallback& format_callback,
     const ConstraintsCallback& callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!base::ContainsValue(tracks_, track));
@@ -56,7 +57,7 @@
   secure_tracker_.Add(track, true);
 
   pending_tracks_.push_back(PendingTrackInfo(
-      track, frame_callback, settings_callback,
+      track, frame_callback, settings_callback, format_callback,
       std::make_unique<VideoTrackAdapterSettings>(track_adapter_settings),
       callback));
 
@@ -368,6 +369,7 @@
     if (result == MEDIA_DEVICE_OK) {
       track_adapter_->AddTrack(track_info.track, track_info.frame_callback,
                                track_info.settings_callback,
+                               track_info.format_callback,
                                *track_info.adapter_settings);
       UpdateTrackSettings(track_info.track, *track_info.adapter_settings);
     }
@@ -434,11 +436,13 @@
     MediaStreamVideoTrack* track,
     const VideoCaptureDeliverFrameCB& frame_callback,
     const VideoTrackSettingsCallback& settings_callback,
+    const VideoTrackFormatCallback& format_callback,
     std::unique_ptr<VideoTrackAdapterSettings> adapter_settings,
     const ConstraintsCallback& callback)
     : track(track),
       frame_callback(frame_callback),
       settings_callback(settings_callback),
+      format_callback(format_callback),
       adapter_settings(std::move(adapter_settings)),
       callback(callback) {}
 
diff --git a/content/renderer/media/stream/media_stream_video_source.h b/content/renderer/media/stream/media_stream_video_source.h
index 2c130f3b..dca07686 100644
--- a/content/renderer/media/stream/media_stream_video_source.h
+++ b/content/renderer/media/stream/media_stream_video_source.h
@@ -70,6 +70,7 @@
                 const VideoTrackAdapterSettings& track_adapter_settings,
                 const VideoCaptureDeliverFrameCB& frame_callback,
                 const VideoTrackSettingsCallback& settings_callback,
+                const VideoTrackFormatCallback& format_callback,
                 const ConstraintsCallback& callback);
   void RemoveTrack(MediaStreamVideoTrack* track, base::OnceClosure callback);
 
@@ -272,6 +273,7 @@
         MediaStreamVideoTrack* track,
         const VideoCaptureDeliverFrameCB& frame_callback,
         const VideoTrackSettingsCallback& settings_callback,
+        const VideoTrackFormatCallback& format_callback,
         std::unique_ptr<VideoTrackAdapterSettings> adapter_settings,
         const ConstraintsCallback& callback);
     PendingTrackInfo(PendingTrackInfo&& other);
@@ -281,6 +283,7 @@
     MediaStreamVideoTrack* track;
     VideoCaptureDeliverFrameCB frame_callback;
     VideoTrackSettingsCallback settings_callback;
+    VideoTrackFormatCallback format_callback;
     // TODO(guidou): Make |adapter_settings| a regular field instead of a
     // unique_ptr.
     std::unique_ptr<VideoTrackAdapterSettings> adapter_settings;
diff --git a/content/renderer/media/stream/media_stream_video_track.cc b/content/renderer/media/stream/media_stream_video_track.cc
index 094eccf..73969fd2 100644
--- a/content/renderer/media/stream/media_stream_video_track.cc
+++ b/content/renderer/media/stream/media_stream_video_track.cc
@@ -270,6 +270,9 @@
       media::BindToCurrentLoop(base::BindRepeating(
           &MediaStreamVideoTrack::SetSizeAndComputedFrameRate,
           weak_factory_.GetWeakPtr())),
+      media::BindToCurrentLoop(base::BindRepeating(
+          &MediaStreamVideoTrack::set_computed_source_format,
+          weak_factory_.GetWeakPtr())),
       callback);
 }
 
@@ -299,6 +302,9 @@
       media::BindToCurrentLoop(base::BindRepeating(
           &MediaStreamVideoTrack::SetSizeAndComputedFrameRate,
           weak_factory_.GetWeakPtr())),
+      media::BindToCurrentLoop(base::BindRepeating(
+          &MediaStreamVideoTrack::set_computed_source_format,
+          weak_factory_.GetWeakPtr())),
       callback);
 }
 
@@ -430,4 +436,9 @@
   adapter_settings_ = std::make_unique<VideoTrackAdapterSettings>(settings);
 }
 
+media::VideoCaptureFormat MediaStreamVideoTrack::GetComputedSourceFormat() {
+  DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+  return computed_source_format_;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/stream/media_stream_video_track.h b/content/renderer/media/stream/media_stream_video_track.h
index 6e0d9993..97530ee8 100644
--- a/content/renderer/media/stream/media_stream_video_track.h
+++ b/content/renderer/media/stream/media_stream_video_track.h
@@ -110,14 +110,24 @@
   // Setting information about the track size.
   // Passed as callback on MediaStreamVideoTrack::AddTrack, and run from
   // VideoFrameResolutionAdapter on frame delivery to update track settings.
-  void SetSizeAndComputedFrameRate(int width, int height, double frame_rate) {
-    width_ = width;
-    height_ = height;
+  void SetSizeAndComputedFrameRate(gfx::Size frame_size, double frame_rate) {
+    width_ = frame_size.width();
+    height_ = frame_size.height();
     computed_frame_rate_ = frame_rate;
   }
 
+  // Setting information about the source format. The format is computed based
+  // on incoming frames and it's used for applying constraints for remote video
+  // tracks. Passed as callback on MediaStreamVideoTrack::AddTrack, and run from
+  // VideoFrameResolutionAdapter on frame delivery.
+  void set_computed_source_format(const media::VideoCaptureFormat& format) {
+    computed_source_format_ = format;
+  }
+
   void SetTrackAdapterSettings(const VideoTrackAdapterSettings& settings);
 
+  media::VideoCaptureFormat GetComputedSourceFormat();
+
   MediaStreamVideoSource* source() const { return source_.get(); }
 
  private:
@@ -166,6 +176,7 @@
   int height_ = 0;
   double frame_rate_ = 0.0;
   base::Optional<double> computed_frame_rate_;
+  media::VideoCaptureFormat computed_source_format_;
 
   base::WeakPtrFactory<MediaStreamVideoTrack> weak_factory_;
 
diff --git a/content/renderer/media/stream/video_track_adapter.cc b/content/renderer/media/stream/video_track_adapter.cc
index 02a07e91..196117f 100644
--- a/content/renderer/media/stream/video_track_adapter.cc
+++ b/content/renderer/media/stream/video_track_adapter.cc
@@ -47,6 +47,15 @@
 const double kFrameRateChangeRate = 0.01;
 const double kFrameRateUpdateIntervalInSeconds = 5;
 
+struct ComputedSettings {
+  gfx::Size frame_size;
+  double frame_rate = MediaStreamVideoSource::kDefaultFrameRate;
+  double last_updated_frame_rate = MediaStreamVideoSource::kDefaultFrameRate;
+  base::TimeDelta prev_frame_timestamp = base::TimeDelta::Max();
+  base::TimeTicks new_frame_rate_timestamp;
+  base::TimeTicks last_update_timestamp;
+};
+
 // Empty method used for keeping a reference to the original media::VideoFrame
 // in VideoFrameResolutionAdapter::DeliverFrame if cropping is needed.
 // The reference to |frame| is kept in the closure that calls this method.
@@ -57,6 +66,53 @@
                   std::max(0, dimension));
 }
 
+void ComputeFrameRate(const base::TimeDelta& frame_timestamp,
+                      double* frame_rate,
+                      base::TimeDelta* prev_frame_timestamp) {
+  const double delta_ms =
+      (frame_timestamp - *prev_frame_timestamp).InMillisecondsF();
+  *prev_frame_timestamp = frame_timestamp;
+  if (delta_ms < 0)
+    return;
+
+  *frame_rate = 200 / delta_ms + 0.8 * *frame_rate;
+}
+
+// Controls the frequency of settings updates based on frame rate changes.
+// Returns |true| if over the last second the computed frame rate is
+// consistently kFrameRateChangeRate different than the last reported value,
+// or if there hasn't been any update in the last
+// kFrameRateUpdateIntervalInSeconds seconds.
+bool MaybeUpdateFrameRate(ComputedSettings* settings) {
+  base::TimeTicks now = base::TimeTicks::Now();
+
+  // Update frame rate if over the last second the computed frame rate has been
+  // consistently kFrameRateChangeIntervalInSeconds different than the last
+  // reported value.
+  if (std::abs(settings->frame_rate - settings->last_updated_frame_rate) >
+      settings->last_updated_frame_rate * kFrameRateChangeRate) {
+    if ((now - settings->new_frame_rate_timestamp).InSecondsF() >
+        kFrameRateChangeIntervalInSeconds) {
+      settings->new_frame_rate_timestamp = now;
+      settings->last_update_timestamp = now;
+      settings->last_updated_frame_rate = settings->frame_rate;
+      return true;
+    }
+  } else {
+    settings->new_frame_rate_timestamp = now;
+  }
+
+  // Update frame rate if it hasn't been updated in the last
+  // kFrameRateUpdateIntervalInSeconds seconds.
+  if ((now - settings->last_update_timestamp).InSecondsF() >
+      kFrameRateUpdateIntervalInSeconds) {
+    settings->last_update_timestamp = now;
+    settings->last_updated_frame_rate = settings->frame_rate;
+    return true;
+  }
+  return false;
+}
+
 }  // anonymous namespace
 
 // VideoFrameResolutionAdapter is created on and lives on the IO-thread. It does
@@ -68,6 +124,7 @@
   struct VideoTrackCallbacks {
     VideoCaptureDeliverFrameCB frame_callback;
     VideoTrackSettingsCallback settings_callback;
+    VideoTrackFormatCallback format_callback;
   };
   // Setting |max_frame_rate| to 0.0, means that no frame rate limitation
   // will be done.
@@ -80,7 +137,8 @@
   // |frame_callback| will however be released on the main render thread.
   void AddCallbacks(const MediaStreamVideoTrack* track,
                     VideoCaptureDeliverFrameCB frame_callback,
-                    VideoTrackSettingsCallback settings_callback);
+                    VideoTrackSettingsCallback settings_callback,
+                    VideoTrackFormatCallback format_callback);
 
   // Removes the callbacks associated with |track| if |track| has been added. It
   // is ok to call RemoveCallbacks() even if |track| has not been added.
@@ -122,14 +180,9 @@
       const VideoTrackSettingsCallback& settings_callback,
       const scoped_refptr<media::VideoFrame>& frame);
 
-  void ComputeFrameRate(const base::TimeDelta& frame_timestamp);
-
-  // Controls the frequency of track settings updates based on frame rate
-  // changes. Returns |true| if over the last second the computed frame rate
-  // is consistently kFrameRateChangeRate different than the last reported
-  // value, or if there hasn't been any update in the last
-  // kFrameRateUpdateIntervalInSeconds seconds.
-  bool MaybeUpdateFrameRate();
+  // Updates computed source format for all tracks if either frame width, height
+  // or frame rate have changed since last update.
+  void MaybeUpdateTracksFormat(const scoped_refptr<media::VideoFrame>& frame);
 
   // Bound to the IO-thread.
   THREAD_CHECKER(io_thread_checker_);
@@ -143,12 +196,8 @@
   base::TimeDelta last_time_stamp_;
   double keep_frame_counter_;
 
-  gfx::Size frame_size_;
-  double computed_frame_rate_;
-  double last_updated_frame_rate_;
-  base::TimeDelta prev_frame_timestamp_;
-  base::TimeTicks new_frame_rate_timestamp_;
-  base::TimeTicks last_update_timestamp_;
+  ComputedSettings track_settings_;
+  ComputedSettings source_format_settings_;
 
   base::flat_map<const MediaStreamVideoTrack*, VideoTrackCallbacks> callbacks_;
 
@@ -162,10 +211,7 @@
       settings_(settings),
       frame_rate_(MediaStreamVideoSource::kDefaultFrameRate),
       last_time_stamp_(base::TimeDelta::Max()),
-      keep_frame_counter_(0.0),
-      computed_frame_rate_(MediaStreamVideoSource::kDefaultFrameRate),
-      last_updated_frame_rate_(MediaStreamVideoSource::kDefaultFrameRate),
-      prev_frame_timestamp_(base::TimeDelta::Max()) {
+      keep_frame_counter_(0.0) {
   DCHECK(renderer_task_runner_.get());
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   CHECK_NE(0, settings_.max_aspect_ratio());
@@ -194,10 +240,12 @@
 void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallbacks(
     const MediaStreamVideoTrack* track,
     VideoCaptureDeliverFrameCB frame_callback,
-    VideoTrackSettingsCallback settings_callback) {
+    VideoTrackSettingsCallback settings_callback,
+    VideoTrackFormatCallback format_callback) {
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-  callbacks_.insert(
-      {track, {std::move(frame_callback), std::move(settings_callback)}});
+  callbacks_.insert({track,
+                     {std::move(frame_callback), std::move(settings_callback),
+                      std::move(format_callback)}});
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallbacks(
@@ -231,6 +279,10 @@
     return;
   }
 
+  ComputeFrameRate(frame->timestamp(), &source_format_settings_.frame_rate,
+                   &source_format_settings_.prev_frame_timestamp);
+  MaybeUpdateTracksFormat(frame);
+
   double frame_rate;
   if (!frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
                                     &frame_rate)) {
@@ -359,62 +411,33 @@
     const VideoTrackSettingsCallback& settings_callback,
     const scoped_refptr<media::VideoFrame>& frame) {
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-  ComputeFrameRate(frame->timestamp());
-  if (MaybeUpdateFrameRate() || frame->natural_size() != frame_size_) {
-    frame_size_ = frame->natural_size();
-    settings_callback.Run(frame_size_.width(), frame_size_.height(),
-                          computed_frame_rate_);
+  ComputeFrameRate(frame->timestamp(), &track_settings_.frame_rate,
+                   &track_settings_.prev_frame_timestamp);
+  if (MaybeUpdateFrameRate(&track_settings_) ||
+      frame->natural_size() != track_settings_.frame_size) {
+    track_settings_.frame_size = frame->natural_size();
+    settings_callback.Run(track_settings_.frame_size,
+                          track_settings_.frame_rate);
   }
 }
-
-void VideoTrackAdapter::VideoFrameResolutionAdapter::ComputeFrameRate(
-    const base::TimeDelta& frame_timestamp) {
+void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTracksFormat(
+    const scoped_refptr<media::VideoFrame>& frame) {
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-  const double delta_ms =
-      (frame_timestamp - prev_frame_timestamp_).InMillisecondsF();
-  prev_frame_timestamp_ = frame_timestamp;
-  if (delta_ms < 0)
-    return;
-
-  computed_frame_rate_ = 200 / delta_ms + 0.8 * computed_frame_rate_;
-}
-
-bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateFrameRate() {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-  base::TimeTicks now = base::TimeTicks::Now();
-
-  // Update frame rate if over the last second the computed frame rate has been
-  // consistently kFrameRateChangeIntervalInSeconds different than the last
-  // reported value.
-  if (std::abs(computed_frame_rate_ - last_updated_frame_rate_) >
-      last_updated_frame_rate_ * kFrameRateChangeRate) {
-    if ((now - new_frame_rate_timestamp_).InSecondsF() >
-        kFrameRateChangeIntervalInSeconds) {
-      new_frame_rate_timestamp_ = now;
-      last_update_timestamp_ = now;
-      last_updated_frame_rate_ = computed_frame_rate_;
-      return true;
-    }
-  } else {
-    new_frame_rate_timestamp_ = now;
+  if (MaybeUpdateFrameRate(&source_format_settings_) ||
+      frame->natural_size() != track_settings_.frame_size) {
+    source_format_settings_.frame_size = frame->natural_size();
+    media::VideoCaptureFormat source_format;
+    source_format.frame_size = source_format_settings_.frame_size;
+    source_format.frame_rate = source_format_settings_.frame_rate;
+    for (const auto& callback : callbacks_)
+      callback.second.format_callback.Run(source_format);
   }
-
-  // Update frame rate if it hasn't been updated in the last
-  // kFrameRateUpdateIntervalInSeconds seconds.
-  if ((now - last_update_timestamp_).InSecondsF() >
-      kFrameRateUpdateIntervalInSeconds) {
-    last_update_timestamp_ = now;
-    last_updated_frame_rate_ = computed_frame_rate_;
-    return true;
-  }
-  return false;
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::ResetFrameRate() {
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   for (const auto& callback : callbacks_) {
-    callback.second.settings_callback.Run(frame_size_.width(),
-                                          frame_size_.height(), 0.0);
+    callback.second.settings_callback.Run(track_settings_.frame_size, 0.0);
   }
 }
 
@@ -479,19 +502,22 @@
 void VideoTrackAdapter::AddTrack(const MediaStreamVideoTrack* track,
                                  VideoCaptureDeliverFrameCB frame_callback,
                                  VideoTrackSettingsCallback settings_callback,
+                                 VideoTrackFormatCallback format_callback,
                                  const VideoTrackAdapterSettings& settings) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   io_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VideoTrackAdapter::AddTrackOnIO, this, track,
-                                std::move(frame_callback),
-                                std::move(settings_callback), settings));
+      FROM_HERE,
+      base::BindOnce(&VideoTrackAdapter::AddTrackOnIO, this, track,
+                     std::move(frame_callback), std::move(settings_callback),
+                     std::move(format_callback), settings));
 }
 
 void VideoTrackAdapter::AddTrackOnIO(
     const MediaStreamVideoTrack* track,
     VideoCaptureDeliverFrameCB frame_callback,
     VideoTrackSettingsCallback settings_callback,
+    VideoTrackFormatCallback format_callback,
     const VideoTrackAdapterSettings& settings) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   scoped_refptr<VideoFrameResolutionAdapter> adapter;
@@ -507,7 +533,8 @@
   }
 
   adapter->AddCallbacks(track, std::move(frame_callback),
-                        std::move(settings_callback));
+                        std::move(settings_callback),
+                        std::move(format_callback));
 }
 
 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) {
@@ -680,7 +707,8 @@
   // If the track was found, re-add it with new settings.
   if (!track_callbacks.frame_callback.is_null())
     AddTrackOnIO(track, std::move(track_callbacks.frame_callback),
-                 std::move(track_callbacks.settings_callback), settings);
+                 std::move(track_callbacks.settings_callback),
+                 std::move(track_callbacks.format_callback), settings);
 }
 
 void VideoTrackAdapter::DeliverFrameOnIO(
diff --git a/content/renderer/media/stream/video_track_adapter.h b/content/renderer/media/stream/video_track_adapter.h
index 8bc2ee20..e2922996 100644
--- a/content/renderer/media/stream/video_track_adapter.h
+++ b/content/renderer/media/stream/video_track_adapter.h
@@ -93,6 +93,7 @@
   void AddTrack(const MediaStreamVideoTrack* track,
                 VideoCaptureDeliverFrameCB frame_callback,
                 VideoTrackSettingsCallback settings_callback,
+                VideoTrackFormatCallback track_callback,
                 const VideoTrackAdapterSettings& settings);
   void RemoveTrack(const MediaStreamVideoTrack* track);
   void ReconfigureTrack(const MediaStreamVideoTrack* track,
@@ -134,6 +135,7 @@
   void AddTrackOnIO(const MediaStreamVideoTrack* track,
                     VideoCaptureDeliverFrameCB frame_callback,
                     VideoTrackSettingsCallback settings_callback,
+                    VideoTrackFormatCallback track_callback,
                     const VideoTrackAdapterSettings& settings);
   void RemoveTrackOnIO(const MediaStreamVideoTrack* track);
   void ReconfigureTrackOnIO(const MediaStreamVideoTrack* track,
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
index cf9da60..d92d292c 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
@@ -24,6 +24,7 @@
 #include "media/base/media_log.h"
 #include "media/base/media_util.h"
 #include "media/base/overlay_info.h"
+#include "media/base/video_decoder_config.h"
 #include "media/base/video_types.h"
 #include "media/video/gpu_video_accelerator_factories.h"
 #include "third_party/webrtc/api/video/video_frame.h"
@@ -140,15 +141,25 @@
   }
 #endif  // defined(OS_WIN)
 
-  // Short circuit known-unsupported codecs.
+  // Bail early for unknown codecs.
   if (ToVideoCodec(video_codec_type) == media::kUnknownVideoCodec)
     return nullptr;
 
-  std::unique_ptr<RTCVideoDecoderAdapter> rtc_video_decoder_adapter =
-      base::WrapUnique(new RTCVideoDecoderAdapter(gpu_factories, format));
+  // Avoid the thread hop if the decoder is known not to support the config.
+  // TODO(sandersd): Predict size from level.
+  media::VideoDecoderConfig config(
+      ToVideoCodec(webrtc::PayloadStringToCodecType(format.name)),
+      GuessVideoCodecProfile(format), kDefaultPixelFormat,
+      media::VideoColorSpace(), media::VIDEO_ROTATION_0, kDefaultSize,
+      gfx::Rect(kDefaultSize), kDefaultSize, media::EmptyExtraData(),
+      media::Unencrypted());
+  if (!gpu_factories->IsDecoderConfigSupported(config))
+    return nullptr;
 
   // Synchronously verify that the decoder can be initialized.
-  if (!rtc_video_decoder_adapter->InitializeSync()) {
+  std::unique_ptr<RTCVideoDecoderAdapter> rtc_video_decoder_adapter =
+      base::WrapUnique(new RTCVideoDecoderAdapter(gpu_factories, format));
+  if (!rtc_video_decoder_adapter->InitializeSync(config)) {
     gpu_factories->GetTaskRunner()->DeleteSoon(
         FROM_HERE, std::move(rtc_video_decoder_adapter));
     return nullptr;
@@ -174,7 +185,8 @@
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 }
 
-bool RTCVideoDecoderAdapter::InitializeSync() {
+bool RTCVideoDecoderAdapter::InitializeSync(
+    const media::VideoDecoderConfig& config) {
   DVLOG(3) << __func__;
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
 
@@ -186,7 +198,8 @@
   if (media_task_runner_->PostTask(
           FROM_HERE,
           base::BindOnce(&RTCVideoDecoderAdapter::InitializeOnMediaThread,
-                         base::Unretained(this), std::move(init_cb)))) {
+                         base::Unretained(this), base::ConstRef(config),
+                         base::ConstRef(init_cb)))) {
     waiter.Wait();
   }
   return result;
@@ -290,7 +303,8 @@
 }
 
 void RTCVideoDecoderAdapter::InitializeOnMediaThread(
-    media::VideoDecoder::InitCB init_cb) {
+    const media::VideoDecoderConfig& config,
+    const media::VideoDecoder::InitCB& init_cb) {
   DVLOG(3) << __func__;
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
@@ -307,14 +321,6 @@
     return;
   }
 
-  // We don't know much about the media that is coming.
-  media::VideoDecoderConfig config(
-      ToVideoCodec(webrtc::PayloadStringToCodecType(format_.name)),
-      GuessVideoCodecProfile(format_), kDefaultPixelFormat,
-      media::VideoColorSpace(), media::VIDEO_ROTATION_0, kDefaultSize,
-      gfx::Rect(kDefaultSize), kDefaultSize, media::EmptyExtraData(),
-      media::Unencrypted());
-
   // In practice this is ignored by hardware decoders.
   bool low_delay = true;
 
@@ -324,8 +330,8 @@
   media::VideoDecoder::OutputCB output_cb =
       base::BindRepeating(&RTCVideoDecoderAdapter::OnOutput, weak_this_);
 
-  video_decoder_->Initialize(config, low_delay, cdm_context, std::move(init_cb),
-                             std::move(output_cb), base::DoNothing());
+  video_decoder_->Initialize(config, low_delay, cdm_context, init_cb, output_cb,
+                             base::DoNothing());
 }
 
 void RTCVideoDecoderAdapter::DecodeOnMediaThread() {
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.h b/content/renderer/media/webrtc/rtc_video_decoder_adapter.h
index ef54cca1..22a1933a 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.h
+++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.h
@@ -30,6 +30,7 @@
 class DecoderBuffer;
 class GpuVideoAcceleratorFactories;
 class MediaLog;
+class VideoDecoderConfig;
 class VideoFrame;
 }  // namespace media
 
@@ -85,8 +86,9 @@
   RTCVideoDecoderAdapter(media::GpuVideoAcceleratorFactories* gpu_factories,
                          const webrtc::SdpVideoFormat& format);
 
-  bool InitializeSync();
-  void InitializeOnMediaThread(media::VideoDecoder::InitCB init_cb);
+  bool InitializeSync(const media::VideoDecoderConfig& config);
+  void InitializeOnMediaThread(const media::VideoDecoderConfig& config,
+                               const media::VideoDecoder::InitCB& init_cb);
   void DecodeOnMediaThread();
   void OnDecodeDone(media::DecodeStatus status);
   void OnOutput(const scoped_refptr<media::VideoFrame>& frame);
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc
index e3959c3..b0c26eb 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc
@@ -100,6 +100,10 @@
         .WillByDefault(Return(media_thread_.task_runner()));
     EXPECT_CALL(gpu_factories_, GetTaskRunner()).Times(AtLeast(0));
 
+    ON_CALL(gpu_factories_, IsDecoderConfigSupported(_))
+        .WillByDefault(Return(true));
+    EXPECT_CALL(gpu_factories_, IsDecoderConfigSupported(_)).Times(AtLeast(0));
+
     ON_CALL(gpu_factories_, CreateVideoDecoder(_, _, _))
         .WillByDefault(
             [this](media::MediaLog* media_log,
@@ -199,9 +203,10 @@
       base::RepeatingCallback<void(const webrtc::VideoFrame&)>>>
       decoded_cb_;
 
- private:
   StrictMock<media::MockGpuVideoAcceleratorFactories> gpu_factories_;
   std::unique_ptr<RTCVideoDecoderAdapter> rtc_video_decoder_adapter_;
+
+ private:
   std::unique_ptr<StrictMock<MockVideoDecoder>> owned_video_decoder_;
   DecodedImageCallback decoded_image_callback_;
   media::VideoDecoder::OutputCB output_cb_;
@@ -209,6 +214,22 @@
   DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderAdapterTest);
 };
 
+TEST_F(RTCVideoDecoderAdapterTest, Create_UnknownFormat) {
+  rtc_video_decoder_adapter_ = RTCVideoDecoderAdapter::Create(
+      &gpu_factories_, webrtc::SdpVideoFormat(webrtc::CodecTypeToPayloadString(
+                           webrtc::kVideoCodecGeneric)));
+  ASSERT_FALSE(rtc_video_decoder_adapter_);
+}
+
+TEST_F(RTCVideoDecoderAdapterTest, Create_UnsupportedFormat) {
+  EXPECT_CALL(gpu_factories_, IsDecoderConfigSupported(_))
+      .WillOnce(Return(false));
+  rtc_video_decoder_adapter_ = RTCVideoDecoderAdapter::Create(
+      &gpu_factories_, webrtc::SdpVideoFormat(webrtc::CodecTypeToPayloadString(
+                           webrtc::kVideoCodecVP9)));
+  ASSERT_FALSE(rtc_video_decoder_adapter_);
+}
+
 TEST_F(RTCVideoDecoderAdapterTest, Lifecycle) {
   ASSERT_TRUE(BasicSetup());
   ASSERT_TRUE(BasicTeardown());
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_factory.cc b/content/renderer/media/webrtc/rtc_video_decoder_factory.cc
index e4d58d40..db9e4a4 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_factory.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder_factory.cc
@@ -157,6 +157,11 @@
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : gpu_factories_(gpu_factories) {
   DVLOG(2) << __func__;
+
+  // RTCVideoDecoderAdapter does not use |supported_formats_|.
+  if (base::FeatureList::IsEnabled(media::kRTCVideoDecoderAdapter))
+    return;
+
   const media::VideoDecodeAccelerator::SupportedProfiles profiles =
       gpu_factories_->GetVideoDecodeAcceleratorCapabilities()
           .supported_profiles;
@@ -170,6 +175,7 @@
 
 std::vector<webrtc::SdpVideoFormat>
 RTCVideoDecoderFactory::GetSupportedFormats() const {
+  DCHECK(!base::FeatureList::IsEnabled(media::kRTCVideoDecoderAdapter));
   return supported_formats_;
 }
 
diff --git a/content/renderer/media/webrtc/video_codec_factory.cc b/content/renderer/media/webrtc/video_codec_factory.cc
index 89446fe6..9be9ec9 100644
--- a/content/renderer/media/webrtc/video_codec_factory.cc
+++ b/content/renderer/media/webrtc/video_codec_factory.cc
@@ -6,11 +6,13 @@
 
 #include "base/base_switches.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
 #include "content/renderer/media/webrtc/rtc_video_decoder_factory.h"
 #include "content/renderer/media/webrtc/rtc_video_encoder_factory.h"
+#include "media/base/media_switches.h"
 #include "third_party/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.h"
 #include "third_party/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.h"
 #include "third_party/webrtc/media/base/codec.h"
@@ -61,6 +63,11 @@
 std::unique_ptr<webrtc::VideoDecoder> CreateDecoder(
     webrtc::VideoDecoderFactory* factory,
     const webrtc::SdpVideoFormat& format) {
+  if (base::FeatureList::IsEnabled(media::kRTCVideoDecoderAdapter))
+    return factory ? factory->CreateVideoDecoder(format) : nullptr;
+
+  // TODO(sandersd): Remove calls to GetSupportedFormats() once the
+  // RTCVideoDecoder path is gone.
   return IsFormatSupported(factory, format)
              ? factory->CreateVideoDecoder(format)
              : nullptr;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 1dedf10..934203f 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6706,15 +6706,7 @@
 
 bool RenderFrameImpl::CreatePlaceholderDocumentLoader(
     const blink::WebNavigationInfo& info) {
-  auto navigation_params = blink::WebNavigationParams::CreateFromInfo(info);
-  // We need the provider to be non-null, otherwise Blink crashes, even though
-  // the provider should not be used for any actual networking.
-  navigation_params->service_worker_network_provider =
-      BuildServiceWorkerNetworkProviderForNavigation(
-          nullptr /* request_params */,
-          nullptr /* controller_service_worker_info */);
-  return frame_->CreatePlaceholderDocumentLoader(
-      std::move(navigation_params), info.navigation_type, BuildDocumentState());
+  return frame_->CreatePlaceholderDocumentLoader(info, BuildDocumentState());
 }
 
 void RenderFrameImpl::BeginNavigationInternal(
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 35051fe0..99357db 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -2890,9 +2890,6 @@
   settings.enable_image_animation_resync =
       !cmd.HasSwitch(switches::kDisableImageAnimationResync);
 
-  settings.always_request_presentation_time =
-      cmd.HasSwitch(cc::switches::kAlwaysRequestPresentationTime);
-
   settings.send_compositor_frame_ack = false;
 
   return settings;
diff --git a/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt b/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt
index b25eb1e6..40dc2f72 100644
--- a/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt
+++ b/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt
@@ -10,7 +10,7 @@
 ++++++columnHeader name='cell 5' ariaCellColumnIndex=5 selected=false
 ++++++++staticText name='cell 5'
 ++++++++++inlineTextBox name='cell 5'
-++++row selected=false
+++++row ariaCellColumnIndex=2 selected=false
 ++++++cell name='cell 2' ariaCellColumnIndex=2 selected=false
 ++++++++staticText name='cell 2'
 ++++++++++inlineTextBox name='cell 2'
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 73f1cd7..697d74c 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -4,8 +4,8 @@
 
 import("//build/config/jumbo.gni")
 import("//build/config/ui.gni")
-import("//third_party/protobuf/proto_library.gni")
 import("//gpu/vulkan/features.gni")
+import("//third_party/protobuf/proto_library.gni")
 
 group("service") {
   if (is_component_build) {
@@ -258,15 +258,6 @@
     "wrapped_sk_image.h",
   ]
 
-  if (is_android) {
-    sources += [
-      "ahardwarebuffer_utils.cc",
-      "ahardwarebuffer_utils.h",
-      "shared_image_backing_factory_ahardwarebuffer.cc",
-      "shared_image_backing_factory_ahardwarebuffer.h",
-    ]
-  }
-
   configs += [
     "//build/config:precompiled_headers",
     "//gpu:gpu_gles2_implementation",
@@ -322,10 +313,31 @@
     ]
   }
 
-  if (is_android && !is_debug) {
-    # On Android optimize more since this component can be a bottleneck.
-    configs -= [ "//build/config/compiler:default_optimization" ]
-    configs += [ "//build/config/compiler:optimize_max" ]
+  if (is_android) {
+    if (!is_debug) {
+      # On Android optimize more since this component can be a bottleneck.
+      configs -= [ "//build/config/compiler:default_optimization" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
+    sources += [
+      "ahardwarebuffer_utils.cc",
+      "ahardwarebuffer_utils.h",
+      "shared_image_backing_factory_ahardwarebuffer.cc",
+      "shared_image_backing_factory_ahardwarebuffer.h",
+    ]
+
+    # TODO(cblume): http://crbug.com/911313
+    # Abstract out the platform specific defines. Right now we need the android
+    # platform specific define here to be able to include android specific
+    # functions.
+    defines = [ "VK_USE_PLATFORM_ANDROID_KHR" ]
+    deps += [ "//third_party/libsync" ]
+    if (enable_vulkan) {
+      deps += [
+        "//gpu/ipc/common:android_image_reader_utils",
+        "//gpu/vulkan:vulkan",
+      ]
+    }
   }
 }
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
index 93fdae99..cb4b858 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -4,9 +4,12 @@
 
 #include "gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h"
 
+#include <sync/sync.h>
+
 #include "base/android/android_hardware_buffer_compat.h"
 #include "base/android/scoped_hardware_buffer_handle.h"
 #include "base/logging.h"
+#include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
@@ -15,20 +18,86 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/raster_decoder_context_state.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
 #include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/ipc/common/android/android_image_reader_utils.h"
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "gpu/vulkan/vulkan_function_pointers.h"
+#include "gpu/vulkan/vulkan_implementation.h"
+#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_fence_android_native_fence_sync.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_image_ahardwarebuffer.h"
 #include "ui/gl/gl_version_info.h"
 
 namespace gpu {
 
+// Implementation of SharedImageBacking that holds an AHardwareBuffer. This
+// can be used to create a GL texture or a VK Image from the AHardwareBuffer
+// backing.
+class SharedImageBackingAHB : public SharedImageBacking {
+ public:
+  SharedImageBackingAHB(const Mailbox& mailbox,
+                        viz::ResourceFormat format,
+                        const gfx::Size& size,
+                        const gfx::ColorSpace& color_space,
+                        uint32_t usage,
+                        base::android::ScopedHardwareBufferHandle handle,
+                        size_t estimated_size,
+                        raster::RasterDecoderContextState* context_state);
+
+  ~SharedImageBackingAHB() override;
+
+  bool IsCleared() const override;
+  void SetCleared() override;
+  void Update() override;
+  bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override;
+  void Destroy() override;
+  raster::RasterDecoderContextState* GetContextState() const;
+  base::ScopedFD TakeGLWriteSyncFd();
+  base::ScopedFD TakeVkReadSyncFd();
+  base::android::ScopedHardwareBufferHandle GetAhbHandle();
+  void SetGLWriteSyncFd(base::ScopedFD fd);
+  void SetVkReadSyncFd(base::ScopedFD fd);
+
+ protected:
+  std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
+      SharedImageManager* manager,
+      MemoryTypeTracker* tracker) override;
+
+  std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia(
+      SharedImageManager* manager,
+      MemoryTypeTracker* tracker) override;
+
+ private:
+  bool GenGLTexture();
+  base::android::ScopedHardwareBufferHandle hardware_buffer_handle_;
+
+  // This texture will be lazily initialised/created when ProduceGLTexture is
+  // called.
+  gles2::Texture* texture_ = nullptr;
+
+  // TODO(vikassoni): In future when we add begin/end write support, we will
+  // need to properly use this flag to pass the is_cleared_ information to
+  // the GL texture representation while begin write and back to this class from
+  // the GL texture represntation after end write. This is because this class
+  // will not know if SetCleared() arrives during begin write happening on GL
+  // texture representation.
+  bool is_cleared_ = false;
+  raster::RasterDecoderContextState* context_state_ = nullptr;
+  base::ScopedFD gl_write_sync_fd_;
+  base::ScopedFD vk_read_sync_fd_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedImageBackingAHB);
+};
+
 // Representation of a SharedImageBackingAHB as a GL Texture.
 class SharedImageRepresentationGLTextureAHB
     : public SharedImageRepresentationGLTexture {
@@ -42,15 +111,52 @@
 
   gles2::Texture* GetTexture() override { return texture_; }
 
+  bool BeginAccess(GLenum mode) override {
+    // TODO(vikassoni): Currently Skia Vk backing never does a write. So GL read
+    // do not need to wait for the Vk write to finish. Eventually when Vk starts
+    // writing, we will need to TakeVkWriteSyncFd() and wait on it for mode =
+    // GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM.
+
+    // Wait on Vk read if GL is going to write.
+    // TODO(vikassoni): GL writes should wait on both Vk read and Vk writes.
+    if (mode == GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM) {
+      base::ScopedFD sync_fd = ahb_backing()->TakeVkReadSyncFd();
+
+      // Create an egl fence sync and do a server side wait.
+      if (!InsertEglFenceAndWait(std::move(sync_fd)))
+        return false;
+    }
+    mode_ = mode;
+    return true;
+  }
+
+  void EndAccess() override {
+    // TODO(vikassoni): Currently Skia Vk backing never does a write. So Vk
+    // writes do not need to wait on GL to finish the read. Eventually when Vk
+    // starts writing, we will need to create and set a GLReadSyncFd for mode =
+    // GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM for Vk to wait on it.
+    if (mode_ == GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM) {
+      base::ScopedFD sync_fd = CreateEglFenceAndExportFd();
+      if (!sync_fd.is_valid())
+        return;
+
+      // Pass this fd to its backing.
+      ahb_backing()->SetGLWriteSyncFd(std::move(sync_fd));
+    }
+  }
+
  private:
+  SharedImageBackingAHB* ahb_backing() {
+    return static_cast<SharedImageBackingAHB*>(backing());
+  }
+
   gles2::Texture* texture_;
+  GLenum mode_ = GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM;
 
   DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureAHB);
 };
 
 // GL backed Skia representation of SharedImageBackingAHB.
-// TODO(vikassoni): Add follow up patch to add a vulkan backed skia
-// representation.
 class SharedImageRepresentationSkiaGLAHB
     : public SharedImageRepresentationSkia {
  public:
@@ -69,9 +175,19 @@
       GrContext* gr_context,
       int final_msaa_count,
       const SkSurfaceProps& surface_props) override {
+    // if there is already a write_surface_, it means previous BeginWriteAccess
+    // doesn't have a corresponding EndWriteAccess.
     if (write_surface_)
       return nullptr;
 
+    // Synchronise this access with the Vk reads.
+    // TODO(vikassoni): SkiaGL writes should wait on both Vk read and Vk writes.
+    base::ScopedFD sync_fd = ahb_backing()->TakeVkReadSyncFd();
+
+    // Create an egl fence sync and do a server side wait.
+    if (!InsertEglFenceAndWait(std::move(sync_fd)))
+      return nullptr;
+
     GrBackendTexture backend_texture;
     if (!GetGrBackendTexture(gl::GLContext::GetCurrent()->GetVersionInfo(),
                              target_, size(), service_id_, format(),
@@ -93,9 +209,22 @@
     DCHECK(surface->unique());
     // TODO(ericrk): Keep the surface around for re-use.
     write_surface_ = nullptr;
+
+    // Insert a gl fence to signal the write completion. Vulkan representation
+    // needs to wait on this signal before it can read from this.
+    base::ScopedFD sync_fd = CreateEglFenceAndExportFd();
+    if (!sync_fd.is_valid())
+      return;
+
+    // Pass this fd to its backing.
+    ahb_backing()->SetGLWriteSyncFd(std::move(sync_fd));
   }
 
-  bool BeginReadAccess(GrBackendTexture* backend_texture) override {
+  bool BeginReadAccess(SkSurface* sk_surface,
+                       GrBackendTexture* backend_texture) override {
+    // TODO(vikassoni): Currently Skia Vk backing never does a write. So this
+    // read do not need to wait for the Vk write to finish. Eventually when Vk
+    // starts writing, we might need to TakeVkWriteSyncFd() and wait on it.
     if (!GetGrBackendTexture(gl::GLContext::GetCurrent()->GetVersionInfo(),
                              target_, size(), service_id_, format(),
                              backend_texture)) {
@@ -105,193 +234,376 @@
   }
 
   void EndReadAccess() override {
+    // TODO(vikassoni): Currently Skia Vk backing never does a write. So Vk
+    // writes do not need to wait on this read to finish. Eventually when Vk
+    // starts writing, we will need to create and set a SkiaGLReadSyncFd.
     // TODO(ericrk): Handle begin/end correctness checks.
   }
 
  private:
+  SharedImageBackingAHB* ahb_backing() {
+    return static_cast<SharedImageBackingAHB*>(backing());
+  }
+
   GLenum target_;
   GLuint service_id_;
-
   SkSurface* write_surface_ = nullptr;
 };
 
-// Implementation of SharedImageBacking that holds an AHardwareBuffer. This
-// can be used to create a GL texture or a VK Image from the AHardwareBuffer
-// backing.
-class SharedImageBackingAHB : public SharedImageBacking {
+// Vk backed Skia representation of SharedImageBackingAHB.
+class SharedImageRepresentationSkiaVkAHB
+    : public SharedImageRepresentationSkia {
  public:
-  SharedImageBackingAHB(const Mailbox& mailbox,
-                        viz::ResourceFormat format,
-                        const gfx::Size& size,
-                        const gfx::ColorSpace& color_space,
-                        uint32_t usage,
-                        base::android::ScopedHardwareBufferHandle handle,
-                        size_t estimated_size)
-      : SharedImageBacking(mailbox,
-                           format,
-                           size,
-                           color_space,
-                           usage,
-                           estimated_size),
-        hardware_buffer_handle_(std::move(handle)) {
-    DCHECK(hardware_buffer_handle_.is_valid());
+  SharedImageRepresentationSkiaVkAHB(SharedImageManager* manager,
+                                     SharedImageBacking* backing)
+      : SharedImageRepresentationSkia(manager, backing, nullptr) {
+    SharedImageBackingAHB* ahb_backing =
+        static_cast<SharedImageBackingAHB*>(backing);
+    DCHECK(ahb_backing);
+    raster::RasterDecoderContextState* context_state =
+        ahb_backing->GetContextState();
+    DCHECK(context_state);
+    DCHECK(context_state->vk_context_provider);
+
+    vk_device_ =
+        context_state->vk_context_provider->GetDeviceQueue()->GetVulkanDevice();
+    vk_phy_device_ = context_state->vk_context_provider->GetDeviceQueue()
+                         ->GetVulkanPhysicalDevice();
+    vk_implementation_ =
+        context_state->vk_context_provider->GetVulkanImplementation();
   }
 
-  ~SharedImageBackingAHB() override {
-    // Check to make sure buffer is explicitly destroyed using Destroy() api
-    // before this destructor is called.
-    DCHECK(!hardware_buffer_handle_.is_valid());
-    DCHECK(!texture_);
+  ~SharedImageRepresentationSkiaVkAHB() override { DCHECK(!read_surface_); }
+
+  sk_sp<SkSurface> BeginWriteAccess(
+      GrContext* gr_context,
+      int final_msaa_count,
+      const SkSurfaceProps& surface_props) override {
+    NOTIMPLEMENTED();
+    return nullptr;
   }
 
-  bool IsCleared() const override {
-    if (texture_)
-      return texture_->IsLevelCleared(texture_->target(), 0);
-    return is_cleared_;
-  }
+  void EndWriteAccess(sk_sp<SkSurface> surface) override { NOTIMPLEMENTED(); }
 
-  void SetCleared() override {
-    if (texture_)
-      texture_->SetLevelCleared(texture_->target(), 0, true);
-    is_cleared_ = true;
-  }
-
-  void Update() override {}
-
-  bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override {
-    DCHECK(hardware_buffer_handle_.is_valid());
-    if (!GenGLTexture())
+  bool BeginReadAccess(SkSurface* sk_surface,
+                       GrBackendTexture* backend_texture) override {
+    // If previous read access has not ended.
+    if (read_surface_)
       return false;
-    DCHECK(texture_);
-    mailbox_manager->ProduceTexture(mailbox(), texture_);
+    DCHECK(sk_surface);
+    DCHECK(backend_texture);
+
+    // Synchronise the read access with the GL writes.
+    base::ScopedFD sync_fd = ahb_backing()->TakeGLWriteSyncFd();
+
+    // We need to wait only if there is a valid fd.
+    if (sync_fd.is_valid()) {
+      // Do a client side wait for now.
+      // TODO(vikassoni): There seems to be a skia bug -
+      // https://bugs.chromium.org/p/chromium/issues/detail?id=916812 currently
+      // where wait() on the sk surface crashes. Remove the sync_wait() and
+      // apply CL mentioned in the bug when the issue is fixed.
+      static const int InfiniteSyncWaitTimeout = -1;
+      if (sync_wait(sync_fd.get(), InfiniteSyncWaitTimeout) < 0) {
+        LOG(ERROR) << "Failed while waiting on GL Write sync fd";
+        return false;
+      }
+    }
+
+    // Create a VkImage and import AHB.
+    VkImage vk_image;
+    VkImageCreateInfo vk_image_info;
+    VkDeviceMemory vk_device_memory;
+    VkDeviceSize mem_allocation_size;
+    if (!vk_implementation_->CreateVkImageAndImportAHB(
+            vk_device_, vk_phy_device_, size(), ahb_backing()->GetAhbHandle(),
+            &vk_image, &vk_image_info, &vk_device_memory,
+            &mem_allocation_size)) {
+      return false;
+    }
+
+    // Create backend texture from the VkImage.
+    GrVkAlloc alloc = {vk_device_memory, 0, mem_allocation_size, 0};
+    GrVkImageInfo vk_info = {vk_image,
+                             alloc,
+                             vk_image_info.tiling,
+                             vk_image_info.initialLayout,
+                             vk_image_info.format,
+                             vk_image_info.mipLevels};
+    *backend_texture =
+        GrBackendTexture(size().width(), size().height(), vk_info);
+    if (!backend_texture->isValid()) {
+      vkDestroyImage(vk_device_, vk_image, nullptr);
+      vkFreeMemory(vk_device_, vk_device_memory, nullptr);
+      return false;
+    }
+
+    // Cache the sk surface in the representation so that it can be used in the
+    // EndReadAccess. Also make sure previous read_surface_ have been consumed
+    // by EndReadAccess() call.
+    read_surface_ = sk_surface;
     return true;
   }
 
-  void Destroy() override {
-    DCHECK(hardware_buffer_handle_.is_valid());
-    if (texture_) {
-      texture_->RemoveLightweightRef(have_context());
-      texture_ = nullptr;
+  void EndReadAccess() override {
+    // There should be a read_surface_ from the BeginReadAccess().
+    DCHECK(read_surface_);
+
+    // Create a vk semaphore which can be exported.
+    VkExportSemaphoreCreateInfo export_info;
+    export_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+    export_info.pNext = nullptr;
+    export_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+    VkSemaphore vk_semaphore;
+    VkSemaphoreCreateInfo sem_info;
+    sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    sem_info.pNext = &export_info;
+    sem_info.flags = 0;
+    bool result =
+        vkCreateSemaphore(vk_device_, &sem_info, nullptr, &vk_semaphore);
+    if (result != VK_SUCCESS) {
+      // TODO(vikassoni): add more error handling rather than just return ?
+      LOG(ERROR) << "vkCreateSemaphore failed";
+      read_surface_ = nullptr;
+      return;
     }
-    hardware_buffer_handle_.reset();
-  }
+    GrBackendSemaphore gr_semaphore;
+    gr_semaphore.initVulkan(vk_semaphore);
 
- protected:
-  std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
-      SharedImageManager* manager,
-      MemoryTypeTracker* tracker) override {
-    // Use same texture for all the texture representations generated from same
-    // backing.
-    if (!GenGLTexture())
-      return nullptr;
+    // If GrSemaphoresSubmitted::kNo is returned, the GPU back-end did not
+    // create or add any semaphores to signal on the GPU; the caller should not
+    // instruct the GPU to wait on any of the semaphores.
+    if (read_surface_->flushAndSignalSemaphores(1, &gr_semaphore) ==
+        GrSemaphoresSubmitted::kNo) {
+      vkDestroySemaphore(vk_device_, vk_semaphore, nullptr);
+      read_surface_ = nullptr;
+      return;
+    }
+    read_surface_ = nullptr;
 
-    DCHECK(texture_);
-    return std::make_unique<SharedImageRepresentationGLTextureAHB>(
-        manager, this, tracker, texture_);
-  }
+    // All the pending SkSurface commands to the GPU-backed API are issued and
+    // any SkSurface MSAA are resolved. After issuing all commands,
+    // signalSemaphores of count numSemaphores semaphores are signaled by the
+    // GPU. The caller must delete the semaphores created.
+    // Export a sync fd from the semaphore.
+    base::ScopedFD sync_fd;
+    vk_implementation_->GetSemaphoreFdKHR(vk_device_, vk_semaphore, &sync_fd);
 
-  std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia(
-      SharedImageManager* manager,
-      MemoryTypeTracker* tracker) override {
-    // TODO(vikassoni): Currently we only have a GL backed skia representation.
-    // Follow up patch will add support to check whether we are in Vulkan mode
-    // OR  GL mode and accordingly create Skia representation.
-    if (!GenGLTexture())
-      return nullptr;
+    // pass this sync fd to the backing.
+    ahb_backing()->SetVkReadSyncFd(std::move(sync_fd));
 
-    DCHECK(texture_);
-    return std::make_unique<SharedImageRepresentationSkiaGLAHB>(
-        manager, this, tracker, texture_->target(), texture_->service_id());
+    // TODO(vikassoni): We need to wait for the queue submission to complete
+    // before we can destroy the semaphore. This will decrease the performance.
+    // Add a future patch to handle this in more efficient way. Keep semaphores
+    // in a STL queue instead of destroying it. Later use a fence to check if
+    // the batch that refers the semaphore has completed execution. Delete the
+    // semaphore once the fence is signalled.
+    vkDeviceWaitIdle(vk_device_);
+    vkDestroySemaphore(vk_device_, vk_semaphore, nullptr);
   }
 
  private:
-  bool GenGLTexture() {
-    if (texture_)
-      return true;
-
-    DCHECK(hardware_buffer_handle_.is_valid());
-
-    // Target for AHB backed egl images.
-    // Note that we are not using GL_TEXTURE_EXTERNAL_OES target since sksurface
-    // doesnt supports it. As per the egl documentation -
-    // https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
-    // if GL_OES_EGL_image is supported then <target> may also be TEXTURE_2D.
-    GLenum target = GL_TEXTURE_2D;
-    GLenum get_target = GL_TEXTURE_BINDING_2D;
-
-    // Create a gles2 texture using the AhardwareBuffer.
-    gl::GLApi* api = gl::g_current_gl_context;
-    GLuint service_id = 0;
-    api->glGenTexturesFn(1, &service_id);
-    GLint old_texture_binding = 0;
-    api->glGetIntegervFn(get_target, &old_texture_binding);
-    api->glBindTextureFn(target, service_id);
-    api->glTexParameteriFn(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    api->glTexParameteriFn(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    api->glTexParameteriFn(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    api->glTexParameteriFn(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-    // Create an egl image using AHardwareBuffer.
-    auto egl_image = base::MakeRefCounted<gl::GLImageAHardwareBuffer>(size());
-    if (!egl_image->Initialize(hardware_buffer_handle_.get(), false)) {
-      LOG(ERROR) << "Failed to create EGL image ";
-      api->glBindTextureFn(target, old_texture_binding);
-      api->glDeleteTexturesFn(1, &service_id);
-      return false;
-    }
-    if (!egl_image->BindTexImage(target)) {
-      LOG(ERROR) << "Failed to bind egl image";
-      api->glBindTextureFn(target, old_texture_binding);
-      api->glDeleteTexturesFn(1, &service_id);
-      return false;
-    }
-
-    // Create a gles2 Texture.
-    texture_ = new gles2::Texture(service_id);
-    texture_->SetLightweightRef();
-    texture_->SetTarget(target, 1);
-    texture_->sampler_state_.min_filter = GL_LINEAR;
-    texture_->sampler_state_.mag_filter = GL_LINEAR;
-    texture_->sampler_state_.wrap_t = GL_CLAMP_TO_EDGE;
-    texture_->sampler_state_.wrap_s = GL_CLAMP_TO_EDGE;
-
-    // If the backing is already cleared, no need to clear it again.
-    gfx::Rect cleared_rect;
-    if (is_cleared_)
-      cleared_rect = gfx::Rect(size());
-
-    GLenum gl_format = viz::GLDataFormat(format());
-    GLenum gl_type = viz::GLDataType(format());
-    texture_->SetLevelInfo(target, 0, egl_image->GetInternalFormat(),
-                           size().width(), size().height(), 1, 0, gl_format,
-                           gl_type, cleared_rect);
-    texture_->SetLevelImage(target, 0, egl_image.get(), gles2::Texture::BOUND);
-    texture_->SetImmutable(true);
-    api->glBindTextureFn(target, old_texture_binding);
-    DCHECK_EQ(egl_image->GetInternalFormat(), gl_format);
-    return true;
+  SharedImageBackingAHB* ahb_backing() {
+    return static_cast<SharedImageBackingAHB*>(backing());
   }
 
-  base::android::ScopedHardwareBufferHandle hardware_buffer_handle_;
-
-  // This texture will be lazily initialised/created when ProduceGLTexture is
-  // called.
-  gles2::Texture* texture_ = nullptr;
-
-  // TODO(vikassoni): In future when we add begin/end write support, we will
-  // need to properly use this flag to pass the is_cleared_ information to
-  // the GL texture representation while begin write and back to this class from
-  // the GL texture represntation after end write. This is because this class
-  // will not know if SetCleared() arrives during begin write happening on GL
-  // texture representation.
-  bool is_cleared_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(SharedImageBackingAHB);
+  SkSurface* read_surface_ = nullptr;
+  gpu::VulkanImplementation* vk_implementation_ = nullptr;
+  VkDevice vk_device_ = VK_NULL_HANDLE;
+  VkPhysicalDevice vk_phy_device_ = VK_NULL_HANDLE;
 };
 
+SharedImageBackingAHB::SharedImageBackingAHB(
+    const Mailbox& mailbox,
+    viz::ResourceFormat format,
+    const gfx::Size& size,
+    const gfx::ColorSpace& color_space,
+    uint32_t usage,
+    base::android::ScopedHardwareBufferHandle handle,
+    size_t estimated_size,
+    raster::RasterDecoderContextState* context_state)
+    : SharedImageBacking(mailbox,
+                         format,
+                         size,
+                         color_space,
+                         usage,
+                         estimated_size),
+      hardware_buffer_handle_(std::move(handle)),
+      context_state_(context_state) {
+  DCHECK(hardware_buffer_handle_.is_valid());
+}
+
+SharedImageBackingAHB::~SharedImageBackingAHB() {
+  // Check to make sure buffer is explicitly destroyed using Destroy() api
+  // before this destructor is called.
+  DCHECK(!hardware_buffer_handle_.is_valid());
+  DCHECK(!texture_);
+}
+
+bool SharedImageBackingAHB::IsCleared() const {
+  if (texture_)
+    return texture_->IsLevelCleared(texture_->target(), 0);
+  return is_cleared_;
+}
+
+void SharedImageBackingAHB::SetCleared() {
+  if (texture_)
+    texture_->SetLevelCleared(texture_->target(), 0, true);
+  is_cleared_ = true;
+}
+
+void SharedImageBackingAHB::Update() {}
+
+bool SharedImageBackingAHB::ProduceLegacyMailbox(
+    MailboxManager* mailbox_manager) {
+  DCHECK(hardware_buffer_handle_.is_valid());
+  if (!GenGLTexture())
+    return false;
+  DCHECK(texture_);
+  mailbox_manager->ProduceTexture(mailbox(), texture_);
+  return true;
+}
+
+void SharedImageBackingAHB::Destroy() {
+  DCHECK(hardware_buffer_handle_.is_valid());
+  if (texture_) {
+    texture_->RemoveLightweightRef(have_context());
+    texture_ = nullptr;
+  }
+  hardware_buffer_handle_.reset();
+}
+
+raster::RasterDecoderContextState* SharedImageBackingAHB::GetContextState()
+    const {
+  return context_state_;
+}
+
+base::ScopedFD SharedImageBackingAHB::TakeGLWriteSyncFd() {
+  return std::move(gl_write_sync_fd_);
+}
+
+void SharedImageBackingAHB::SetGLWriteSyncFd(base::ScopedFD fd) {
+  gl_write_sync_fd_ = std::move(fd);
+}
+
+base::ScopedFD SharedImageBackingAHB::TakeVkReadSyncFd() {
+  return std::move(vk_read_sync_fd_);
+}
+
+void SharedImageBackingAHB::SetVkReadSyncFd(base::ScopedFD fd) {
+  vk_read_sync_fd_ = std::move(fd);
+}
+
+base::android::ScopedHardwareBufferHandle
+SharedImageBackingAHB::GetAhbHandle() {
+  return hardware_buffer_handle_.Clone();
+}
+
+std::unique_ptr<SharedImageRepresentationGLTexture>
+SharedImageBackingAHB::ProduceGLTexture(SharedImageManager* manager,
+                                        MemoryTypeTracker* tracker) {
+  // Use same texture for all the texture representations generated from same
+  // backing.
+  if (!GenGLTexture())
+    return nullptr;
+
+  DCHECK(texture_);
+  return std::make_unique<SharedImageRepresentationGLTextureAHB>(
+      manager, this, tracker, texture_);
+}
+
+std::unique_ptr<SharedImageRepresentationSkia>
+SharedImageBackingAHB::ProduceSkia(SharedImageManager* manager,
+                                   MemoryTypeTracker* tracker) {
+  DCHECK(context_state_);
+
+  // Check whether we are in Vulkan mode OR GL mode and accordingly create
+  // Skia representation.
+  if (context_state_->use_vulkan_gr_context) {
+    return std::make_unique<SharedImageRepresentationSkiaVkAHB>(manager, this);
+  }
+
+  if (!GenGLTexture())
+    return nullptr;
+
+  DCHECK(texture_);
+  return std::make_unique<SharedImageRepresentationSkiaGLAHB>(
+      manager, this, tracker, texture_->target(), texture_->service_id());
+}
+
+bool SharedImageBackingAHB::GenGLTexture() {
+  if (texture_)
+    return true;
+
+  DCHECK(hardware_buffer_handle_.is_valid());
+
+  // Target for AHB backed egl images.
+  // Note that we are not using GL_TEXTURE_EXTERNAL_OES target since sksurface
+  // doesn't supports it. As per the egl documentation -
+  // https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
+  // if GL_OES_EGL_image is supported then <target> may also be TEXTURE_2D.
+  GLenum target = GL_TEXTURE_2D;
+  GLenum get_target = GL_TEXTURE_BINDING_2D;
+
+  // Create a gles2 texture using the AhardwareBuffer.
+  gl::GLApi* api = gl::g_current_gl_context;
+  GLuint service_id = 0;
+  api->glGenTexturesFn(1, &service_id);
+  GLint old_texture_binding = 0;
+  api->glGetIntegervFn(get_target, &old_texture_binding);
+  api->glBindTextureFn(target, service_id);
+  api->glTexParameteriFn(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  api->glTexParameteriFn(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  api->glTexParameteriFn(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  api->glTexParameteriFn(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  // Create an egl image using AHardwareBuffer.
+  auto egl_image = base::MakeRefCounted<gl::GLImageAHardwareBuffer>(size());
+  if (!egl_image->Initialize(hardware_buffer_handle_.get(), false)) {
+    LOG(ERROR) << "Failed to create EGL image ";
+    api->glBindTextureFn(target, old_texture_binding);
+    api->glDeleteTexturesFn(1, &service_id);
+    return false;
+  }
+  if (!egl_image->BindTexImage(target)) {
+    LOG(ERROR) << "Failed to bind egl image";
+    api->glBindTextureFn(target, old_texture_binding);
+    api->glDeleteTexturesFn(1, &service_id);
+    return false;
+  }
+
+  // Create a gles2 Texture.
+  texture_ = new gles2::Texture(service_id);
+  texture_->SetLightweightRef();
+  texture_->SetTarget(target, 1);
+  texture_->sampler_state_.min_filter = GL_LINEAR;
+  texture_->sampler_state_.mag_filter = GL_LINEAR;
+  texture_->sampler_state_.wrap_t = GL_CLAMP_TO_EDGE;
+  texture_->sampler_state_.wrap_s = GL_CLAMP_TO_EDGE;
+
+  // If the backing is already cleared, no need to clear it again.
+  gfx::Rect cleared_rect;
+  if (is_cleared_)
+    cleared_rect = gfx::Rect(size());
+
+  GLenum gl_format = viz::GLDataFormat(format());
+  GLenum gl_type = viz::GLDataType(format());
+  texture_->SetLevelInfo(target, 0, egl_image->GetInternalFormat(),
+                         size().width(), size().height(), 1, 0, gl_format,
+                         gl_type, cleared_rect);
+  texture_->SetLevelImage(target, 0, egl_image.get(), gles2::Texture::BOUND);
+  texture_->SetImmutable(true);
+  api->glBindTextureFn(target, old_texture_binding);
+  DCHECK_EQ(egl_image->GetInternalFormat(), gl_format);
+  return true;
+}
+
 SharedImageBackingFactoryAHB::SharedImageBackingFactoryAHB(
     const GpuDriverBugWorkarounds& workarounds,
-    const GpuFeatureInfo& gpu_feature_info) {
+    const GpuFeatureInfo& gpu_feature_info,
+    raster::RasterDecoderContextState* context_state)
+    : context_state_(context_state) {
   scoped_refptr<gles2::FeatureInfo> feature_info =
       new gles2::FeatureInfo(workarounds, gpu_feature_info);
   feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2, false,
@@ -314,7 +626,8 @@
     info.ahb_format = AHardwareBufferFormat(format);
 
     // TODO(vikassoni): In future when we use GL_TEXTURE_EXTERNAL_OES target
-    // with AHB, we need to check if oes_egl_image_external is supported or not.
+    // with AHB, we need to check if oes_egl_image_external is supported or
+    // not.
     if (!is_egl_image_supported)
       continue;
 
@@ -325,11 +638,8 @@
     GLenum gl_format = viz::GLDataFormat(format);
     GLenum gl_type = viz::GLDataType(format);
 
-    //  GLImageAHardwareBuffer currently supports internal format GL_RGBA only.
-    //  TODO(vikassoni): Pass the AHBuffer format while GLImageAHardwareBuffer
-    //  creation and based on that return the equivalent internal format as
-    //  GL_RGBA or GL_RGB.
-    if (internal_format != GL_RGBA)
+    //  GLImageAHardwareBuffer supports internal format GL_RGBA and GL_RGB.
+    if (internal_format != GL_RGBA && internal_format != GL_RGB)
       continue;
 
     // Validate if GL format, type and internal format is supported.
@@ -344,12 +654,13 @@
   }
   // TODO(vikassoni): We are using below GL api calls for now as Vulkan mode
   // doesn't exist. Once we have vulkan support, we shouldn't query GL in this
-  // code until we are asked to make a GL representation (or allocate a backing
-  // for import into GL)? We may use an AHardwareBuffer exclusively with Vulkan,
-  // where there is no need to require that a GL context is current. Maybe we
-  // can lazy init this if someone tries to create an AHardwareBuffer with
-  // SHARED_IMAGE_USAGE_GLES2 || !gpu_preferences.enable_vulkan. When in Vulkan
-  // mode, we should only need this with GLES2.
+  // code until we are asked to make a GL representation (or allocate a
+  // backing for import into GL)? We may use an AHardwareBuffer exclusively
+  // with Vulkan, where there is no need to require that a GL context is
+  // current. Maybe we can lazy init this if someone tries to create an
+  // AHardwareBuffer with SHARED_IMAGE_USAGE_GLES2 ||
+  // !gpu_preferences.enable_vulkan. When in Vulkan mode, we should only need
+  // this with GLES2.
   gl::GLApi* api = gl::g_current_gl_context;
   api->glGetIntegervFn(GL_MAX_TEXTURE_SIZE, &max_gl_texture_size_);
 
@@ -381,16 +692,16 @@
   }
 
   // SHARED_IMAGE_USAGE_RASTER is set when we want to write on Skia
-  // representation and SHARED_IMAGE_USAGE_DISPLAY is used for cases we want to
-  // read from skia representation.
-  // TODO(vikassoni): Also check gpu_preferences.enable_vulkan to figure out if
-  // skia is using vulkan backing or GL backing.
+  // representation and SHARED_IMAGE_USAGE_DISPLAY is used for cases we want
+  // to read from skia representation.
+  // TODO(vikassoni): Also check gpu_preferences.enable_vulkan to figure out
+  // if skia is using vulkan backing or GL backing.
   const bool use_gles2 =
       (usage & (SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_RASTER |
                 SHARED_IMAGE_USAGE_DISPLAY));
 
-  // If usage flags indicated this backing can be used as a GL texture, then do
-  // below gl related checks.
+  // If usage flags indicated this backing can be used as a GL texture, then
+  // do below gl related checks.
   if (use_gles2) {
     // Check if the GL texture can be created from AHB with this format.
     if (!format_info.gl_supported) {
@@ -449,7 +760,8 @@
 
   auto backing = std::make_unique<SharedImageBackingAHB>(
       mailbox, format, size, color_space, usage,
-      base::android::ScopedHardwareBufferHandle::Adopt(buffer), estimated_size);
+      base::android::ScopedHardwareBufferHandle::Adopt(buffer), estimated_size,
+      context_state_);
   return backing;
 }
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h
index 4988f47e..fba257a 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h
@@ -22,13 +22,19 @@
 struct GpuFeatureInfo;
 struct Mailbox;
 
+namespace raster {
+struct RasterDecoderContextState;
+}  // namespace raster
+
 // Implementation of SharedImageBackingFactory that produces AHardwareBuffer
 // backed SharedImages. This is meant to be used on Android only.
 class GPU_GLES2_EXPORT SharedImageBackingFactoryAHB
     : public SharedImageBackingFactory {
  public:
-  SharedImageBackingFactoryAHB(const GpuDriverBugWorkarounds& workarounds,
-                               const GpuFeatureInfo& gpu_feature_info);
+  SharedImageBackingFactoryAHB(
+      const GpuDriverBugWorkarounds& workarounds,
+      const GpuFeatureInfo& gpu_feature_info,
+      raster::RasterDecoderContextState* context_state);
   ~SharedImageBackingFactoryAHB() override;
 
   // SharedImageBackingFactory implementation.
@@ -77,6 +83,7 @@
 
   // Used to limit the max size of AHardwareBuffer.
   int32_t max_gl_texture_size_ = 0;
+  raster::RasterDecoderContextState* context_state_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SharedImageBackingFactoryAHB);
 };
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
index 354a0c6c..746605e 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
@@ -49,8 +49,6 @@
 
     GpuDriverBugWorkarounds workarounds;
     workarounds.max_texture_size = INT_MAX - 1;
-    backing_factory_ = std::make_unique<SharedImageBackingFactoryAHB>(
-        workarounds, GpuFeatureInfo());
 
     scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup();
     context_state_ = new raster::RasterDecoderContextState(
@@ -61,6 +59,9 @@
         base::MakeRefCounted<gles2::FeatureInfo>(workarounds, GpuFeatureInfo());
     context_state_->InitializeGL(std::move(feature_info));
 
+    backing_factory_ = std::make_unique<SharedImageBackingFactoryAHB>(
+        workarounds, GpuFeatureInfo(), context_state_.get());
+
     memory_type_tracker_ = std::make_unique<MemoryTypeTracker>(nullptr);
     shared_image_representation_factory_ =
         std::make_unique<SharedImageRepresentationFactory>(
@@ -149,7 +150,7 @@
   EXPECT_EQ(size.height(), surface->height());
   skia_representation->EndWriteAccess(std::move(surface));
   GrBackendTexture backend_texture;
-  EXPECT_TRUE(skia_representation->BeginReadAccess(&backend_texture));
+  EXPECT_TRUE(skia_representation->BeginReadAccess(nullptr, &backend_texture));
   EXPECT_EQ(size.width(), backend_texture.width());
   EXPECT_EQ(size.width(), backend_texture.width());
   skia_representation->EndReadAccess();
@@ -209,7 +210,7 @@
       shared_image_representation_factory_->ProduceSkia(mailbox);
   EXPECT_TRUE(skia_representation);
   GrBackendTexture backend_texture;
-  EXPECT_TRUE(skia_representation->BeginReadAccess(&backend_texture));
+  EXPECT_TRUE(skia_representation->BeginReadAccess(nullptr, &backend_texture));
   EXPECT_EQ(size.width(), backend_texture.width());
   EXPECT_EQ(size.width(), backend_texture.width());
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
index 257ad55f..0ccfee8 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
@@ -269,7 +269,8 @@
     write_surface_ = nullptr;
   }
 
-  bool BeginReadAccess(GrBackendTexture* backend_texture) override {
+  bool BeginReadAccess(SkSurface* sk_surface,
+                       GrBackendTexture* backend_texture) override {
     if (!GetGrBackendTexture(gl::GLContext::GetCurrent()->GetVersionInfo(),
                              target_, size(), service_id_, format(),
                              backend_texture)) {
@@ -814,24 +815,23 @@
     gfx::BufferFormat format,
     SurfaceHandle surface_handle,
     const gfx::Size& size) {
+  if (handle.type == gfx::SHARED_MEMORY_BUFFER) {
+    if (!base::IsValueInRangeForNumericType<size_t>(handle.stride))
+      return nullptr;
+    auto image = base::MakeRefCounted<gl::GLImageSharedMemory>(size);
+    if (!image->Initialize(handle.region, handle.id, format, handle.offset,
+                           handle.stride)) {
+      return nullptr;
+    }
+
+    return image;
+  }
+
   if (!image_factory_)
     return nullptr;
-  switch (handle.type) {
-    case gfx::SHARED_MEMORY_BUFFER: {
-      if (!base::IsValueInRangeForNumericType<size_t>(handle.stride))
-        return nullptr;
-      auto image = base::MakeRefCounted<gl::GLImageSharedMemory>(size);
-      if (!image->Initialize(handle.region, handle.id, format, handle.offset,
-                             handle.stride)) {
-        return nullptr;
-      }
 
-      return image;
-    }
-    default:
-      return image_factory_->CreateImageForGpuMemoryBuffer(
-          std::move(handle), size, format, client_id, surface_handle);
-  }
+  return image_factory_->CreateImageForGpuMemoryBuffer(
+      std::move(handle), size, format, client_id, surface_handle);
 }
 
 std::unique_ptr<SharedImageBacking>
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
index 9b1a5b4..3d58a1b 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
@@ -186,7 +186,7 @@
   EXPECT_EQ(size.height(), surface->height());
   skia_representation->EndWriteAccess(std::move(surface));
   GrBackendTexture backend_texture;
-  EXPECT_TRUE(skia_representation->BeginReadAccess(&backend_texture));
+  EXPECT_TRUE(skia_representation->BeginReadAccess(nullptr, &backend_texture));
   EXPECT_EQ(size.width(), backend_texture.width());
   EXPECT_EQ(size.width(), backend_texture.width());
   skia_representation->EndReadAccess();
@@ -270,7 +270,7 @@
   EXPECT_EQ(size.height(), surface->height());
   skia_representation->EndWriteAccess(std::move(surface));
   GrBackendTexture backend_texture;
-  EXPECT_TRUE(skia_representation->BeginReadAccess(&backend_texture));
+  EXPECT_TRUE(skia_representation->BeginReadAccess(nullptr, &backend_texture));
   EXPECT_EQ(size.width(), backend_texture.width());
   EXPECT_EQ(size.width(), backend_texture.width());
   skia_representation->EndReadAccess();
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h
index 8a1f962..5a1ea6b 100644
--- a/gpu/command_buffer/service/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -112,7 +112,8 @@
       int final_msaa_count,
       const SkSurfaceProps& surface_props) = 0;
   virtual void EndWriteAccess(sk_sp<SkSurface> surface) = 0;
-  virtual bool BeginReadAccess(GrBackendTexture* backend_texture_out) = 0;
+  virtual bool BeginReadAccess(SkSurface* sk_surface,
+                               GrBackendTexture* backend_texture_out) = 0;
   virtual void EndReadAccess() = 0;
 };
 
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index 4b24e0f..f5c9c38 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -205,7 +205,8 @@
     write_surface_ = nullptr;
   }
 
-  bool BeginReadAccess(GrBackendTexture* backend_texture) override {
+  bool BeginReadAccess(SkSurface* sk_surface,
+                       GrBackendTexture* backend_texture) override {
     if (!wrapped_sk_image()->GetGrBackendTexture(backend_texture))
       return false;
     return true;
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc
index a833540bc..46710ba 100644
--- a/gpu/ipc/service/direct_composition_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -1026,8 +1026,28 @@
   RECT target_rect = gfx::Rect(swap_chain_size).ToRECT();
   decode_swap_chain_->SetTargetRect(&target_rect);
 
-  // TODO(sunnyps): Set color space on swap chain.  Setting Rec 709 color space
-  // on the swap chain seems to produce incorrect colors.
+  gfx::ColorSpace color_space = image_dxgi->color_space();
+  if (!color_space.IsValid())
+    color_space = gfx::ColorSpace::CreateREC709();
+
+  // TODO(sunnyps): Move this to gfx::ColorSpaceWin helper where we can access
+  // internal color space state and do a better job.
+  // Common color spaces have primaries and transfer function similar to BT 709
+  // and there are no other choices anyway.
+  int flags = DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAG_BT709;
+  // Proper Rec 709 and 601 have limited or nominal color range.
+  if (color_space == gfx::ColorSpace::CreateREC709() ||
+      color_space == gfx::ColorSpace::CreateREC601()) {
+    flags |= DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAG_NOMINAL_RANGE;
+  }
+  // xvYCC allows colors outside nominal range to encode negative colors that
+  // allows for a wider gamut.
+  if (color_space.FullRangeEncodedValues()) {
+    flags |= DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAG_xvYCC;
+  }
+  decode_swap_chain_->SetColorSpace(
+      static_cast<DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAGS>(flags));
+
   HRESULT hr = decode_swap_chain_->PresentBuffer(image_dxgi->level(), 1, 0);
   base::UmaHistogramSparse("GPU.DirectComposition.DecodeSwapChainPresentResult",
                            hr);
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm
index 9042d96bb..0b27cd0 100644
--- a/ios/chrome/browser/prerender/preload_controller.mm
+++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -348,9 +348,10 @@
   return nil;
 }
 
-- (CGFloat)nativeContentHeaderHeightForWebState:(web::WebState*)webState {
-  return [delegate_ nativeContentHeaderHeightForPreloadController:self
-                                                         webState:webState];
+- (UIEdgeInsets)nativeContentInsetForWebState:(web::WebState*)webState {
+  // |-controllerForURL:webState:| short-circuits the native controller
+  // presentation flow, so the insets are never used.
+  return UIEdgeInsetsZero;
 }
 
 #pragma mark -
diff --git a/ios/chrome/browser/prerender/preload_controller_delegate.h b/ios/chrome/browser/prerender/preload_controller_delegate.h
index aa905cf..c1dc4fb 100644
--- a/ios/chrome/browser/prerender/preload_controller_delegate.h
+++ b/ios/chrome/browser/prerender/preload_controller_delegate.h
@@ -18,12 +18,6 @@
 // Returns YES if the given |url| should be backed by a native controller.
 - (BOOL)preloadHasNativeControllerForURL:(const GURL&)url;
 
-// Called to retrieve the height of any header that is overlaying on top of the
-// native content.
-- (CGFloat)
-nativeContentHeaderHeightForPreloadController:(PreloadController*)controller
-                                     webState:(web::WebState*)webState;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_PRERENDER_PRELOAD_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h
index 25d5e822..abc1498 100644
--- a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h
+++ b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h
@@ -17,10 +17,10 @@
 
 // Initializes a coordinator for displaying an alert on this |viewController|.
 // |dialogLocation| is a point where the repost form dialog should be presented
-// on iPad. |webState| must not be null and must be owned by the caller.
-// |completionHandler| will be called with YES when Continue button is tapped
-// and with NO when Cancel button is tapped. |completionHandler| can not be
-// null.
+// on iPad (in |viewController|'s coordinate space). |webState| must not be null
+// and must be owned by the caller. |completionHandler| will be called with YES
+// when Continue button is tapped and with NO when Cancel button is tapped.
+// |completionHandler| can not be null.
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                             dialogLocation:(CGPoint)dialogLocation
                                   webState:(web::WebState*)webState
diff --git a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm
index 210fc20..d94fbeb 100644
--- a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm
+++ b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm
@@ -48,7 +48,7 @@
     _webState = webState;
     CGRect sourceRect = CGRectMake(dialogLocation.x, dialogLocation.y, 1, 1);
     _dialogController =
-        [[self class] newDialogControllerForSourceView:webState->GetView()
+        [[self class] newDialogControllerForSourceView:viewController.view
                                             sourceRect:sourceRect
                                      completionHandler:completionHandler];
     // The dialog may be dimissed when a new navigation starts while the dialog
@@ -66,7 +66,8 @@
     return;
 
   // Check to see if an action sheet can be shown.
-  if ([_webState->GetView() window]) {
+  if (self.baseViewController.view.window &&
+      !self.baseViewController.presentedViewController) {
     [self.baseViewController presentViewController:_dialogController
                                           animated:YES
                                         completion:nil];
diff --git a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator_unittest.mm b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator_unittest.mm
index 6b2f860..7f2ee8d4 100644
--- a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator_unittest.mm
@@ -31,9 +31,6 @@
  protected:
   RepostFormCoordinatorTest() {
     view_controller_ = [[UIViewController alloc] init];
-    [scoped_key_window_.Get() setRootViewController:view_controller_];
-    UIView* view = [[UIView alloc] initWithFrame:view_controller_.view.bounds];
-    web_state_.SetView(view);
 
     CGPoint dialogLocation =
         CGPointMake(kDialogHorizontalLocation, kDialogVerticalLocation);
@@ -52,7 +49,7 @@
 
   // Coordinator will not present the dialog until view is added to the window.
   void AddViewToWindow() {
-    [view_controller_.view addSubview:web_state_.GetView()];
+    [scoped_key_window_.Get() setRootViewController:view_controller_];
   }
 
   RepostFormCoordinator* coordinator_;
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index de05eb0..5adefbf 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -2486,15 +2486,20 @@
 }
 
 - (CGRect)ntpFrameForWebState:(web::WebState*)webState {
-  UIEdgeInsets headerInset = UIEdgeInsetsMake(
-      [self nativeContentHeaderHeightForWebState:webState], 0, 0, 0);
-  return UIEdgeInsetsInsetRect(self.contentArea.bounds, headerInset);
+  NewTabPageTabHelper* NTPHelper = NewTabPageTabHelper::FromWebState(webState);
+  if (!NTPHelper || !NTPHelper->IsActive())
+    return CGRectZero;
+  // NTP expects to be laid out behind the bottom toolbar.  It uses
+  // |contentInset| to push content above the toolbar.
+  UIEdgeInsets viewportInsets = [self viewportInsetsForView:self.contentArea];
+  viewportInsets.bottom = 0.0;
+  return UIEdgeInsetsInsetRect(self.contentArea.bounds, viewportInsets);
 }
 
 - (CGRect)visibleFrameForTab:(Tab*)tab {
-  UIEdgeInsets headerInset = UIEdgeInsetsMake(
-      [self nativeContentHeaderHeightForWebState:tab.webState], 0, 0, 0);
-  return UIEdgeInsetsInsetRect([self viewForTab:tab].bounds, headerInset);
+  UIView* tabView = [self viewForTab:tab];
+  return UIEdgeInsetsInsetRect(tabView.bounds,
+                               [self viewportInsetsForView:tabView]);
 }
 
 - (void)setFramesForHeaders:(NSArray<HeaderDefinition*>*)headers
@@ -3019,19 +3024,6 @@
          CGRectGetHeight(_downloadManagerCoordinator.viewController.view.frame);
 }
 
-// Returns a vertical voice search bar offset relative to the tab content.
-- (CGFloat)voiceSearchOverlayYOffsetForTab:(Tab*)tab {
-  if (tab != self.tabModel.currentTab) {
-    // There is no UI representation for non-current tabs or there is
-    // no visible voice search. Return offset outside of tab.
-    return CGRectGetMaxY(self.view.frame);
-  } else {
-    // The voice search bar on iPhone is displayed at the bottom of a tab.
-    CGRect visibleFrame = [self visibleFrameForTab:self.tabModel.currentTab];
-    return CGRectGetMaxY(visibleFrame);
-  }
-}
-
 #pragma mark - PasswordControllerDelegate methods
 
 - (BOOL)displaySignInNotification:(UIViewController*)viewController
@@ -3336,9 +3328,9 @@
     runRepostFormDialogWithCompletionHandler:(void (^)(BOOL))handler {
   // Display the action sheet with the arrow pointing at the top center of the
   // web contents.
-  UIView* view = webState->GetView();
+  CGRect bounds = self.view.bounds;
   CGPoint dialogLocation = CGPointMake(
-      CGRectGetMidX(view.frame), CGRectGetMinY(view.frame) + self.headerHeight);
+      CGRectGetMidX(bounds), CGRectGetMinY(bounds) + self.headerHeight);
   auto* helper = RepostFormTabHelper::FromWebState(webState);
   helper->PresentDialog(dialogLocation, base::BindOnce(^(bool shouldContinue) {
                           handler(shouldContinue);
@@ -3627,15 +3619,8 @@
   return nativeController;
 }
 
-- (CGFloat)nativeContentHeaderHeightForWebState:(web::WebState*)webState {
-  if (IsVisibleURLNewTabPage(webState) && ![self canShowTabStrip]) {
-    if (self.usesFullscreenContainer)
-      return 0;
-    // Also subtract the top safe area so the view will appear as full screen.
-    // TODO(crbug.com/826369) Remove this once NTP is out of native content.
-    return -self.view.safeAreaInsets.top;
-  }
-  return self.headerHeight;
+- (UIEdgeInsets)nativeContentInsetForWebState:(web::WebState*)webState {
+  return [self viewportInsetsForView:webState->GetView()];
 }
 
 #pragma mark - DialogPresenterDelegate methods
@@ -3654,7 +3639,9 @@
 
 - (CGFloat)collapsedTopToolbarHeight {
   if (base::FeatureList::IsEnabled(web::features::kOutOfWebFullscreen) &&
-      IsVisibleURLNewTabPage(self.currentWebState)) {
+      IsVisibleURLNewTabPage(self.currentWebState) && ![self canShowTabStrip]) {
+    // When the NTP is displayed in a horizontally compact environment, the top
+    // toolbars are hidden.
     return 0;
   }
   CGFloat collapsedToolbarHeight =
@@ -3670,7 +3657,9 @@
 
 - (CGFloat)expandedTopToolbarHeight {
   if (base::FeatureList::IsEnabled(web::features::kOutOfWebFullscreen) &&
-      IsVisibleURLNewTabPage(self.currentWebState)) {
+      IsVisibleURLNewTabPage(self.currentWebState) && ![self canShowTabStrip]) {
+    // When the NTP is displayed in a horizontally compact environment, the top
+    // toolbars are hidden.
     return 0;
   }
   return [self primaryToolbarHeightWithInset] +
@@ -3679,10 +3668,6 @@
 }
 
 - (CGFloat)bottomToolbarHeight {
-  if (base::FeatureList::IsEnabled(web::features::kOutOfWebFullscreen) &&
-      IsVisibleURLNewTabPage(self.currentWebState)) {
-    return 0;
-  }
   return [self secondaryToolbarHeightWithInset];
 }
 
@@ -3875,6 +3860,23 @@
   return -(topHeader.frame.origin.y - self.headerOffset);
 }
 
+// Returns the insets into |view| that result in the visible viewport.
+- (UIEdgeInsets)viewportInsetsForView:(UIView*)view {
+  DCHECK(view);
+  UIEdgeInsets viewportInsets = FullscreenControllerFactory::GetInstance()
+                                    ->GetForBrowserState(_browserState)
+                                    ->GetCurrentViewportInsets();
+  // TODO(crbug.com/917548): Use BVC for viewport inset coordinate space rather
+  // than the content area.
+  CGRect viewportFrame = [view
+      convertRect:UIEdgeInsetsInsetRect(self.contentArea.bounds, viewportInsets)
+         fromView:self.contentArea];
+  return UIEdgeInsetsMake(
+      CGRectGetMinY(viewportFrame), CGRectGetMinX(viewportFrame),
+      CGRectGetMaxY(view.bounds) - CGRectGetMaxY(viewportFrame),
+      CGRectGetMaxX(view.bounds) - CGRectGetMaxX(viewportFrame));
+}
+
 #pragma mark - KeyCommandsPlumbing
 
 - (BOOL)isOffTheRecord {
@@ -4967,12 +4969,6 @@
   return [self hasControllerForURL:url];
 }
 
-- (CGFloat)
-nativeContentHeaderHeightForPreloadController:(PreloadController*)controller
-                                     webState:(web::WebState*)webState {
-  return [self nativeContentHeaderHeightForWebState:webState];
-}
-
 #pragma mark - NetExportTabHelperDelegate
 
 - (void)netExportTabHelper:(NetExportTabHelper*)tabHelper
diff --git a/ios/chrome/browser/ui/open_in_controller.mm b/ios/chrome/browser/ui/open_in_controller.mm
index af43388..ed86ab2 100644
--- a/ios/chrome/browser/ui/open_in_controller.mm
+++ b/ios/chrome/browser/ui/open_in_controller.mm
@@ -311,7 +311,7 @@
 
   OpenInToolbar* openInToolbar = [self openInToolbar];
   if (!isOpenInToolbarDisplayed_) {
-    openInToolbar.bottomMarginConstraint.active = YES;
+    [openInToolbar updateBottomMarginHeight];
     [UIView animateWithDuration:kOpenInToolbarAnimationDuration
                      animations:^{
                        [openInToolbar setAlpha:1.0];
diff --git a/ios/chrome/browser/ui/open_in_toolbar.h b/ios/chrome/browser/ui/open_in_toolbar.h
index 1584594..4e017b44 100644
--- a/ios/chrome/browser/ui/open_in_toolbar.h
+++ b/ios/chrome/browser/ui/open_in_toolbar.h
@@ -11,8 +11,8 @@
 
 - (instancetype)initWithTarget:(id)target action:(SEL)action;
 
-// Constraint to have the open in toolbar be displayed above the bottom toolbar.
-@property(nonatomic, strong) NSLayoutConstraint* bottomMarginConstraint;
+// Updates the constraint managing the bottom margin height using NamedGuides.
+- (void)updateBottomMarginHeight;
 
 @end
 
diff --git a/ios/chrome/browser/ui/open_in_toolbar.mm b/ios/chrome/browser/ui/open_in_toolbar.mm
index 45b42f2..fd3213a3 100644
--- a/ios/chrome/browser/ui/open_in_toolbar.mm
+++ b/ios/chrome/browser/ui/open_in_toolbar.mm
@@ -57,6 +57,9 @@
 // https://crbug.com/857371.
 @property(nonatomic, strong) UIView* bottomMargin;
 
+// Constraint to have the open in toolbar be displayed above the bottom toolbar.
+@property(nonatomic, strong) NSLayoutConstraint* bottomMarginConstraint;
+
 // Relayout the frame of the Open In toolbar, based on its superview and the
 // bottom margin.
 - (void)relayout;
@@ -162,6 +165,27 @@
   return _topBorder;
 }
 
+- (void)setBottomMarginConstraint:(NSLayoutConstraint*)bottomMarginConstraint {
+  if (_bottomMarginConstraint == bottomMarginConstraint)
+    return;
+
+  _bottomMarginConstraint.active = NO;
+  _bottomMarginConstraint = bottomMarginConstraint;
+  _bottomMarginConstraint.active = YES;
+}
+
+#pragma mark Public
+
+- (void)updateBottomMarginHeight {
+  NSLayoutDimension* marginHeightAnchor = self.bottomMargin.heightAnchor;
+  NamedGuide* guide = [NamedGuide guideWithName:kSecondaryToolbarGuide
+                                           view:self];
+  self.bottomMarginConstraint =
+      guide ? [marginHeightAnchor constraintEqualToAnchor:guide.heightAnchor]
+            : [marginHeightAnchor constraintEqualToConstant:0];
+  [self relayout];
+}
+
 #pragma mark Layout
 
 - (CGSize)sizeThatFits:(CGSize)size {
@@ -172,21 +196,7 @@
 }
 
 - (void)didMoveToWindow {
-  if (!self.window) {
-    self.bottomMarginConstraint = nil;
-    return;
-  }
-
-  self.bottomMarginConstraint.active = NO;
-  // If the bottom toolbar isn't present on screen, guide is nil and then
-  // bottomMarginConstraint is also nil.
-  NamedGuide* guide =
-      [NamedGuide guideWithName:kSecondaryToolbarGuide view:self];
-  self.bottomMarginConstraint = [guide.heightAnchor
-      constraintEqualToAnchor:self.bottomMargin.heightAnchor];
-  self.bottomMarginConstraint.active = YES;
-
-  [self relayout];
+  [self updateBottomMarginHeight];
 }
 
 - (void)relayout {
diff --git a/ios/components/io_thread/DEPS b/ios/components/io_thread/DEPS
index c088928..89b16ff94 100644
--- a/ios/components/io_thread/DEPS
+++ b/ios/components/io_thread/DEPS
@@ -7,4 +7,8 @@
   "+components/version_info",
   "+ios/web/public",
   "+net",
+
+  # Temporarily allow WebThreadImpl until TaskExecutor functionality is moved
+  # into a new file in ios/web/public.
+  "+ios/web/web_thread_impl.h"
 ]
diff --git a/ios/components/io_thread/ios_io_thread_unittest.mm b/ios/components/io_thread/ios_io_thread_unittest.mm
index cc1580d..3915f21 100644
--- a/ios/components/io_thread/ios_io_thread_unittest.mm
+++ b/ios/components/io_thread/ios_io_thread_unittest.mm
@@ -4,16 +4,16 @@
 
 #include "ios/components/io_thread/ios_io_thread.h"
 
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/pref_service_factory.h"
-#include "components/prefs/testing_pref_store.h"
+#include <memory>
+
+#include "base/test/scoped_task_environment.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "net/test/url_request/url_request_failed_job.h"
-#include "net/url_request/url_request_filter.h"
+#import "ios/web/public/test/fakes/test_web_client.h"
+#include "ios/web/public/test/scoped_testing_web_client.h"
+#include "ios/web/public/test/test_web_thread.h"
+#include "ios/web/web_thread_impl.h"
+#include "net/base/network_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -42,32 +42,43 @@
 
 class IOSIOThreadTest : public PlatformTest {
  public:
-  IOSIOThreadTest() : thread_bundle_(web::TestWebThreadBundle::IO_MAINLOOP) {
-    net::URLRequestFailedJob::AddUrlHandler();
+  IOSIOThreadTest() : web_client_(std::make_unique<web::TestWebClient>()) {
+    web::WebThreadImpl::CreateTaskExecutor();
+
+    ui_thread_ = std::make_unique<web::TestWebThread>(
+        web::WebThread::UI, scoped_task_environment_.GetMainThreadTaskRunner());
   }
 
   ~IOSIOThreadTest() override {
-    net::URLRequestFilter::GetInstance()->ClearHandlers();
+    web::WebThreadImpl::ResetTaskExecutorForTesting();
   }
 
- private:
-  web::TestWebThreadBundle thread_bundle_;
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  web::ScopedTestingWebClient web_client_;
+  std::unique_ptr<web::TestWebThread> ui_thread_;
 };
 
 // Tests the creation of an IOSIOThread and verifies that it returns a system
 // url request context.
 TEST_F(IOSIOThreadTest, AssertSystemUrlRequestContext) {
-  PrefServiceFactory pref_service_factory;
-  pref_service_factory.set_user_prefs(base::MakeRefCounted<TestingPrefStore>());
+  std::unique_ptr<TestingPrefServiceSimple> pref_service(
+      std::make_unique<TestingPrefServiceSimple>());
+  PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service->registry());
 
-  scoped_refptr<PrefRegistrySimple> pref_registry = new PrefRegistrySimple;
-  PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get());
+  // Create the IO thread but do not register it yet.
+  std::unique_ptr<web::TestWebThread> io_thread(
+      std::make_unique<web::TestWebThread>(web::WebThread::IO));
+  io_thread->StartIOThreadUnregistered();
 
-  std::unique_ptr<PrefService> pref_service(
-      pref_service_factory.Create(pref_registry.get()));
-
-  std::unique_ptr<TestIOThread> test_io_thread(
+  // Create the TestIOThread before the IO thread is registered.
+  std::unique_ptr<TestIOThread> ios_io_thread(
       new TestIOThread(pref_service.get(), nullptr));
+  io_thread->RegisterAsWebThread();
 
-  ASSERT_TRUE(test_io_thread->system_url_request_context_getter());
+  ASSERT_TRUE(ios_io_thread->system_url_request_context_getter());
+
+  // Explicitly destroy the IO thread so that it is unregistered before the
+  // TestIOThread is destroyed.
+  io_thread.reset();
 }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 4ba52f6..6e5b9fa5 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -51,7 +51,6 @@
     "//services/network:network_service",
     "//services/network/public/mojom",
     "//services/service_manager",
-    "//services/service_manager/embedder",
     "//services/service_manager/public/cpp",
   ]
 
diff --git a/ios/web/app/web_main_loop.h b/ios/web/app/web_main_loop.h
index 3cc416d6..14ce06e 100644
--- a/ios/web/app/web_main_loop.h
+++ b/ios/web/app/web_main_loop.h
@@ -83,7 +83,7 @@
   // This must get destroyed after other threads that are created in parts_.
   std::unique_ptr<WebThreadImpl> main_thread_;
 
-  // Members initialized in |RunMainMessageLoopParts()| ------------------------
+  // Members initialized in |CreateThreads()| ------------------------
   std::unique_ptr<WebSubThread> io_thread_;
 
   // Members initialized in |WebThreadsStarted()| --------------------------
diff --git a/ios/web/app/web_main_loop.mm b/ios/web/app/web_main_loop.mm
index d3bf9fe..083fc5d1 100644
--- a/ios/web/app/web_main_loop.mm
+++ b/ios/web/app/web_main_loop.mm
@@ -130,7 +130,9 @@
   base::Thread::Options io_message_loop_options;
   io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
   io_thread_ = std::make_unique<WebSubThread>(WebThread::IO);
-  io_thread_->StartWithOptions(io_message_loop_options);
+  if (!io_thread_->StartWithOptions(io_message_loop_options))
+    LOG(FATAL) << "Failed to start WebThread::IO";
+  io_thread_->RegisterAsWebThread();
 
   // Only start IO thread above as this is the only WebThread besides UI (which
   // is the main thread).
@@ -196,8 +198,10 @@
   base::PlatformThread::SetName("CrWebMain");
 
   // Register the main thread by instantiating it, but don't call any methods.
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
   main_thread_.reset(new WebThreadImpl(
-      WebThread::UI, ios_global_state::GetMainThreadMessageLoop()));
+      WebThread::UI,
+      ios_global_state::GetMainThreadMessageLoop()->task_runner()));
 }
 
 int WebMainLoop::WebThreadsStarted() {
diff --git a/ios/web/public/test/fakes/test_native_content_provider.mm b/ios/web/public/test/fakes/test_native_content_provider.mm
index 17c390e..ad116ce 100644
--- a/ios/web/public/test/fakes/test_native_content_provider.mm
+++ b/ios/web/public/test/fakes/test_native_content_provider.mm
@@ -32,8 +32,8 @@
   return nativeContent == _nativeContent.end() ? nil : nativeContent->second;
 }
 
-- (CGFloat)nativeContentHeaderHeightForWebState:(web::WebState*)webState {
-  return 0;
+- (UIEdgeInsets)nativeContentInsetForWebState:(web::WebState*)webState {
+  return UIEdgeInsetsZero;
 }
 
 @end
diff --git a/ios/web/public/test/test_web_thread.h b/ios/web/public/test/test_web_thread.h
index bc5e427..449359e 100644
--- a/ios/web/public/test/test_web_thread.h
+++ b/ios/web/public/test/test_web_thread.h
@@ -12,18 +12,29 @@
 
 namespace base {
 class MessageLoop;
+class Thread;
 }
 
 namespace web {
 
-class TestWebThreadImpl;
+class WebSubThread;
+class WebThreadImpl;
 
 // DEPRECATED: use TestWebThreadBundle instead.
 // A WebThread for unit tests; this lets unit tests outside of web create
 // WebThread instances.
 class TestWebThread {
  public:
+  // Constructs a TestWebThread with a |real_thread_| and starts it (with a
+  // MessageLoopForIO if |identifier == WebThread::IO|).
   explicit TestWebThread(WebThread::ID identifier);
+
+  // Constructs a TestWebThread "running" on |thread_runner| (no
+  // |real_thread_|).
+  TestWebThread(WebThread::ID identifier,
+                scoped_refptr<base::SingleThreadTaskRunner> thread_runner);
+
+  // Constructs a TestWebThread based on |message_loop| (no |real_thread_|).
   TestWebThread(WebThread::ID identifier, base::MessageLoop* message_loop);
 
   ~TestWebThread();
@@ -33,22 +44,31 @@
   // WebThread, do no provide the full Thread interface.
 
   // Starts the thread with a generic message loop.
-  bool Start();
+  void Start();
 
   // Starts the thread with an IOThread message loop.
-  bool StartIOThread();
+  void StartIOThread();
+
+  // Together these are the same as StartIOThread(). They can be called in
+  // phases to test binding WebThread::IO after its underlying thread was
+  // started.
+  void StartIOThreadUnregistered();
+  void RegisterAsWebThread();
 
   // Stops the thread.
   void Stop();
 
-  // Returns true if the thread is running.
-  bool IsRunning();
-
  private:
-  std::unique_ptr<TestWebThreadImpl> impl_;
-
   const WebThread::ID identifier_;
 
+  // A real thread which represents |identifier_| when constructor #1 is used
+  // (null otherwise).
+  std::unique_ptr<WebSubThread> real_thread_;
+
+  // Binds |identifier_| to |message_loop| when constructor #2 is used (null
+  // otherwise).
+  std::unique_ptr<WebThreadImpl> fake_thread_;
+
   DISALLOW_COPY_AND_ASSIGN(TestWebThread);
 };
 
diff --git a/ios/web/public/web_state/ui/crw_native_content_provider.h b/ios/web/public/web_state/ui/crw_native_content_provider.h
index 01b3266f..2feba845 100644
--- a/ios/web/public/web_state/ui/crw_native_content_provider.h
+++ b/ios/web/public/web_state/ui/crw_native_content_provider.h
@@ -27,13 +27,8 @@
 - (id<CRWNativeContent>)controllerForURL:(const GURL&)url
                                 webState:(web::WebState*)webState;
 
-// Called to retrieve the height of any header that is overlaying on top of the
-// native content. This can be used to implement, for e.g. a toolbar that
-// changes height dynamically. Returning a non-zero height affects the visible
-// frame shown by the CRWWebController. 0.0 is assumed if not implemented.
-// TODO(crbug.com/674991) These should be removed when native content is
-// removed.
-- (CGFloat)nativeContentHeaderHeightForWebState:(web::WebState*)webState;
+// Returns the inset from |webState|'s view to lay out provided native content.
+- (UIEdgeInsets)nativeContentInsetForWebState:(web::WebState*)webState;
 
 @end
 
diff --git a/ios/web/public/web_thread.h b/ios/web/public/web_thread.h
index 1244866..811520d 100644
--- a/ios/web/public/web_thread.h
+++ b/ios/web/public/web_thread.h
@@ -95,9 +95,9 @@
   // Only one delegate may be registered at a time. Delegates may be
   // unregistered by providing a nullptr pointer.
   //
-  // If the caller unregisters a delegate before CleanUp has been
-  // called, it must perform its own locking to ensure the delegate is
-  // not deleted while unregistering.
+  // The delegate can only be registered through this call before
+  // WebThreadImpl(WebThread::IO) is created and unregistered after
+  // it was destroyed and its underlying thread shutdown.
   static void SetIOThreadDelegate(WebThreadDelegate* delegate);
 
   // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails.
diff --git a/ios/web/public/web_thread_delegate.h b/ios/web/public/web_thread_delegate.h
index 9c57bd67..f8005761 100644
--- a/ios/web/public/web_thread_delegate.h
+++ b/ios/web/public/web_thread_delegate.h
@@ -13,14 +13,17 @@
 // If registered as such, it will schedule to run Init() before the
 // message loop begins, and receive a CleanUp() call right after the message
 // loop ends (and before the WebThread has done its own clean-up).
+
+// A delegate for //web embedders to perform extra initialization/cleanup on
+// WebThread::IO.
 class WebThreadDelegate {
  public:
   virtual ~WebThreadDelegate() {}
 
-  // Called prior to starting the message loop
+  // Called prior to completing initialization of WebThread::IO.
   virtual void Init() = 0;
 
-  // Called just after the message loop ends.
+  // Called during teardown of WebThread::IO.
   virtual void CleanUp() = 0;
 };
 
diff --git a/ios/web/service_manager_context.mm b/ios/web/service_manager_context.mm
index 3f10f2b9..df31e85 100644
--- a/ios/web/service_manager_context.mm
+++ b/ios/web/service_manager_context.mm
@@ -26,10 +26,8 @@
 #include "ios/web/public/web_task_traits.h"
 #include "ios/web/public/web_thread.h"
 #include "ios/web/service_manager_connection_impl.h"
-#include "services/catalog/public/cpp/manifest_parsing_util.h"
 #include "services/catalog/public/mojom/constants.mojom.h"
 #include "services/service_manager/connect_params.h"
-#include "services/service_manager/embedder/manifest_utils.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/constants.h"
 #include "services/service_manager/public/cpp/manifest.h"
diff --git a/ios/web/test/test_web_thread.cc b/ios/web/test/test_web_thread.cc
index cee2468..4cb38dc 100644
--- a/ios/web/test/test_web_thread.cc
+++ b/ios/web/test/test_web_thread.cc
@@ -6,41 +6,36 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "ios/web/web_sub_thread.h"
 #include "ios/web/web_thread_impl.h"
 
 namespace web {
 
-class TestWebThreadImpl : public WebThreadImpl {
- public:
-  TestWebThreadImpl(WebThread::ID identifier) : WebThreadImpl(identifier) {}
-
-  TestWebThreadImpl(WebThread::ID identifier, base::MessageLoop* message_loop)
-      : WebThreadImpl(identifier, message_loop) {}
-
-  ~TestWebThreadImpl() override { Stop(); }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestWebThreadImpl);
-};
-
 TestWebThread::TestWebThread(WebThread::ID identifier)
-    : impl_(new TestWebThreadImpl(identifier)), identifier_(identifier) {}
+    : identifier_(identifier),
+      real_thread_(std::make_unique<WebSubThread>(identifier_)) {
+  real_thread_->AllowBlockingForTesting();
+}
+
+TestWebThread::TestWebThread(
+    WebThread::ID identifier,
+    scoped_refptr<base::SingleThreadTaskRunner> thread_runner)
+    : identifier_(identifier),
+      fake_thread_(new WebThreadImpl(identifier_, thread_runner)) {}
 
 TestWebThread::TestWebThread(WebThread::ID identifier,
                              base::MessageLoop* message_loop)
-    : impl_(new TestWebThreadImpl(identifier, message_loop)),
-      identifier_(identifier) {}
+    : TestWebThread(identifier, message_loop->task_runner()) {}
 
 TestWebThread::~TestWebThread() {
   // The upcoming WebThreadImpl::ResetGlobalsForTesting() call requires that
-  // |impl_| have triggered the shutdown phase for its WebThread::ID. This
-  // either happens when the thread is stopped (if real) or destroyed (when fake
-  // -- i.e. using an externally provided MessageLoop).
-  impl_.reset();
+  // |identifier_| completed its shutdown phase.
+  real_thread_.reset();
+  fake_thread_.reset();
 
-  // Resets WebThreadImpl's globals so that |impl_| is no longer bound to
-  // |identifier_|. This is fine since the underlying MessageLoop has already
-  // been flushed and deleted in Stop(). In the case of an externally provided
+  // Resets WebThreadImpl's globals so that |identifier_| is no longer
+  // bound. This is fine since the underlying MessageLoop has already been
+  // flushed and deleted above. In the case of an externally provided
   // MessageLoop however, this means that TaskRunners obtained through
   // |WebThreadImpl::GetTaskRunnerForThread(identifier_)| will no longer
   // recognize their WebThreadImpl for RunsTasksInCurrentSequence(). This
@@ -54,22 +49,29 @@
   WebThreadImpl::ResetGlobalsForTesting(identifier_);
 }
 
-bool TestWebThread::Start() {
-  return impl_->Start();
+void TestWebThread::Start() {
+  CHECK(real_thread_->Start());
+  RegisterAsWebThread();
 }
 
-bool TestWebThread::StartIOThread() {
+void TestWebThread::StartIOThread() {
+  StartIOThreadUnregistered();
+  RegisterAsWebThread();
+}
+
+void TestWebThread::StartIOThreadUnregistered() {
   base::Thread::Options options;
   options.message_loop_type = base::MessageLoop::TYPE_IO;
-  return impl_->StartWithOptions(options);
+  CHECK(real_thread_->StartWithOptions(options));
+}
+
+void TestWebThread::RegisterAsWebThread() {
+  real_thread_->RegisterAsWebThread();
 }
 
 void TestWebThread::Stop() {
-  impl_->Stop();
-}
-
-bool TestWebThread::IsRunning() {
-  return impl_->IsRunning();
+  if (real_thread_)
+    real_thread_->Stop();
 }
 
 }  // namespace web
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index c04b05c..57fcf41f4 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2347,9 +2347,9 @@
   return _webViewProxy;
 }
 
-- (CGFloat)nativeContentHeaderHeightForContainerView:
+- (UIEdgeInsets)nativeContentInsetsForContainerView:
     (CRWWebControllerContainerView*)containerView {
-  return [_nativeProvider nativeContentHeaderHeightForWebState:self.webState];
+  return [self.nativeProvider nativeContentInsetForWebState:self.webState];
 }
 
 #pragma mark -
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.h b/ios/web/web_state/ui/crw_web_controller_container_view.h
index 74f83c54..5b6d44e 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.h
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.h
@@ -21,8 +21,9 @@
 - (CRWWebViewProxyImpl*)contentViewProxyForContainerView:
         (CRWWebControllerContainerView*)containerView;
 
-// Returns the height for any toolbars that overlap the top native content.
-- (CGFloat)nativeContentHeaderHeightForContainerView:
+// Returns the insets from |containerView|'s bounds in which to lay out native
+// content.
+- (UIEdgeInsets)nativeContentInsetsForContainerView:
     (CRWWebControllerContainerView*)containerView;
 
 @end
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm
index 1a56c3a..e2af8c2 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -25,12 +25,6 @@
 // Convenience getter for the proxy object.
 @property(nonatomic, weak, readonly) CRWWebViewProxyImpl* contentViewProxy;
 
-// Returns |self.bounds| after being inset at the top and bottom by the header
-// and footer heights returned by the delegate.  This is only used to lay out
-// native controllers, as the header height is already accounted for in the
-// scroll view content insets for other CRWContentViews.
-@property(nonatomic, readonly) CGRect nativeContentVisibleFrame;
-
 @end
 
 @implementation CRWWebControllerContainerView
@@ -102,13 +96,6 @@
   return [_delegate contentViewProxyForContainerView:self];
 }
 
-- (CGRect)nativeContentVisibleFrame {
-  CGFloat headerHeight =
-      [_delegate nativeContentHeaderHeightForContainerView:self];
-  return UIEdgeInsetsInsetRect(self.bounds,
-                               UIEdgeInsetsMake(headerHeight, 0, 0, 0));
-}
-
 #pragma mark Layout
 
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
@@ -138,7 +125,8 @@
       [self addSubview:nativeView];
       [nativeView setNeedsUpdateConstraints];
     }
-    nativeView.frame = self.nativeContentVisibleFrame;
+    nativeView.frame = UIEdgeInsetsInsetRect(
+        self.bounds, [self.delegate nativeContentInsetsForContainerView:self]);
   }
 
   // transientContentView layout.
diff --git a/ios/web/web_sub_thread.cc b/ios/web/web_sub_thread.cc
index 5a7f39a..4ab2333 100644
--- a/ios/web/web_sub_thread.cc
+++ b/ios/web/web_sub_thread.cc
@@ -4,43 +4,122 @@
 
 #include "ios/web/web_sub_thread.h"
 
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
 #include "base/threading/thread_restrictions.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/web_thread_delegate.h"
 #include "ios/web/web_thread_impl.h"
 #include "net/url_request/url_fetcher.h"
 
 namespace web {
 
-WebSubThread::WebSubThread(WebThread::ID identifier)
-    : WebThreadImpl(identifier) {}
+namespace {
+WebThreadDelegate* g_io_thread_delegate = nullptr;
+}  // namespace
 
-WebSubThread::WebSubThread(WebThread::ID identifier,
-                           base::MessageLoop* message_loop)
-    : WebThreadImpl(identifier, message_loop) {}
+// static
+void WebThread::SetIOThreadDelegate(WebThreadDelegate* delegate) {
+  // |delegate| can only be set/unset while WebThread::IO isn't up.
+  DCHECK(!WebThread::IsThreadInitialized(WebThread::IO));
+  // and it cannot be set twice.
+  DCHECK(!g_io_thread_delegate || !delegate);
+
+  g_io_thread_delegate = delegate;
+}
+
+WebSubThread::WebSubThread(WebThread::ID identifier)
+    : base::Thread(WebThreadImpl::GetThreadName(identifier)),
+      identifier_(identifier) {
+  // Not bound to creation thread.
+  DETACH_FROM_THREAD(web_thread_checker_);
+}
 
 WebSubThread::~WebSubThread() {
   Stop();
 }
 
-void WebSubThread::Init() {
-  WebThreadImpl::Init();
+void WebSubThread::RegisterAsWebThread() {
+  DCHECK(IsRunning());
 
-  if (WebThread::CurrentlyOn(WebThread::IO)) {
-    // Though this thread is called the "IO" thread, it actually just routes
-    // messages around; it shouldn't be allowed to perform any blocking disk
-    // I/O.
+  DCHECK(!web_thread_);
+  web_thread_.reset(new WebThreadImpl(identifier_, task_runner()));
+
+  // Unretained(this) is safe as |this| outlives its underlying thread.
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&WebSubThread::CompleteInitializationOnWebThread,
+                     Unretained(this)));
+}
+
+void WebSubThread::AllowBlockingForTesting() {
+  DCHECK(!IsRunning());
+  is_blocking_allowed_for_testing_ = true;
+}
+
+void WebSubThread::Init() {
+  DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
+
+  if (!is_blocking_allowed_for_testing_) {
     base::DisallowUnresponsiveTasks();
   }
 }
 
-void WebSubThread::CleanUp() {
-  if (WebThread::CurrentlyOn(WebThread::IO))
-    IOThreadPreCleanUp();
+void WebSubThread::Run(base::RunLoop* run_loop) {
+  DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
 
-  WebThreadImpl::CleanUp();
+  switch (identifier_) {
+    case WebThread::UI:
+      // The main thread is usually promoted as the UI thread and doesn't go
+      // through Run() but some tests do run a separate UI thread.
+      UIThreadRun(run_loop);
+      break;
+    case WebThread::IO:
+      IOThreadRun(run_loop);
+      return;
+    case WebThread::ID_COUNT:
+      NOTREACHED();
+      break;
+  }
 }
 
-void WebSubThread::IOThreadPreCleanUp() {
+void WebSubThread::CleanUp() {
+  DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
+
+  // Run extra cleanup if this thread represents WebThread::IO.
+  if (WebThread::CurrentlyOn(WebThread::IO))
+    IOThreadCleanUp();
+
+  if (identifier_ == WebThread::IO && g_io_thread_delegate)
+    g_io_thread_delegate->CleanUp();
+
+  web_thread_.reset();
+}
+
+void WebSubThread::CompleteInitializationOnWebThread() {
+  DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
+
+  if (identifier_ == WebThread::IO && g_io_thread_delegate) {
+    // Allow blocking calls while initializing the IO thread.
+    base::ScopedAllowBlocking allow_blocking_for_init;
+    g_io_thread_delegate->Init();
+  }
+}
+
+void WebSubThread::UIThreadRun(base::RunLoop* run_loop) {
+  const int line_number = __LINE__;
+  Thread::Run(run_loop);
+  base::debug::Alias(&line_number);
+}
+
+void WebSubThread::IOThreadRun(base::RunLoop* run_loop) {
+  const int line_number = __LINE__;
+  Thread::Run(run_loop);
+  base::debug::Alias(&line_number);
+}
+
+void WebSubThread::IOThreadCleanUp() {
+  DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
+
   // Kill all things that might be holding onto
   // net::URLRequest/net::URLRequestContexts.
 
diff --git a/ios/web/web_sub_thread.h b/ios/web/web_sub_thread.h
index 9805f536..4d8a26f 100644
--- a/ios/web/web_sub_thread.h
+++ b/ios/web/web_sub_thread.h
@@ -6,26 +6,65 @@
 #define IOS_WEB_WEB_SUB_THREAD_H_
 
 #include "base/macros.h"
-#include "ios/web/web_thread_impl.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "ios/web/public/web_thread.h"
+
+namespace web {
+class WebThreadImpl;
+}
 
 namespace web {
 
-// This simple thread object is used for the specialized threads that are spun
-// up during startup.
-class WebSubThread : public WebThreadImpl {
+// A WebSubThread is a physical thread backing a WebThread.
+class WebSubThread : public base::Thread {
  public:
+  // Constructs a WebSubThread for |identifier|.
   explicit WebSubThread(WebThread::ID identifier);
-  WebSubThread(WebThread::ID identifier, base::MessageLoop* message_loop);
   ~WebSubThread() override;
 
+  // Registers this thread to represent |identifier_| in the web_thread.h
+  // API. This thread must already be running when this is called. This can only
+  // be called once per WebSubThread instance.
+  void RegisterAsWebThread();
+
+  // Ideally there wouldn't be a special blanket allowance to block the
+  // WebThreads in tests but TestWebThreadImpl previously bypassed
+  // WebSubThread and hence wasn't subject to ThreadRestrictions...
+  // Flipping that around in favor of explicit scoped allowances would be
+  // preferable but a non-trivial amount of work. Can only be called before
+  // starting this WebSubThread.
+  void AllowBlockingForTesting();
+
  protected:
   void Init() override;
+  void Run(base::RunLoop* run_loop) override;
   void CleanUp() override;
 
  private:
-  // These methods encapsulate cleanup that needs to happen on the IO thread
-  // before the embedder's |CleanUp()| function is called.
-  void IOThreadPreCleanUp();
+  // Second Init() phase that must happen on this thread but can only happen
+  // after it's promoted to a WebThread in |RegisterAsWebThread()|.
+  void CompleteInitializationOnWebThread();
+
+  // These methods merely forwards to Thread::Run() but are useful to identify
+  // which WebThread this represents in stack traces.
+  void UIThreadRun(base::RunLoop* run_loop);
+  void IOThreadRun(base::RunLoop* run_loop);
+
+  // This method encapsulates cleanup that needs to happen on the IO thread.
+  void IOThreadCleanUp();
+
+  const WebThread::ID identifier_;
+
+  // WebThreads are not allowed to do file I/O nor wait on synchronization
+  // primitives except when explicitly allowed in tests.
+  bool is_blocking_allowed_for_testing_ = false;
+
+  // The WebThread registration for this |identifier_|, initialized in
+  // RegisterAsWebThread().
+  std::unique_ptr<WebThreadImpl> web_thread_;
+
+  THREAD_CHECKER(web_thread_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(WebSubThread);
 };
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc
index 2feb1e7..54c7348 100644
--- a/ios/web/web_thread_impl.cc
+++ b/ios/web/web_thread_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/atomicops.h"
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
@@ -17,6 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/task_executor.h"
+#include "base/time/time.h"
 #include "ios/web/public/web_task_traits.h"
 #include "ios/web/public/web_thread_delegate.h"
 
@@ -24,18 +26,6 @@
 
 namespace {
 
-// Friendly names for the well-known threads.
-const char* const g_web_thread_names[WebThread::ID_COUNT] = {
-    "Web_UIThread",                // UI
-    "Web_IOThread",                // IO
-};
-
-static const char* GetThreadName(WebThread::ID thread) {
-  if (WebThread::UI <= thread && thread < WebThread::ID_COUNT)
-    return g_web_thread_names[thread];
-  return "Unknown Thread";
-}
-
 // An implementation of SingleThreadTaskRunner to be used in conjunction
 // with WebThread.
 class WebThreadTaskRunner : public base::SingleThreadTaskRunner {
@@ -88,17 +78,12 @@
 enum WebThreadState {
   // WebThread::ID does not exist.
   UNINITIALIZED = 0,
-  // WebThread::ID is associated with a WebThreadImpl instance but the
-  // underlying thread hasn't started yet.
-  INITIALIZED,
   // WebThread::ID is associated to a TaskRunner and is accepting tasks.
   RUNNING,
   // WebThread::ID no longer accepts tasks.
   SHUTDOWN,
 };
 
-using WebThreadDelegateAtomicPtr = base::subtle::AtomicWord;
-
 struct WebThreadGlobals {
   WebThreadGlobals() {
   }
@@ -114,11 +99,6 @@
 
   // This array is protected by |lock|. Holds the state of each WebThread::ID.
   WebThreadState states[WebThread::ID_COUNT] GUARDED_BY(lock) = {};
-
-  // Only atomic operations are used on this pointer. The delegate isn't owned
-  // by WebThreadGlobals, rather by whoever calls
-  // WebThread::SetIOThreadDelegate.
-  WebThreadDelegateAtomicPtr io_thread_delegate;
 };
 
 base::LazyInstance<WebThreadGlobals>::Leaky g_globals =
@@ -234,186 +214,55 @@
 
 }  // namespace
 
-WebThreadImpl::WebThreadImpl(ID identifier)
-    : Thread(GetThreadName(identifier)), identifier_(identifier) {
-  Initialize();
-}
+WebThreadImpl::WebThreadImpl(
+    ID identifier,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : identifier_(identifier) {
+  DCHECK(task_runner);
 
-WebThreadImpl::WebThreadImpl(ID identifier, base::MessageLoop* message_loop)
-    : Thread(GetThreadName(identifier)), identifier_(identifier) {
-  SetMessageLoop(message_loop);
-  Initialize();
-
-  // If constructed with an explicit message loop, this is a fake
-  // WebThread which runs on the current thread.
   WebThreadGlobals& globals = g_globals.Get();
+
   base::AutoLock lock(globals.lock);
-
-  DCHECK(!globals.task_runners[identifier_]);
-  globals.task_runners[identifier_] = this->task_runner();
-
-  DCHECK_EQ(globals.states[identifier_], WebThreadState::INITIALIZED);
-  globals.states[identifier_] = WebThreadState::RUNNING;
-}
-
-void WebThreadImpl::Init() {
-  WebThreadGlobals& globals = g_globals.Get();
-
-#if DCHECK_IS_ON()
-  {
-    base::AutoLock lock(globals.lock);
-    // |globals| should already have been initialized for |identifier_| in
-    // WebThreadImpl::StartWithOptions(). If this isn't the case it's likely
-    // because this WebThreadImpl's owner incorrectly used Thread::Start.*()
-    // instead of WebThreadImpl::Start.*().
-    DCHECK_EQ(globals.states[identifier_], WebThreadState::RUNNING);
-    DCHECK(globals.task_runners[identifier_]);
-    DCHECK(globals.task_runners[identifier_]->RunsTasksInCurrentSequence());
-  }
-#endif  // DCHECK_IS_ON()
-
-  if (identifier_ == WebThread::IO) {
-    WebThreadDelegateAtomicPtr delegate =
-        base::subtle::NoBarrier_Load(&globals.io_thread_delegate);
-    if (delegate)
-      reinterpret_cast<WebThreadDelegate*>(delegate)->Init();
-  }
-}
-
-NOINLINE void WebThreadImpl::UIThreadRun(base::RunLoop* run_loop) {
-  volatile int line_number = __LINE__;
-  Thread::Run(run_loop);
-  CHECK_GT(line_number, 0);
-}
-
-NOINLINE void WebThreadImpl::IOThreadRun(base::RunLoop* run_loop) {
-  volatile int line_number = __LINE__;
-  Thread::Run(run_loop);
-  CHECK_GT(line_number, 0);
-}
-
-bool WebThreadImpl::Start() {
-  return StartWithOptions(base::Thread::Options());
-}
-
-bool WebThreadImpl::StartWithOptions(const Options& options) {
-  WebThreadGlobals& globals = g_globals.Get();
-
-  // Holding the lock is necessary when kicking off the thread to ensure
-  // |states| and |task_runners| are updated before it gets to query them.
-  base::AutoLock lock(globals.lock);
-
-  bool result = Thread::StartWithOptions(options);
-
-  // Although the thread is starting asynchronously, the MessageLoop is already
-  // ready to accept tasks and as such this BrowserThreadImpl is considered as
-  // "running".
   DCHECK_GE(identifier_, 0);
   DCHECK_LT(identifier_, ID_COUNT);
-  DCHECK(!globals.task_runners[identifier_]);
-  globals.task_runners[identifier_] = this->task_runner();
-  DCHECK(globals.task_runners[identifier_]);
 
-  DCHECK_EQ(globals.states[identifier_], WebThreadState::INITIALIZED);
+  DCHECK_EQ(globals.states[identifier_], WebThreadState::UNINITIALIZED);
   globals.states[identifier_] = WebThreadState::RUNNING;
 
-  return result;
+  DCHECK(!globals.task_runners[identifier_]);
+  globals.task_runners[identifier_] = std::move(task_runner);
 }
 
-bool WebThreadImpl::StartAndWaitForTesting() {
-  if (!Start())
-    return false;
-  WaitUntilThreadStarted();
-  return true;
-}
-
-void WebThreadImpl::Run(base::RunLoop* run_loop) {
-  WebThread::ID thread_id = ID_COUNT;
-  if (!GetCurrentThreadIdentifier(&thread_id))
-    return Thread::Run(run_loop);
-
-  switch (thread_id) {
-    case WebThread::UI:
-      return UIThreadRun(run_loop);
-    case WebThread::IO:
-      return IOThreadRun(run_loop);
-    case WebThread::ID_COUNT:
-      CHECK(false);  // This shouldn't actually be reached!
-      break;
-  }
-  Thread::Run(run_loop);
-}
-
-void WebThreadImpl::CleanUp() {
+WebThreadImpl::~WebThreadImpl() {
   WebThreadGlobals& globals = g_globals.Get();
-
-  if (identifier_ == WebThread::IO) {
-    WebThreadDelegateAtomicPtr delegate =
-        base::subtle::NoBarrier_Load(&globals.io_thread_delegate);
-    if (delegate)
-      reinterpret_cast<WebThreadDelegate*>(delegate)->CleanUp();
-  }
-
-  // Change the state to SHUTDOWN so that PostTaskHelper stops accepting tasks
-  // for this thread. Do not clear globals.task_runners[identifier_] so that
-  // WebThread::CurrentlyOn() works from the MessageLoop's
-  // DestructionObservers.
   base::AutoLock lock(globals.lock);
+
   DCHECK_EQ(globals.states[identifier_], WebThreadState::RUNNING);
   globals.states[identifier_] = WebThreadState::SHUTDOWN;
 }
 
-void WebThreadImpl::Initialize() {
-  WebThreadGlobals& globals = g_globals.Get();
-
-  base::AutoLock lock(globals.lock);
-  DCHECK_GE(identifier_, 0);
-  DCHECK_LT(identifier_, ID_COUNT);
-  DCHECK_EQ(globals.states[identifier_], WebThreadState::UNINITIALIZED);
-  DCHECK(globals.task_runners[identifier_] == nullptr);
-  globals.states[identifier_] = WebThreadState::INITIALIZED;
-}
-
 // static
 void WebThreadImpl::ResetGlobalsForTesting(WebThread::ID identifier) {
   WebThreadGlobals& globals = g_globals.Get();
+
   base::AutoLock lock(globals.lock);
   DCHECK_EQ(globals.states[identifier], WebThreadState::SHUTDOWN);
   globals.states[identifier] = WebThreadState::UNINITIALIZED;
   globals.task_runners[identifier] = nullptr;
-  if (identifier == WebThread::IO)
-    SetIOThreadDelegate(nullptr);
 }
 
-WebThreadImpl::~WebThreadImpl() {
-  // All Thread subclasses must call Stop() in the destructor. This is
-  // doubly important here as various bits of code check they are on
-  // the right WebThread.
-  Stop();
+// Friendly names for the well-known threads.
 
-  WebThreadGlobals& globals = g_globals.Get();
-  base::AutoLock lock(globals.lock);
-  // This thread should have gone through Cleanup() as part of Stop() and be in
-  // the SHUTDOWN state already (unless it uses an externally provided
-  // MessageLoop instead of a real underlying thread and thus doesn't go through
-  // Cleanup()).
-  if (using_external_message_loop()) {
-    DCHECK_EQ(globals.states[identifier_], WebThreadState::RUNNING);
-    globals.states[identifier_] = WebThreadState::SHUTDOWN;
-  } else {
-    DCHECK_EQ(globals.states[identifier_], WebThreadState::SHUTDOWN);
-  }
-  globals.task_runners[identifier_] = nullptr;
-#if DCHECK_IS_ON()
-  // Double check that the threads are ordered correctly in the enumeration.
-  for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
-    DCHECK(globals.states[i] == WebThreadState::SHUTDOWN ||
-           globals.states[i] == WebThreadState::UNINITIALIZED)
-        << "Threads must be listed in the reverse order that they die";
-    DCHECK(!globals.task_runners[i])
-        << "Threads must be listed in the reverse order that they die";
-  }
-#endif  // DCHECK_IS_ON()
+// static
+const char* WebThreadImpl::GetThreadName(WebThread::ID thread) {
+  static const char* const kWebThreadNames[WebThread::ID_COUNT] = {
+      "Web_UIThread",  // UI
+      "Web_IOThread",  // IO
+  };
+
+  if (WebThread::UI <= thread && thread < WebThread::ID_COUNT)
+    return kWebThreadNames[thread];
+  return "Unknown Thread";
 }
 
 // static
@@ -425,8 +274,7 @@
   base::AutoLock lock(globals.lock);
   DCHECK_GE(identifier, 0);
   DCHECK_LT(identifier, ID_COUNT);
-  return globals.states[identifier] == WebThreadState::INITIALIZED ||
-         globals.states[identifier] == WebThreadState::RUNNING;
+  return globals.states[identifier] == WebThreadState::RUNNING;
 }
 
 // static
@@ -446,7 +294,7 @@
     actual_name = "Unknown Thread";
 
   std::string result = "Must be called on ";
-  result += GetThreadName(expected);
+  result += WebThreadImpl::GetThreadName(expected);
   result += "; actually called on ";
   result += actual_name;
   result += ".";
@@ -478,19 +326,6 @@
 }
 
 // static
-void WebThread::SetIOThreadDelegate(WebThreadDelegate* delegate) {
-  using base::subtle::AtomicWord;
-  WebThreadGlobals& globals = g_globals.Get();
-  WebThreadDelegateAtomicPtr old_delegate =
-      base::subtle::NoBarrier_AtomicExchange(
-          &globals.io_thread_delegate,
-          reinterpret_cast<WebThreadDelegateAtomicPtr>(delegate));
-
-  // This catches registration when previously registered.
-  DCHECK(!delegate || !old_delegate);
-}
-
-// static
 void WebThreadImpl::CreateTaskExecutor() {
   DCHECK(!g_web_thread_task_executor);
   g_web_thread_task_executor = new WebThreadTaskExecutor();
diff --git a/ios/web/web_thread_impl.h b/ios/web/web_thread_impl.h
index e695139d..b0a2c61 100644
--- a/ios/web/web_thread_impl.h
+++ b/ios/web/web_thread_impl.h
@@ -6,28 +6,30 @@
 #define IOS_WEB_WEB_THREAD_IMPL_H_
 
 #include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/threading/thread.h"
 #include "ios/web/public/web_thread.h"
 
 namespace web {
 
-class WebTestSuiteListener;
+class TestWebThread;
+class WebMainLoop;
+class WebSubThread;
 
-class WebThreadImpl : public WebThread, public base::Thread {
+// WebThreadImpl is a scoped object which maps a SingleThreadTaskRunner to a
+// WebThread::ID. On ~WebThreadImpl() that ID enters a SHUTDOWN state
+// (in which WebThread::IsThreadInitialized() returns false) but the mapping
+// isn't undone to avoid shutdown races (the task runner is free to stop
+// accepting tasks however).
+//
+// Very few users should use this directly. To mock WebThreads, tests should
+// use TestWebThreadBundle instead.
+class WebThreadImpl : public WebThread {
  public:
-  // Construct a WebThreadImpl with the supplied identifier.  It is an error
-  // to construct a WebThreadImpl that already exists.
-  explicit WebThreadImpl(WebThread::ID identifier);
+  ~WebThreadImpl();
 
-  // Special constructor for the main (UI) thread and unittests. If a
-  // |message_loop| is provied, we use a dummy thread here since the main
-  // thread already exists.
-  WebThreadImpl(WebThread::ID identifier, base::MessageLoop* message_loop);
-  ~WebThreadImpl() override;
-
-  bool Start();
-  bool StartWithOptions(const Options& options);
-  bool StartAndWaitForTesting();
+  // Returns the thread name for |identifier|.
+  static const char* GetThreadName(WebThread::ID identifier);
 
   // Creates and registers a TaskExecutor that facilitates posting tasks to a
   // WebThread via //base/task/post_task.h.
@@ -46,29 +48,19 @@
   // Also unregisters and deletes the TaskExecutor.
   static void ResetGlobalsForTesting(WebThread::ID identifier);
 
- protected:
-  void Init() override;
-  void Run(base::RunLoop* run_loop) override;
-  void CleanUp() override;
-
  private:
-  // This class implements all the functionality of the public WebThread
-  // functions, but state is stored in the WebThreadImpl to keep
-  // the API cleaner. Therefore make WebThread a friend class.
-  friend class WebThread;
+  // Restrict instantiation to WebSubThread as it performs important
+  // initialization that shouldn't be bypassed (except by WebMainLoop for
+  // the main thread).
+  friend class WebSubThread;
+  friend class WebMainLoop;
+  // TestWebThread is also allowed to construct this when instantiating fake
+  // threads.
+  friend class TestWebThread;
 
-  // The following are unique function names that makes it possible to tell
-  // the thread id from the callstack alone in crash dumps.
-  void UIThreadRun(base::RunLoop* run_loop);
-  void IOThreadRun(base::RunLoop* run_loop);
-
-  // Common initialization code for the constructors.
-  void Initialize();
-
-  // For testing.
-  friend class TestWebThreadBundle;
-  friend class TestWebThreadBundleImpl;
-  friend class WebTestSuiteListener;
+  // Binds |identifier| to |task_runner| for the web_thread.h API.
+  WebThreadImpl(WebThread::ID identifier,
+                scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // The identifier of this thread.  Only one thread can exist with a given
   // identifier at a given time.
diff --git a/mash/BUILD.gn b/mash/BUILD.gn
index b9aa26a..d1773fbf 100644
--- a/mash/BUILD.gn
+++ b/mash/BUILD.gn
@@ -13,7 +13,6 @@
   testonly = true
 
   deps = [
-    ":mash_catalog",
     "//components/services/leveldb",
     "//mash/catalog_viewer",
     "//mash/example",
@@ -36,16 +35,14 @@
   standalone_services = [
     "//components/services/leveldb:manifest",
     "//mash/catalog_viewer:manifest",
+    "//mash/example/views_examples:manifest",
+    "//mash/example/window_type_launcher:manifest",
     "//mash/session:manifest",
     "//mash/task_viewer:manifest",
     "//services/ws/ime/test_ime_driver:manifest",
     "//services/viz:manifest",
   ]
 
-  executable_overrides = [ "content_packaged_services:@EXE_DIR/chrome" ]
-
-  catalog_deps = [ "//mash/example:catalog" ]
-
   if (is_chromeos) {
     standalone_services += [
       "//ash:manifest",
@@ -65,13 +62,8 @@
   }
 }
 
-copy("mash_catalog") {
+catalog_cpp_source("mash_catalog_source") {
   testonly = true
-  sources = get_target_outputs(":catalog")
-  outputs = [
-    "$root_out_dir/mash_catalog.json",
-  ]
-  deps = [
-    ":catalog",
-  ]
+  catalog = ":catalog"
+  generated_function_name = "CreateMashCatalog"
 }
diff --git a/mash/example/BUILD.gn b/mash/example/BUILD.gn
index a210a3c..1e772aae 100644
--- a/mash/example/BUILD.gn
+++ b/mash/example/BUILD.gn
@@ -18,10 +18,3 @@
     deps += [ "//ash:ash_service" ]
   }
 }
-
-catalog("catalog") {
-  standalone_services = [
-    "//mash/example/views_examples:manifest",
-    "//mash/example/window_type_launcher:manifest",
-  ]
-}
diff --git a/mash/runner/BUILD.gn b/mash/runner/BUILD.gn
index 4cb3030c..a82a207 100644
--- a/mash/runner/BUILD.gn
+++ b/mash/runner/BUILD.gn
@@ -13,13 +13,10 @@
     "//base",
     "//base:i18n",
     "//base/test:test_support",
+    "//mash:mash_catalog_source",
     "//mojo/core/embedder",
     "//services/service_manager",
     "//services/service_manager/runner:init",
     "//services/service_manager/standalone",
   ]
-
-  data_deps = [
-    "//mash:mash_catalog",
-  ]
 }
diff --git a/mash/runner/main.cc b/mash/runner/main.cc
index 68e56a3..e08d303 100644
--- a/mash/runner/main.cc
+++ b/mash/runner/main.cc
@@ -25,19 +25,13 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
+#include "mash/mash_catalog_source.h"
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/core/embedder/scoped_ipc_support.h"
 #include "services/service_manager/runner/init.h"
 #include "services/service_manager/standalone/context.h"
 #include "services/service_manager/switches.h"
 
-namespace {
-
-const base::FilePath::CharType kMashCatalogFilename[] =
-    FILE_PATH_LITERAL("mash_catalog.json");
-
-}  // namespace
-
 int main(int argc, char** argv) {
   base::CommandLine::Init(argc, argv);
 
@@ -54,19 +48,11 @@
 #endif
   base::PlatformThread::SetName("service_manager");
 
-  std::string catalog_contents;
-  base::FilePath exe_path;
-  base::PathService::Get(base::DIR_EXE, &exe_path);
-  base::FilePath catalog_path = exe_path.Append(kMashCatalogFilename);
-  bool result = base::ReadFileToString(catalog_path, &catalog_contents);
-  DCHECK(result);
-  std::unique_ptr<base::Value> manifest_value =
-      base::JSONReader::Read(catalog_contents);
-  DCHECK(manifest_value);
-
 #if defined(OS_WIN) && defined(COMPONENT_BUILD)
   // In Windows component builds, ensure that loaded service binaries always
   // search this exe's dir for DLLs.
+  base::FilePath exe_path;
+  base::PathService::Get(base::DIR_EXE, &exe_path);
   SetDllDirectory(exe_path.value().c_str());
 #endif
 
@@ -86,7 +72,7 @@
 
   base::test::ScopedTaskEnvironment scoped_task_environment;
   service_manager::Context service_manager_context(nullptr,
-                                                   std::move(manifest_value));
+                                                   CreateMashCatalog());
   base::RunLoop loop;
   scoped_task_environment.GetMainThreadTaskRunner()->PostTask(
       FROM_HERE,
diff --git a/media/capture/video/linux/camera_config_chromeos_unittest.cc b/media/capture/video/linux/camera_config_chromeos_unittest.cc
index 4610803..a5f236f 100644
--- a/media/capture/video/linux/camera_config_chromeos_unittest.cc
+++ b/media/capture/video/linux/camera_config_chromeos_unittest.cc
@@ -20,12 +20,11 @@
 }
 
 TEST(CameraConfigChromeOSTest, ParseSuccessfully) {
-  const char file_name[] = "fake_camera_characteristics.conf";
-  base::WriteFile(base::FilePath(file_name), kConfigFileContent,
-                  sizeof(kConfigFileContent));
+  base::FilePath conf_path;
+  ASSERT_TRUE(base::CreateTemporaryFile(&conf_path));
+  base::WriteFile(conf_path, kConfigFileContent, sizeof(kConfigFileContent));
 
-  std::string file_name_str(file_name);
-  CameraConfigChromeOS camera_config(file_name_str);
+  CameraConfigChromeOS camera_config(conf_path.value());
   EXPECT_EQ(VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT,
             camera_config.GetCameraFacing(std::string("/dev/video2"),
                                           std::string("04f2:b53a")));
diff --git a/media/gpu/windows/d3d11_cdm_proxy_unittest.cc b/media/gpu/windows/d3d11_cdm_proxy_unittest.cc
index 00140a8..f4887ece 100644
--- a/media/gpu/windows/d3d11_cdm_proxy_unittest.cc
+++ b/media/gpu/windows/d3d11_cdm_proxy_unittest.cc
@@ -145,47 +145,46 @@
             DoAll(SetComPointee<7>(device_mock_.Get()),
                   SetComPointeeAndReturnOk<9>(device_context_mock_.Get())));
 
-    ON_CALL(*device_mock_.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+    COM_ON_CALL(device_mock_, QueryInterface(IID_ID3D11VideoDevice, _))
         .WillByDefault(SetComPointeeAndReturnOk<1>(video_device_mock_.Get()));
 
-    ON_CALL(*device_mock_.Get(), QueryInterface(IID_ID3D11VideoDevice1, _))
+    COM_ON_CALL(device_mock_, QueryInterface(IID_ID3D11VideoDevice1, _))
         .WillByDefault(SetComPointeeAndReturnOk<1>(video_device1_mock_.Get()));
 
-    ON_CALL(*device_mock_.Get(), QueryInterface(IID_IDXGIDevice2, _))
+    COM_ON_CALL(device_mock_, QueryInterface(IID_IDXGIDevice2, _))
         .WillByDefault(SetComPointeeAndReturnOk<1>(dxgi_device_.Get()));
 
-    ON_CALL(*dxgi_device_.Get(), GetParent(IID_IDXGIAdapter3, _))
+    COM_ON_CALL(dxgi_device_, GetParent(IID_IDXGIAdapter3, _))
         .WillByDefault(SetComPointeeAndReturnOk<1>(dxgi_adapter_.Get()));
 
-    ON_CALL(*dxgi_adapter_.Get(),
-            RegisterHardwareContentProtectionTeardownStatusEvent(_, _))
+    COM_ON_CALL(dxgi_adapter_,
+                RegisterHardwareContentProtectionTeardownStatusEvent(_, _))
         .WillByDefault(DoAll(SaveArg<0>(&teardown_event_), Return(S_OK)));
 
-    ON_CALL(*device_context_mock_.Get(),
-            QueryInterface(IID_ID3D11VideoContext, _))
+    COM_ON_CALL(device_context_mock_, QueryInterface(IID_ID3D11VideoContext, _))
         .WillByDefault(SetComPointeeAndReturnOk<1>(video_context_mock_.Get()));
 
-    ON_CALL(*device_context_mock_.Get(),
-            QueryInterface(IID_ID3D11VideoContext1, _))
+    COM_ON_CALL(device_context_mock_,
+                QueryInterface(IID_ID3D11VideoContext1, _))
         .WillByDefault(SetComPointeeAndReturnOk<1>(video_context1_mock_.Get()));
 
-    ON_CALL(*video_device_mock_.Get(),
-            CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
-                                Pointee(D3D11_KEY_EXCHANGE_HW_PROTECTION), _))
+    COM_ON_CALL(
+        video_device_mock_,
+        CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
+                            Pointee(D3D11_KEY_EXCHANGE_HW_PROTECTION), _))
         .WillByDefault(SetComPointeeAndReturnOk<3>(crypto_session_mock_.Get()));
 
-    ON_CALL(
-        *video_device1_mock_.Get(),
-        GetCryptoSessionPrivateDataSize(Pointee(CRYPTO_TYPE_GUID), _, _, _, _))
+    COM_ON_CALL(video_device1_mock_, GetCryptoSessionPrivateDataSize(
+                                         Pointee(CRYPTO_TYPE_GUID), _, _, _, _))
         .WillByDefault(DoAll(SetArgPointee<3>(kPrivateInputSize),
                              SetArgPointee<4>(kPrivateOutputSize),
                              Return(S_OK)));
 
-    ON_CALL(*video_device_mock_.Get(), GetContentProtectionCaps(_, _, _))
+    COM_ON_CALL(video_device_mock_, GetContentProtectionCaps(_, _, _))
         .WillByDefault(
             DoAll(SetArgPointee<2>(content_protection_caps_), Return(S_OK)));
 
-    ON_CALL(*video_device_mock_.Get(), CheckCryptoKeyExchange(_, _, Lt(1u), _))
+    COM_ON_CALL(video_device_mock_, CheckCryptoKeyExchange(_, _, Lt(1u), _))
         .WillByDefault(DoAll(SetArgPointee<3>(D3D11_KEY_EXCHANGE_HW_PROTECTION),
                              Return(S_OK)));
   }
@@ -195,35 +194,35 @@
   void Initialize(CdmProxy::Client* client, CdmProxy::InitializeCB callback) {
     EXPECT_CALL(create_device_mock_,
                 Create(_, D3D_DRIVER_TYPE_HARDWARE, _, _, _, _, _, _, _, _));
-    EXPECT_CALL(*device_mock_.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+    COM_EXPECT_CALL(device_mock_, QueryInterface(IID_ID3D11VideoDevice, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(*device_mock_.Get(), QueryInterface(IID_IDXGIDevice2, _))
+    COM_EXPECT_CALL(device_mock_, QueryInterface(IID_IDXGIDevice2, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(*dxgi_device_.Get(), GetParent(IID_IDXGIAdapter3, _))
+    COM_EXPECT_CALL(dxgi_device_, GetParent(IID_IDXGIAdapter3, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(*dxgi_adapter_.Get(),
-                RegisterHardwareContentProtectionTeardownStatusEvent(_, _))
+    COM_EXPECT_CALL(dxgi_adapter_,
+                    RegisterHardwareContentProtectionTeardownStatusEvent(_, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(*device_mock_.Get(), QueryInterface(IID_ID3D11VideoDevice1, _))
+    COM_EXPECT_CALL(device_mock_, QueryInterface(IID_ID3D11VideoDevice1, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(*device_context_mock_.Get(),
-                QueryInterface(IID_ID3D11VideoContext, _))
+    COM_EXPECT_CALL(device_context_mock_,
+                    QueryInterface(IID_ID3D11VideoContext, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(*device_context_mock_.Get(),
-                QueryInterface(IID_ID3D11VideoContext1, _))
+    COM_EXPECT_CALL(device_context_mock_,
+                    QueryInterface(IID_ID3D11VideoContext1, _))
         .Times(AtLeast(1));
-    EXPECT_CALL(
-        *video_device_mock_.Get(),
+    COM_EXPECT_CALL(
+        video_device_mock_,
         CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
                             Pointee(D3D11_KEY_EXCHANGE_HW_PROTECTION), _));
-    EXPECT_CALL(
-        *video_device1_mock_.Get(),
+    COM_EXPECT_CALL(
+        video_device1_mock_,
         GetCryptoSessionPrivateDataSize(Pointee(CRYPTO_TYPE_GUID), _, _, _, _));
 
-    EXPECT_CALL(*video_device_mock_.Get(), GetContentProtectionCaps(_, _, _));
+    COM_EXPECT_CALL(video_device_mock_, GetContentProtectionCaps(_, _, _));
 
-    EXPECT_CALL(*video_device_mock_.Get(),
-                CheckCryptoKeyExchange(_, _, Lt(1u), _));
+    COM_EXPECT_CALL(video_device_mock_,
+                    CheckCryptoKeyExchange(_, _, Lt(1u), _));
 
     proxy_->Initialize(client, std::move(callback));
 
@@ -316,8 +315,8 @@
   EXPECT_CALL(callback_mock_,
               InitializeCallback(CdmProxy::Status::kFail, _, _));
 
-  EXPECT_CALL(*dxgi_adapter_.Get(),
-              RegisterHardwareContentProtectionTeardownStatusEvent(_, _))
+  COM_EXPECT_CALL(dxgi_adapter_,
+                  RegisterHardwareContentProtectionTeardownStatusEvent(_, _))
       .Times(AtLeast(1))
       .WillRepeatedly(Return(E_FAIL));
 
@@ -359,8 +358,7 @@
               InitializeCallback(CdmProxy::Status::kFail, _, _));
   // GUID is set to non-D3D11_KEY_EXCHANGE_HW_PROTECTION, which means no HW key
   // exchange.
-  EXPECT_CALL(*video_device_mock_.Get(),
-              CheckCryptoKeyExchange(_, _, Lt(1u), _))
+  COM_EXPECT_CALL(video_device_mock_, CheckCryptoKeyExchange(_, _, Lt(1u), _))
       .WillOnce(
           DoAll(SetArgPointee<3>(D3D11_CRYPTO_TYPE_AES128_CTR), Return(S_OK)));
 
@@ -532,11 +530,11 @@
            test_output_data.size());
   };
 
-  EXPECT_CALL(*video_context_mock_.Get(),
-              NegotiateCryptoSessionKeyExchange(
-                  _, sizeof(expected_key_exchange_data),
-                  MatchesKeyExchangeStructure(&expected_key_exchange_data,
-                                              input_structure_size)))
+  COM_EXPECT_CALL(video_context_mock_,
+                  NegotiateCryptoSessionKeyExchange(
+                      _, sizeof(expected_key_exchange_data),
+                      MatchesKeyExchangeStructure(&expected_key_exchange_data,
+                                                  input_structure_size)))
       .WillOnce(DoAll(WithArgs<2>(Invoke(set_test_output_data)), Return(S_OK)));
 
   proxy_->Process(kTestFunction, crypto_session_id, kAnyInput,
@@ -571,16 +569,16 @@
                                   CdmProxy::Status::kOk,
                                   Ne(crypto_session_id_from_initialize), _));
   auto media_crypto_session_mock = CreateD3D11Mock<D3D11CryptoSessionMock>();
-  EXPECT_CALL(*video_device_mock_.Get(),
-              CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
-                                  Pointee(CRYPTO_TYPE_GUID), _))
+  COM_EXPECT_CALL(video_device_mock_,
+                  CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
+                                      Pointee(CRYPTO_TYPE_GUID), _))
       .WillOnce(SetComPointeeAndReturnOk<3>(media_crypto_session_mock.Get()));
 
-  EXPECT_CALL(*video_context1_mock_.Get(), GetDataForNewHardwareKey(_, _, _, _))
+  COM_EXPECT_CALL(video_context1_mock_, GetDataForNewHardwareKey(_, _, _, _))
       .Times(0);
 
-  EXPECT_CALL(*video_context1_mock_.Get(),
-              CheckCryptoSessionStatus(media_crypto_session_mock.Get(), _))
+  COM_EXPECT_CALL(video_context1_mock_,
+                  CheckCryptoSessionStatus(media_crypto_session_mock.Get(), _))
       .WillOnce(DoAll(SetArgPointee<1>(D3D11_CRYPTO_SESSION_STATUS_OK),
                       Return(S_OK)));
   proxy_->CreateMediaCryptoSession(
@@ -619,21 +617,21 @@
                                   Ne(crypto_session_id_from_initialize), _));
 
   auto media_crypto_session_mock = CreateD3D11Mock<D3D11CryptoSessionMock>();
-  EXPECT_CALL(*video_device_mock_.Get(),
-              CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
-                                  Pointee(CRYPTO_TYPE_GUID), _))
+  COM_EXPECT_CALL(video_device_mock_,
+                  CreateCryptoSession(Pointee(CRYPTO_TYPE_GUID), _,
+                                      Pointee(CRYPTO_TYPE_GUID), _))
       .WillOnce(SetComPointeeAndReturnOk<3>(media_crypto_session_mock.Get()));
   // The size nor value here matter, so making non empty non zero vector.
   const std::vector<uint8_t> kAnyInput(16, 0xFF);
   const uint64_t kAnyOutputData = 23298u;
-  EXPECT_CALL(*video_context1_mock_.Get(),
-              GetDataForNewHardwareKey(media_crypto_session_mock.Get(),
-                                       kAnyInput.size(),
-                                       CastedToUint8Are(kAnyInput), _))
+  COM_EXPECT_CALL(video_context1_mock_,
+                  GetDataForNewHardwareKey(media_crypto_session_mock.Get(),
+                                           kAnyInput.size(),
+                                           CastedToUint8Are(kAnyInput), _))
       .WillOnce(DoAll(SetArgPointee<3>(kAnyOutputData), Return(S_OK)));
 
-  EXPECT_CALL(*video_context1_mock_.Get(),
-              CheckCryptoSessionStatus(media_crypto_session_mock.Get(), _))
+  COM_EXPECT_CALL(video_context1_mock_,
+                  CheckCryptoSessionStatus(media_crypto_session_mock.Get(), _))
       .WillOnce(DoAll(SetArgPointee<1>(D3D11_CRYPTO_SESSION_STATUS_OK),
                       Return(S_OK)));
   proxy_->CreateMediaCryptoSession(
@@ -674,9 +672,7 @@
                                           base::Unretained(&callback_mock_))));
   Mock::VerifyAndClearExpectations(&callback_mock_);
 
-  const std::vector<uint8_t> kAnyBlob = {
-      0x01, 0x4f, 0x83,
-  };
+  const std::vector<uint8_t> kAnyBlob = {0x01, 0x4f, 0x83};
 
   EXPECT_CALL(callback_mock_, SetKeyCallback(CdmProxy::Status::kOk));
   proxy_->SetKey(crypto_session_id_from_initialize, kAnyBlob,
diff --git a/media/gpu/windows/d3d11_decryptor_unittest.cc b/media/gpu/windows/d3d11_decryptor_unittest.cc
index 75b4041..134e9b5 100644
--- a/media/gpu/windows/d3d11_decryptor_unittest.cc
+++ b/media/gpu/windows/d3d11_decryptor_unittest.cc
@@ -172,11 +172,11 @@
         .WillRepeatedly(SetComPointee<0>(device_mock_.Get()));
 
     // The other components accessible (directly or indirectly) from the device.
-    EXPECT_CALL(*device_mock_.Get(), GetImmediateContext(_))
+    COM_EXPECT_CALL(device_mock_, GetImmediateContext(_))
         .Times(AtLeast(1))
         .WillRepeatedly(SetComPointee<0>(device_context_mock_.Get()));
-    EXPECT_CALL(*device_context_mock_.Get(),
-                QueryInterface(IID_ID3D11VideoContext, _))
+    COM_EXPECT_CALL(device_context_mock_,
+                    QueryInterface(IID_ID3D11VideoContext, _))
         .Times(AtLeast(1))
         .WillRepeatedly(SetComPointeeAndReturnOk<1>(video_context_mock_.Get()));
 
@@ -185,29 +185,29 @@
         .WillOnce(Return(*decrypt_context));
 
     // These return big enough size.
-    ON_CALL(*staging_buffer1_.Get(), GetDesc(_))
+    COM_ON_CALL(staging_buffer1_, GetDesc(_))
         .WillByDefault(SetBufferDescSize(20000));
-    ON_CALL(*staging_buffer2_.Get(), GetDesc(_))
+    COM_ON_CALL(staging_buffer2_, GetDesc(_))
         .WillByDefault(SetBufferDescSize(20000));
-    ON_CALL(*gpu_buffer_.Get(), GetDesc(_))
+    COM_ON_CALL(gpu_buffer_, GetDesc(_))
         .WillByDefault(SetBufferDescSize(20000));
 
     // It should be requesting for 2 staging buffers one for writing the data to
     // a GPU buffer and one for reading from the a GPU buffer.
-    EXPECT_CALL(*device_mock_.Get(),
-                CreateBuffer(BufferDescHas(D3D11_USAGE_STAGING, 0u,
-                                           D3D11_CPU_ACCESS_READ |
-                                               D3D11_CPU_ACCESS_WRITE),
-                             nullptr, _))
+    COM_EXPECT_CALL(device_mock_,
+                    CreateBuffer(BufferDescHas(D3D11_USAGE_STAGING, 0u,
+                                               D3D11_CPU_ACCESS_READ |
+                                                   D3D11_CPU_ACCESS_WRITE),
+                                 nullptr, _))
         .WillOnce(SetComPointeeAndReturnOk<2>(staging_buffer1_.Get()))
         .WillOnce(SetComPointeeAndReturnOk<2>(staging_buffer2_.Get()));
 
     // It should be requesting a GPU only accessible buffer to the decrypted
     // output.
-    EXPECT_CALL(*device_mock_.Get(),
-                CreateBuffer(BufferDescHas(D3D11_USAGE_DEFAULT,
-                                           D3D11_BIND_RENDER_TARGET, 0u),
-                             nullptr, _))
+    COM_EXPECT_CALL(device_mock_,
+                    CreateBuffer(BufferDescHas(D3D11_USAGE_DEFAULT,
+                                               D3D11_BIND_RENDER_TARGET, 0u),
+                                 nullptr, _))
         .WillOnce(SetComPointeeAndReturnOk<2>(gpu_buffer_.Get()));
   }
 
@@ -232,22 +232,22 @@
 
     // It should be requesting for a memory mapped buffer, from the staging
     // buffer, to pass the encrypted data to the GPU.
-    EXPECT_CALL(*device_context_mock_.Get(),
-                Map(staging_buffer1_.Get(), 0, D3D11_MAP_WRITE, _, _))
+    COM_EXPECT_CALL(device_context_mock_,
+                    Map(staging_buffer1_.Get(), 0, D3D11_MAP_WRITE, _, _))
         .WillOnce(
             DoAll(SetArgPointee<4>(staging_buffer1_subresource), Return(S_OK)));
-    EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer1_.Get(), 0));
+    COM_EXPECT_CALL(device_context_mock_, Unmap(staging_buffer1_.Get(), 0));
 
-    EXPECT_CALL(
-        *video_context_mock_.Get(),
+    COM_EXPECT_CALL(
+        video_context_mock_,
         DecryptionBlt(
             crypto_session_mock,
             reinterpret_cast<ID3D11Texture2D*>(staging_buffer1_.Get()),
             reinterpret_cast<ID3D11Texture2D*>(gpu_buffer_.Get()),
             NumEncryptedBytesAtBeginningGreaterOrEq(encrypted_input.size()),
             sizeof(kAnyKeyBlob), kAnyKeyBlob, _, _));
-    EXPECT_CALL(*device_context_mock_.Get(),
-                CopyResource(staging_buffer2_.Get(), gpu_buffer_.Get()));
+    COM_EXPECT_CALL(device_context_mock_,
+                    CopyResource(staging_buffer2_.Get(), gpu_buffer_.Get()));
 
     D3D11_MAPPED_SUBRESOURCE staging_buffer2_subresource = {};
 
@@ -261,11 +261,11 @@
 
     // Tt should be requesting for a memory mapped buffer, from the staging
     // buffer, to read the decrypted data out from the GPU buffer.
-    EXPECT_CALL(*device_context_mock_.Get(),
-                Map(staging_buffer2_.Get(), 0, D3D11_MAP_READ, _, _))
+    COM_EXPECT_CALL(device_context_mock_,
+                    Map(staging_buffer2_.Get(), 0, D3D11_MAP_READ, _, _))
         .WillOnce(
             DoAll(SetArgPointee<4>(staging_buffer2_subresource), Return(S_OK)));
-    EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer2_.Get(), 0));
+    COM_EXPECT_CALL(device_context_mock_, Unmap(staging_buffer2_.Get(), 0));
 
     CallbackMock callbacks;
     EXPECT_CALL(callbacks,
@@ -499,7 +499,7 @@
   Mock::VerifyAndClearExpectations(device_context_mock_.Get());
   Mock::VerifyAndClearExpectations(&mock_proxy_);
 
-  EXPECT_CALL(*crypto_session_mock.Get(), GetDevice(_))
+  COM_EXPECT_CALL(crypto_session_mock, GetDevice(_))
       .Times(AtLeast(1))
       .WillRepeatedly(SetComPointee<0>(device_mock_.Get()));
   EXPECT_CALL(mock_proxy_,
@@ -508,7 +508,7 @@
 
   // Buffers should not be (re)initialized on the next call to decrypt because
   // it's the same device as the previous call.
-  EXPECT_CALL(*device_mock_.Get(), CreateBuffer(_, _, _)).Times(0);
+  COM_EXPECT_CALL(device_mock_, CreateBuffer(_, _, _)).Times(0);
 
   // This calls Decrypt() so that the expectations above are triggered.
   ExpectSuccessfulDecryption(crypto_session_mock.Get(), kAnyInput, kAnyInput,
diff --git a/media/gpu/windows/d3d11_mocks.h b/media/gpu/windows/d3d11_mocks.h
index 69d70a48..6c4d01b 100644
--- a/media/gpu/windows/d3d11_mocks.h
+++ b/media/gpu/windows/d3d11_mocks.h
@@ -44,11 +44,17 @@
 #define MOCK_STDCALL_METHOD9(Name, Types) \
   MOCK_METHOD9_WITH_CALLTYPE(STDMETHODCALLTYPE, Name, Types)
 
+// Helper ON_CALL and EXPECT_CALL for Microsoft::WRL::ComPtr, e.g.
+//   COM_EXPECT_CALL(foo_, Bar());
+// where |foo_| is ComPtr<D3D11FooMock>.
+#define COM_ON_CALL(obj, call) ON_CALL(*obj.Get(), call)
+#define COM_EXPECT_CALL(obj, call) EXPECT_CALL(*obj.Get(), call)
+
 namespace media {
 
 // Use this action when using SetArgPointee with COM pointers.
 // e.g.
-// EXPECT_CALL(*device_mock_.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+// COM_EXPECT_CALL(device_mock_, QueryInterface(IID_ID3D11VideoDevice, _))
 //  .WillRepeatedly(DoAll(
 //     SetComPointee<1>(video_device_mock_.Get()), Return(S_OK)));
 ACTION_TEMPLATE(SetComPointee,
@@ -60,7 +66,7 @@
 
 // Same as above, but returns S_OK for convenience.
 // e.g.
-// EXPECT_CALL(*device_mock_.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+// COM_EXPECT_CALL(device_mock_, QueryInterface(IID_ID3D11VideoDevice, _))
 //  .WillRepeatedly(SetComPointeeAndReturnOk<1>(video_device_mock_.Get()));
 ACTION_TEMPLATE(SetComPointeeAndReturnOk,
                 HAS_1_TEMPLATE_PARAMS(int, k),
diff --git a/media/video/gpu_video_accelerator_factories.h b/media/video/gpu_video_accelerator_factories.h
index 63b8f37..a4328d37 100644
--- a/media/video/gpu_video_accelerator_factories.h
+++ b/media/video/gpu_video_accelerator_factories.h
@@ -81,6 +81,8 @@
 
   // Return true if |config| is potentially supported by a decoder created with
   // CreateVideoDecoder().
+  //
+  // May be called on any thread.
   virtual bool IsDecoderConfigSupported(const VideoDecoderConfig& config) = 0;
 
   virtual std::unique_ptr<media::VideoDecoder> CreateVideoDecoder(
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index 03e3747c1..7dbcc87 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -100,7 +100,7 @@
     case __NR_stat:  // EPERM not a valid errno.
     case __NR_symlink:
     case __NR_unlink:
-#if !defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#if !(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
     case __NR_uselib:  // Neither EPERM, nor ENOENT are valid errno.
 #endif
     case __NR_ustat:   // Same as above. Deprecated.
@@ -483,7 +483,7 @@
 // Big multiplexing system call for sockets.
 bool SyscallSets::IsSocketCall(int sysno) {
   switch (sysno) {
-#if !defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#if !(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
     case __NR_socketcall:
       return true;
 #endif
@@ -881,7 +881,7 @@
 // Big system V multiplexing system call.
 bool SyscallSets::IsSystemVIpc(int sysno) {
   switch (sysno) {
-#if !defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#if !(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
     case __NR_ipc:
       return true;
 #endif
@@ -1090,7 +1090,7 @@
 bool SyscallSets::IsMipsMisc(int sysno) {
   switch (sysno) {
     case __NR_sysmips:
-#if !defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#if !(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
     case __NR_unused150:
 #endif
       return true;
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 575bcab..f6012237 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -223,6 +223,7 @@
   service_manifest("standalone_unittest_manifest") {
     name = "audio_unittests"
     source = "test/service_unittest_manifest.json"
+    generated_namespace = "standalone_audio_unittest"
   }
 
   catalog("standalone_unittest_catalog") {
diff --git a/services/catalog/BUILD.gn b/services/catalog/BUILD.gn
index c35b58a..07cfd90 100644
--- a/services/catalog/BUILD.gn
+++ b/services/catalog/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 group("catalog") {
@@ -31,7 +30,6 @@
     "entry_cache.h",
     "instance.cc",
     "instance.h",
-    "manifest_provider.h",
     "service_options.h",
   ]
 
@@ -55,24 +53,3 @@
 
   defines = [ "IS_CATALOG_IMPL" ]
 }
-
-service_manifest("manifest") {
-  name = "catalog"
-  source = "manifest.json"
-}
-
-source_set("unittests") {
-  testonly = true
-  sources = [
-    "entry_unittest.cc",
-  ]
-  data = [
-    "//services/catalog/test_data/",
-  ]
-  deps = [
-    ":lib",
-    "//base",
-    "//services/service_manager/public/cpp",
-    "//testing/gtest",
-  ]
-}
diff --git a/services/catalog/catalog.cc b/services/catalog/catalog.cc
index 6931cf8..2d1d21ff 100644
--- a/services/catalog/catalog.cc
+++ b/services/catalog/catalog.cc
@@ -32,87 +32,11 @@
 
 namespace {
 
-const char kCatalogServicesKey[] = "services";
-const char kCatalogServiceEmbeddedKey[] = "embedded";
-const char kCatalogServiceExecutableKey[] = "executable";
-const char kCatalogServiceManifestKey[] = "manifest";
-
 std::vector<service_manager::Manifest>& GetDefaultManifests() {
   static base::NoDestructor<std::vector<service_manager::Manifest>> manifests;
   return *manifests;
 }
 
-void LoadCatalogManifestIntoCache(const base::Value* root, EntryCache* cache) {
-  DCHECK(root);
-  const base::DictionaryValue* catalog = nullptr;
-  if (!root->GetAsDictionary(&catalog)) {
-    LOG(ERROR) << "Catalog manifest is not a dictionary value.";
-    return;
-  }
-  DCHECK(catalog);
-
-  const base::DictionaryValue* services = nullptr;
-  if (!catalog->GetDictionary(kCatalogServicesKey, &services)) {
-    LOG(ERROR) << "Catalog manifest \"services\" is not a dictionary value.";
-    return;
-  }
-
-  for (base::DictionaryValue::Iterator it(*services); !it.IsAtEnd();
-       it.Advance()) {
-    const base::DictionaryValue* service_entry = nullptr;
-    if (!it.value().GetAsDictionary(&service_entry)) {
-      LOG(ERROR) << "Catalog service entry for \"" << it.key()
-                 << "\" is not a dictionary value.";
-      continue;
-    }
-
-    bool is_embedded = false;
-    service_entry->GetBoolean(kCatalogServiceEmbeddedKey, &is_embedded);
-
-    base::FilePath executable_path;
-    std::string executable_path_string;
-    if (service_entry->GetString(kCatalogServiceExecutableKey,
-                                 &executable_path_string)) {
-      base::FilePath exe_dir;
-      CHECK(base::PathService::Get(base::DIR_EXE, &exe_dir));
-#if defined(OS_WIN)
-      executable_path_string += ".exe";
-      base::ReplaceFirstSubstringAfterOffset(
-          &executable_path_string, 0, "@EXE_DIR",
-          base::UTF16ToUTF8(exe_dir.value()));
-      executable_path =
-          base::FilePath(base::UTF8ToUTF16(executable_path_string));
-#else
-      base::ReplaceFirstSubstringAfterOffset(
-          &executable_path_string, 0, "@EXE_DIR", exe_dir.value());
-      executable_path = base::FilePath(executable_path_string);
-#endif
-    }
-
-    const base::DictionaryValue* manifest = nullptr;
-    if (!service_entry->GetDictionary(kCatalogServiceManifestKey, &manifest)) {
-      LOG(ERROR) << "Catalog entry for \"" << it.key() << "\" has an invalid "
-                 << "\"manifest\" value.";
-      continue;
-    }
-
-    DCHECK(!(is_embedded && !executable_path.empty()));
-
-    if (is_embedded)
-      executable_path = base::CommandLine::ForCurrentProcess()->GetProgram();
-
-    auto entry = Entry::Deserialize(*manifest);
-    if (entry) {
-      if (!executable_path.empty())
-        entry->set_path(std::move(executable_path));
-      bool added = cache->AddRootEntry(std::move(entry));
-      DCHECK(added);
-    } else {
-      LOG(ERROR) << "Failed to read manifest entry for \"" << it.key() << "\".";
-    }
-  }
-}
-
 }  // namespace
 
 // Wraps state needed for servicing directory requests on a separate thread.
@@ -143,13 +67,8 @@
   DISALLOW_COPY_AND_ASSIGN(DirectoryThreadState);
 };
 
-Catalog::Catalog(std::unique_ptr<base::Value> catalog_contents,
-                 const std::vector<service_manager::Manifest>& manifests,
-                 ManifestProvider* service_manifest_provider)
-    : service_manifest_provider_(service_manifest_provider) {
-  if (catalog_contents) {
-    LoadCatalogManifestIntoCache(catalog_contents.get(), &system_cache_);
-  } else if (!manifests.empty()) {
+Catalog::Catalog(const std::vector<service_manager::Manifest>& manifests) {
+  if (!manifests.empty()) {
     for (const auto& manifest : manifests)
       system_cache_.AddRootEntryFromManifest(manifest);
   } else {
@@ -181,9 +100,8 @@
   if (it != instances_.end())
     return it->second.get();
 
-  auto result = instances_.emplace(
-      instance_group,
-      std::make_unique<Instance>(&system_cache_, service_manifest_provider_));
+  auto result = instances_.emplace(instance_group,
+                                   std::make_unique<Instance>(&system_cache_));
   return result.first->second.get();
 }
 
diff --git a/services/catalog/catalog.h b/services/catalog/catalog.h
index daa3a42..728dd5a 100644
--- a/services/catalog/catalog.h
+++ b/services/catalog/catalog.h
@@ -26,23 +26,18 @@
 
 namespace base {
 class SequencedTaskRunner;
-class Value;
 }
 
 namespace catalog {
 
 class Instance;
-class ManifestProvider;
 
 // Creates and owns an instance of the catalog. Exposes a ServicePtr that
 // can be passed to the service manager, potentially in a different process.
 class COMPONENT_EXPORT(CATALOG) Catalog : public service_manager::Service {
  public:
-  // Constructs a catalog over a set of Manifests and optionally a
-  // ManifestProvider for dynamic manifest lookup.
-  explicit Catalog(std::unique_ptr<base::Value> catalog_contents,
-                   const std::vector<service_manager::Manifest>& manifests,
-                   ManifestProvider* service_manifest_provider = nullptr);
+  // Constructs a catalog over a set of Manifests to use for lookup.
+  explicit Catalog(const std::vector<service_manager::Manifest>& manifests);
   ~Catalog() override;
 
   void BindServiceRequest(service_manager::mojom::ServiceRequest request);
@@ -79,7 +74,6 @@
       const service_manager::BindSourceInfo&>
       registry_;
 
-  ManifestProvider* service_manifest_provider_;
   EntryCache system_cache_;
   std::map<base::Token, std::unique_ptr<Instance>> instances_;
 
diff --git a/services/catalog/entry.cc b/services/catalog/entry.cc
index f3884de..c1d438d 100644
--- a/services/catalog/entry.cc
+++ b/services/catalog/entry.cc
@@ -5,113 +5,10 @@
 #include "services/catalog/entry.h"
 
 #include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "services/catalog/public/cpp/manifest_parsing_util.h"
 #include "services/catalog/store.h"
 #include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
 
 namespace catalog {
-namespace {
-
-#if defined(OS_WIN)
-const char kServiceExecutableExtension[] = ".service.exe";
-#else
-const char kServiceExecutableExtension[] = ".service";
-#endif
-
-bool ReadStringSet(const base::ListValue& list_value,
-                   std::set<std::string>* string_set) {
-  DCHECK(string_set);
-  for (const auto& value_value : list_value) {
-    std::string value;
-    if (!value_value.GetAsString(&value)) {
-      LOG(ERROR) << "Entry::Deserialize: list member must be a string";
-      return false;
-    }
-    string_set->insert(std::move(value));
-  }
-  return true;
-}
-
-bool ReadStringSetFromValue(const base::Value& value,
-                            std::set<std::string>* string_set) {
-  const base::ListValue* list_value = nullptr;
-  if (!value.GetAsList(&list_value)) {
-    LOG(ERROR) << "Entry::Deserialize: Value must be a list.";
-    return false;
-  }
-  return ReadStringSet(*list_value, string_set);
-}
-
-// If |key| refers to a dictionary value within |value|, |*out| is set to that
-// DictionaryValue. Returns true if either |key| is not present or the
-// corresponding value is a dictionary.
-bool GetDictionaryValue(const base::DictionaryValue& value,
-                        base::StringPiece key,
-                        const base::DictionaryValue** out) {
-  const base::Value* entry_value = nullptr;
-  return !value.Get(key, &entry_value) || entry_value->GetAsDictionary(out);
-}
-
-bool BuildInterfaceProviderSpec(
-    const base::DictionaryValue& value,
-    service_manager::InterfaceProviderSpec* interface_provider_specs) {
-  DCHECK(interface_provider_specs);
-  const base::DictionaryValue* provides_value = nullptr;
-  if (!GetDictionaryValue(value, Store::kInterfaceProviderSpecs_ProvidesKey,
-                          &provides_value)) {
-    LOG(ERROR) << "Entry::Deserialize: "
-               << Store::kInterfaceProviderSpecs_ProvidesKey
-               << " must be a dictionary.";
-    return false;
-  }
-  if (provides_value) {
-    base::DictionaryValue::Iterator it(*provides_value);
-    for(; !it.IsAtEnd(); it.Advance()) {
-      service_manager::InterfaceSet interfaces;
-      if (!ReadStringSetFromValue(it.value(), &interfaces)) {
-        LOG(ERROR) << "Entry::Deserialize: Invalid interface list in provided "
-                   << " capabilities dictionary";
-        return false;
-      }
-      interface_provider_specs->provides[it.key()] = std::move(interfaces);
-    }
-  }
-
-  const base::DictionaryValue* requires_value = nullptr;
-  if (!GetDictionaryValue(value, Store::kInterfaceProviderSpecs_RequiresKey,
-                          &requires_value)) {
-    LOG(ERROR) << "Entry::Deserialize: "
-               << Store::kInterfaceProviderSpecs_RequiresKey
-               << " must be a dictionary.";
-    return false;
-  }
-  if (requires_value) {
-    base::DictionaryValue::Iterator it(*requires_value);
-    for (; !it.IsAtEnd(); it.Advance()) {
-      service_manager::CapabilitySet capabilities;
-      const base::ListValue* entry_value = nullptr;
-      if (!it.value().GetAsList(&entry_value)) {
-        LOG(ERROR) << "Entry::Deserialize: "
-                   << Store::kInterfaceProviderSpecs_RequiresKey
-                   << " entry must be a list.";
-        return false;
-      }
-      if (!ReadStringSet(*entry_value, &capabilities)) {
-        LOG(ERROR) << "Entry::Deserialize: Invalid capabilities list in "
-                   << "requires dictionary.";
-        return false;
-      }
-
-      interface_provider_specs->requires[it.key()] = std::move(capabilities);
-    }
-  }
-  return true;
-}
-
-}  // namespace
 
 Entry::Entry() {}
 Entry::Entry(const std::string& name)
@@ -119,147 +16,6 @@
       display_name_(name) {}
 Entry::~Entry() {}
 
-// static
-std::unique_ptr<Entry> Entry::Deserialize(const base::Value& manifest_root) {
-  const base::DictionaryValue* dictionary_value = nullptr;
-  if (!manifest_root.GetAsDictionary(&dictionary_value))
-    return nullptr;
-  const base::DictionaryValue& value = *dictionary_value;
-
-  auto entry = std::make_unique<Entry>();
-
-  // Name.
-  std::string name;
-  if (!value.GetString(Store::kNameKey, &name)) {
-    LOG(ERROR) << "Entry::Deserialize: dictionary has no "
-               << Store::kNameKey << " key";
-    return nullptr;
-  }
-  if (name.empty()) {
-    LOG(ERROR) << "Entry::Deserialize: empty service name.";
-    return nullptr;
-  }
-  entry->set_name(std::move(name));
-
-  // By default we assume a standalone service executable. The catalog may
-  // override this layer based on configuration external to the service's own
-  // manifest.
-  base::FilePath service_exe_root;
-  CHECK(base::PathService::Get(base::DIR_ASSETS, &service_exe_root));
-  entry->set_path(service_exe_root.AppendASCII(entry->name() +
-                                               kServiceExecutableExtension));
-
-  // Human-readable name.
-  std::string display_name;
-  if (!value.GetString(Store::kDisplayNameKey, &display_name)) {
-    LOG(ERROR) << "Entry::Deserialize: dictionary has no "
-               << Store::kDisplayNameKey << " key";
-    return nullptr;
-  }
-  entry->set_display_name(std::move(display_name));
-
-  // Sandbox type, optional.
-  std::string sandbox_type;
-  if (value.GetString(Store::kSandboxTypeKey, &sandbox_type))
-    entry->set_sandbox_type(std::move(sandbox_type));
-
-  // Options, optional.
-  if (const base::Value* options = value.FindKey(Store::kOptionsKey)) {
-    ServiceOptions options_struct;
-
-    if (const base::Value* instance_sharing_value =
-            options->FindKey("instance_sharing")) {
-      const std::string& instance_sharing = instance_sharing_value->GetString();
-      if (instance_sharing == "none") {
-        options_struct.instance_sharing =
-            ServiceOptions::InstanceSharingType::NONE;
-      } else if (instance_sharing == "singleton") {
-        options_struct.instance_sharing =
-            ServiceOptions::InstanceSharingType::SINGLETON;
-      } else if (instance_sharing == "shared_instance_across_users" ||
-                 instance_sharing == "shared_across_instance_groups") {
-        options_struct.instance_sharing =
-            ServiceOptions::InstanceSharingType::SHARED_ACROSS_INSTANCE_GROUPS;
-      } else {
-        LOG(ERROR) << "Entry::Deserialize invalid instance sharing type: "
-                   << instance_sharing;
-      }
-    }
-
-    if (const base::Value* can_connect_to_instances_in_any_group =
-            options->FindKey("can_connect_to_other_services_as_any_user")) {
-      options_struct.can_connect_to_instances_in_any_group =
-          can_connect_to_instances_in_any_group->GetBool();
-    }
-
-    if (const base::Value*
-            can_connect_to_other_services_with_any_instance_name_value =
-                options->FindKey(
-                    "can_connect_to_other_services_with_any_instance_name")) {
-      options_struct.can_connect_to_other_services_with_any_instance_name =
-          can_connect_to_other_services_with_any_instance_name_value->GetBool();
-    }
-
-    if (const base::Value* can_create_other_service_instances_value =
-            options->FindKey("can_create_other_service_instances")) {
-      options_struct.can_create_other_service_instances =
-          can_create_other_service_instances_value->GetBool();
-    }
-
-    entry->AddOptions(std::move(options_struct));
-  }
-
-  // InterfaceProvider specs.
-  const base::DictionaryValue* interface_provider_specs = nullptr;
-  if (!value.GetDictionary(Store::kInterfaceProviderSpecsKey,
-                           &interface_provider_specs)) {
-    LOG(ERROR) << "Entry::Deserialize: dictionary has no "
-               << Store::kInterfaceProviderSpecsKey << " key";
-    return nullptr;
-  }
-
-  base::DictionaryValue::Iterator it(*interface_provider_specs);
-  for (; !it.IsAtEnd(); it.Advance()) {
-    const base::DictionaryValue* spec_value = nullptr;
-    if (!interface_provider_specs->GetDictionary(it.key(), &spec_value)) {
-      LOG(ERROR) << "Entry::Deserialize: value of InterfaceProvider map for "
-                 << "key: " << it.key() << " not a dictionary.";
-      return nullptr;
-    }
-
-    service_manager::InterfaceProviderSpec spec;
-    if (!BuildInterfaceProviderSpec(*spec_value, &spec)) {
-      LOG(ERROR) << "Entry::Deserialize: failed to build InterfaceProvider "
-                 << "spec for key: " << it.key();
-      return nullptr;
-    }
-    entry->AddInterfaceProviderSpec(it.key(), std::move(spec));
-  }
-
-  // Required files.
-  base::Optional<RequiredFileMap> required_files =
-      catalog::RetrieveRequiredFiles(value);
-  DCHECK(required_files);
-  for (auto& iter : *required_files) {
-    entry->AddRequiredFilePath(iter.first, std::move(iter.second));
-  }
-
-  const base::ListValue* services = nullptr;
-  if (value.GetList(Store::kServicesKey, &services)) {
-    for (size_t i = 0; i < services->GetSize(); ++i) {
-      const base::DictionaryValue* service = nullptr;
-      services->GetDictionary(i, &service);
-      std::unique_ptr<Entry> child = Entry::Deserialize(*service);
-      if (child) {
-        child->set_parent(entry.get());
-        entry->children().emplace_back(std::move(child));
-      }
-    }
-  }
-
-  return entry;
-}
-
 bool Entry::ProvidesCapability(const std::string& capability) const {
   auto it = interface_provider_specs_.find(
       service_manager::mojom::kServiceManager_ConnectorSpec);
diff --git a/services/catalog/entry.h b/services/catalog/entry.h
index 86a29e3..46de570 100644
--- a/services/catalog/entry.h
+++ b/services/catalog/entry.h
@@ -16,10 +16,6 @@
 #include "services/catalog/service_options.h"
 #include "services/service_manager/public/cpp/interface_provider_spec.h"
 
-namespace base {
-class Value;
-}
-
 namespace catalog {
 
 // Static information about a service package known to the Catalog.
@@ -29,8 +25,6 @@
   explicit Entry(const std::string& name);
   ~Entry();
 
-  static std::unique_ptr<Entry> Deserialize(const base::Value& manifest_root);
-
   bool ProvidesCapability(const std::string& capability) const;
 
   bool operator==(const Entry& other) const;
diff --git a/services/catalog/entry_unittest.cc b/services/catalog/entry_unittest.cc
deleted file mode 100644
index f89668b4..0000000
--- a/services/catalog/entry_unittest.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/catalog/entry.h"
-
-#include "base/files/file_path.h"
-#include "base/json/json_file_value_serializer.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace catalog {
-
-class EntryTest : public testing::Test {
- public:
-  EntryTest() {}
-  ~EntryTest() override {}
-
- protected:
-  std::unique_ptr<Entry> ReadEntry(const std::string& manifest,
-                                   std::unique_ptr<base::Value>* out_value) {
-    std::unique_ptr<base::Value> value = ReadManifest(manifest);
-    base::DictionaryValue* dictionary = nullptr;
-    CHECK(value->GetAsDictionary(&dictionary));
-    if (out_value)
-      *out_value = std::move(value);
-    return Entry::Deserialize(*dictionary);
-  }
-
-  std::unique_ptr<base::Value> ReadManifest(const std::string& manifest) {
-    base::FilePath manifest_path;
-    base::PathService::Get(base::DIR_SOURCE_ROOT, &manifest_path);
-    manifest_path =
-        manifest_path.AppendASCII("services/catalog/test_data/" + manifest);
-
-    JSONFileValueDeserializer deserializer(manifest_path);
-    int error = 0;
-    std::string message;
-    // TODO(beng): probably want to do more detailed error checking. This should
-    //             be done when figuring out if to unblock connection
-    //             completion.
-    return deserializer.Deserialize(&error, &message);
-  }
-
- private:
-  void SetUp() override {}
-  void TearDown() override {}
-
-  DISALLOW_COPY_AND_ASSIGN(EntryTest);
-};
-
-TEST_F(EntryTest, Simple) {
-  std::unique_ptr<Entry> entry = ReadEntry("simple", nullptr);
-  EXPECT_EQ("foo", entry->name());
-  EXPECT_EQ("Foo", entry->display_name());
-  EXPECT_EQ("none", entry->sandbox_type());
-}
-
-TEST_F(EntryTest, Instance) {
-  std::unique_ptr<Entry> entry = ReadEntry("instance", nullptr);
-  EXPECT_EQ("foo", entry->name());
-  EXPECT_EQ("Foo", entry->display_name());
-  EXPECT_EQ("", entry->sandbox_type());
-}
-
-TEST_F(EntryTest, Options) {
-  std::unique_ptr<Entry> entry = ReadEntry("options", nullptr);
-  EXPECT_EQ("foo", entry->name());
-  EXPECT_EQ("Foo", entry->display_name());
-
-  EXPECT_EQ(ServiceOptions::InstanceSharingType::SINGLETON,
-            entry->options().instance_sharing);
-  EXPECT_TRUE(entry->options().can_connect_to_instances_in_any_group);
-  EXPECT_TRUE(
-      entry->options().can_connect_to_other_services_with_any_instance_name);
-  EXPECT_TRUE(entry->options().can_create_other_service_instances);
-
-  EXPECT_EQ("", entry->sandbox_type());
-}
-
-TEST_F(EntryTest, ConnectionSpec) {
-  std::unique_ptr<Entry> entry = ReadEntry("connection_spec", nullptr);
-
-  EXPECT_EQ("foo", entry->name());
-  EXPECT_EQ("Foo", entry->display_name());
-  service_manager::InterfaceProviderSpec spec;
-  service_manager::CapabilitySet capabilities;
-  capabilities.insert("bar:bar");
-  spec.requires["bar"] = capabilities;
-  service_manager::InterfaceProviderSpecMap specs;
-  specs[service_manager::mojom::kServiceManager_ConnectorSpec] = spec;
-  EXPECT_EQ(specs, entry->interface_provider_specs());
-}
-
-TEST_F(EntryTest, RequiredFiles) {
-  std::unique_ptr<Entry> entry = ReadEntry("required_files", nullptr);
-  EXPECT_EQ("foo", entry->name());
-  EXPECT_EQ("Foo", entry->display_name());
-  auto required_files = entry->required_file_paths();
-  EXPECT_EQ(2U, required_files.size());
-  auto iter = required_files.find("all_platforms");
-  ASSERT_NE(required_files.end(), iter);
-  bool checked_platform_specific_file = false;
-#if defined(OS_WIN)
-  EXPECT_EQ(base::FilePath(L"/all/platforms/windows"), iter->second);
-  iter = required_files.find("windows_only");
-  ASSERT_NE(required_files.end(), iter);
-  EXPECT_EQ(base::FilePath(L"/windows/only"), iter->second);
-  checked_platform_specific_file = true;
-#elif defined(OS_FUCHSIA)
-  EXPECT_EQ(base::FilePath("/all/platforms/fuchsia"), iter->second);
-  iter = required_files.find("fuchsia_only");
-  ASSERT_NE(required_files.end(), iter);
-  EXPECT_EQ(base::FilePath("/fuchsia/only"), iter->second);
-  checked_platform_specific_file = true;
-#elif defined(OS_LINUX)
-  EXPECT_EQ(base::FilePath("/all/platforms/linux"), iter->second);
-  iter = required_files.find("linux_only");
-  ASSERT_NE(required_files.end(), iter);
-  EXPECT_EQ(base::FilePath("/linux/only"), iter->second);
-  checked_platform_specific_file = true;
-#elif defined(OS_MACOSX)
-  EXPECT_EQ(base::FilePath("/all/platforms/macosx"), iter->second);
-  iter = required_files.find("macosx_only");
-  ASSERT_NE(required_files.end(), iter);
-  EXPECT_EQ(base::FilePath("/macosx/only"), iter->second);
-  checked_platform_specific_file = true;
-#elif defined(OS_ANDROID)
-  EXPECT_EQ(base::FilePath("/all/platforms/android"), iter->second);
-  iter = required_files.find("android_only");
-  ASSERT_NE(required_files.end(), iter);
-  EXPECT_EQ(base::FilePath("/android/only"), iter->second);
-  checked_platform_specific_file = true;
-#endif
-  EXPECT_TRUE(checked_platform_specific_file);
-}
-
-TEST_F(EntryTest, Malformed) {
-  std::unique_ptr<base::Value> value = ReadManifest("malformed");
-  EXPECT_FALSE(value.get());
-}
-
-
-}  // namespace catalog
diff --git a/services/catalog/instance.cc b/services/catalog/instance.cc
index 7dcbb76..8cc1422 100644
--- a/services/catalog/instance.cc
+++ b/services/catalog/instance.cc
@@ -10,7 +10,6 @@
 #include "base/values.h"
 #include "services/catalog/entry.h"
 #include "services/catalog/entry_cache.h"
-#include "services/catalog/manifest_provider.h"
 
 namespace catalog {
 namespace {
@@ -24,12 +23,9 @@
 
 }  // namespace
 
-Instance::Instance(EntryCache* system_cache,
-                   ManifestProvider* service_manifest_provider)
-    : system_cache_(system_cache),
-      service_manifest_provider_(service_manifest_provider) {}
+Instance::Instance(EntryCache* system_cache) : system_cache_(system_cache) {}
 
-Instance::~Instance() {}
+Instance::~Instance() = default;
 
 void Instance::BindCatalog(mojom::CatalogRequest request) {
   catalog_bindings_.AddBinding(this, std::move(request));
@@ -41,25 +37,8 @@
   if (cached_entry)
     return cached_entry;
 
-  std::unique_ptr<base::Value> new_manifest;
-  if (service_manifest_provider_)
-    new_manifest = service_manifest_provider_->GetManifest(service_name);
-
-  if (!new_manifest) {
-    LOG(ERROR) << "Unable to locate service manifest for " << service_name;
-    return nullptr;
-  }
-
-  auto new_entry = Entry::Deserialize(*new_manifest);
-  if (!new_entry) {
-    LOG(ERROR) << "Malformed manifest for " << service_name;
-    return nullptr;
-  }
-
-  cached_entry = const_cast<const Entry*>(new_entry.get());
-  bool added = system_cache_->AddRootEntry(std::move(new_entry));
-  DCHECK(added);
-  return cached_entry;
+  LOG(ERROR) << "Unable to locate service manifest for " << service_name;
+  return nullptr;
 }
 
 void Instance::GetEntries(const base::Optional<std::vector<std::string>>& names,
diff --git a/services/catalog/instance.h b/services/catalog/instance.h
index ad7d05c..14faa9d3 100644
--- a/services/catalog/instance.h
+++ b/services/catalog/instance.h
@@ -17,14 +17,11 @@
 namespace catalog {
 
 class EntryCache;
-class ManifestProvider;
 
 class COMPONENT_EXPORT(CATALOG) Instance : public mojom::Catalog {
  public:
-  // Neither |system_cache| nor |service_manifest_provider| is owned.
-  // |service_manifest_provider| may be null
-  Instance(EntryCache* system_cache,
-           ManifestProvider* service_manifest_provider);
+  // |system_cache| is not owned.
+  explicit Instance(EntryCache* system_cache);
   ~Instance() override;
 
   void BindCatalog(mojom::CatalogRequest request);
@@ -46,10 +43,6 @@
   // TODO(beng): eventually add per-user applications.
   EntryCache* const system_cache_;
 
-  // A runtime interface the embedder can use to provide dynamic manifest data
-  // to be queried on-demand if something can't be found in |system_cache_|.
-  ManifestProvider* const service_manifest_provider_;
-
   DISALLOW_COPY_AND_ASSIGN(Instance);
 };
 
diff --git a/services/catalog/manifest.json b/services/catalog/manifest.json
deleted file mode 100644
index 0a5c2d2..0000000
--- a/services/catalog/manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "name": "catalog",
-  "display_name": "Application Resolver",
-  "options" : {
-    "instance_sharing" : "shared_instance_across_users"
-  },
-  "interface_provider_specs": {
-    // NOTE: This manifest is for documentation purposes only. Relevant
-    // capability spec is defined inline in the ServiceManager implementation.
-    //
-    // TODO(rockot): Fix this. We can bake this file into ServiceManager at
-    // build time or something. Same with service:service_manager.
-    "service_manager:connector": {
-      "provides": {
-        "directory": [ "filesystem.mojom.Directory" ],
-        "control": [ "catalog.mojom.CatalogControl" ]
-      }
-    }
-  }
-}
diff --git a/services/catalog/manifest_provider.h b/services/catalog/manifest_provider.h
deleted file mode 100644
index f1caa225..0000000
--- a/services/catalog/manifest_provider.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_CATALOG_MANIFEST_PROVIDER_H_
-#define SERVICES_CATALOG_MANIFEST_PROVIDER_H_
-
-#include <string>
-
-#include "base/component_export.h"
-
-namespace base {
-class Value;
-}
-
-namespace catalog {
-
-// An interface which can be implemented by a catalog embedder to override
-// manifest fetching behavior.
-class COMPONENT_EXPORT(CATALOG) ManifestProvider {
- public:
-  virtual ~ManifestProvider() {}
-
-  // Retrieves the raw contents of the manifest for application named |name|.
-  // Returns true if |name| is known and |*manifest_contents| is populated.
-  // returns false otherwise.
-  virtual std::unique_ptr<base::Value> GetManifest(const std::string& name) = 0;
-};
-
-}  // namespace catalog
-
-#endif  // SERVICES_CATALOG_MANIFEST_PROVIDER_H_
diff --git a/services/catalog/public/cpp/BUILD.gn b/services/catalog/public/cpp/BUILD.gn
index 7eb6bda..1b61a04 100644
--- a/services/catalog/public/cpp/BUILD.gn
+++ b/services/catalog/public/cpp/BUILD.gn
@@ -4,8 +4,6 @@
 
 source_set("cpp") {
   sources = [
-    "manifest_parsing_util.cc",
-    "manifest_parsing_util.h",
     "resource_loader.cc",
     "resource_loader.h",
   ]
diff --git a/services/catalog/public/cpp/manifest_parsing_util.cc b/services/catalog/public/cpp/manifest_parsing_util.cc
deleted file mode 100644
index 4a19ec6..0000000
--- a/services/catalog/public/cpp/manifest_parsing_util.cc
+++ /dev/null
@@ -1,111 +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 "services/catalog/public/cpp/manifest_parsing_util.h"
-
-#include "base/values.h"
-#include "build/build_config.h"
-#include "services/catalog/store.h"
-
-namespace catalog {
-
-namespace {
-
-bool IsValidPlatformName(const std::string& name) {
-  return name == Store::kRequiredFilesKey_PlatformValue_Windows ||
-         name == Store::kRequiredFilesKey_PlatformValue_Linux ||
-         name == Store::kRequiredFilesKey_PlatformValue_MacOSX ||
-         name == Store::kRequiredFilesKey_PlatformValue_Android ||
-         name == Store::kRequiredFilesKey_PlatformValue_Fuchsia;
-}
-
-bool IsCurrentPlatform(const std::string& name) {
-#if defined(OS_WIN)
-  return name == Store::kRequiredFilesKey_PlatformValue_Windows;
-#elif defined(OS_LINUX)
-  return name == Store::kRequiredFilesKey_PlatformValue_Linux;
-#elif defined(OS_MACOSX)
-  return name == Store::kRequiredFilesKey_PlatformValue_MacOSX;
-#elif defined(OS_ANDROID)
-  return name == Store::kRequiredFilesKey_PlatformValue_Android;
-#elif defined(OS_FUCHSIA)
-  return name == Store::kRequiredFilesKey_PlatformValue_Fuchsia;
-#else
-#error This architecture is not supported.
-#endif
-}
-
-}  // namespace
-
-base::Optional<RequiredFileMap> RetrieveRequiredFiles(
-    const base::Value& manifest_value) {
-  const base::DictionaryValue* manifest_dictionary = nullptr;
-  if (!manifest_value.GetAsDictionary(&manifest_dictionary)) {
-    DLOG(ERROR) << "Entry::Deserialize: manifest node is not a dictionary.";
-    return base::nullopt;
-  }
-
-  RequiredFileMap required_files;
-  if (!manifest_dictionary->HasKey(Store::kRequiredFilesKey))
-    return {required_files};
-
-  const base::DictionaryValue* required_files_value = nullptr;
-  if (!manifest_dictionary->GetDictionary(Store::kRequiredFilesKey,
-                                          &required_files_value)) {
-    DLOG(ERROR) << "Entry::Deserialize: RequiredFiles not a dictionary.";
-    return base::nullopt;
-  }
-
-  base::DictionaryValue::Iterator it(*required_files_value);
-  for (; !it.IsAtEnd(); it.Advance()) {
-    const std::string& entry_name = it.key();
-    const base::ListValue* all_platform_values = nullptr;
-    if (!it.value().GetAsList(&all_platform_values)) {
-      DLOG(ERROR) << "Entry::Deserialize: value of RequiredFiles for key: "
-                  << entry_name << " not a list.";
-      return base::nullopt;
-    }
-
-    for (size_t i = 0; i < all_platform_values->GetSize(); i++) {
-      const base::DictionaryValue* file_descriptor_value = nullptr;
-      if (!all_platform_values->GetDictionary(i, &file_descriptor_value)) {
-        DLOG(ERROR) << "Entry::Deserialize: value of entry at index " << i
-                    << " of RequiredFiles for key: " << entry_name
-                    << " not a dictionary.";
-        return base::nullopt;
-      }
-      std::string platform;
-      if (file_descriptor_value->GetString(Store::kRequiredFilesKey_PlatformKey,
-                                           &platform)) {
-        if (!IsValidPlatformName(platform)) {
-          DLOG(ERROR) << "Entry::Deserialize: value of platform for "
-                      << "required file entry entry is invalid " << platform;
-          return base::nullopt;
-        }
-      }
-      if (!IsCurrentPlatform(platform)) {
-        continue;
-      }
-      base::FilePath::StringType path;
-      if (!file_descriptor_value->GetString(Store::kRequiredFilesKey_PathKey,
-                                            &path)) {
-        DLOG(ERROR) << "Entry::Deserialize: value of RequiredFiles entry for "
-                    << "key: " << entry_name
-                    << " missing: " << Store::kRequiredFilesKey_PathKey
-                    << " value.";
-        return base::nullopt;
-      }
-      if (required_files.count(entry_name) > 0) {
-        DLOG(ERROR) << "Entry::Deserialize: value of RequiredFiles entry for "
-                    << "key: " << entry_name << " has more than one value for "
-                    << "platform: " << platform;
-        return base::nullopt;
-      }
-      required_files[entry_name] = base::FilePath(path);
-    }
-  }
-  return base::make_optional(std::move(required_files));
-}
-
-}  // namespace content
diff --git a/services/catalog/public/cpp/manifest_parsing_util.h b/services/catalog/public/cpp/manifest_parsing_util.h
deleted file mode 100644
index f76c156..0000000
--- a/services/catalog/public/cpp/manifest_parsing_util.h
+++ /dev/null
@@ -1,29 +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 SERVICES_CATALOG_PUBLIC_CPP_MANIFEST_PARSING_UTIL_H_
-#define SERVICES_CATALOG_PUBLIC_CPP_MANIFEST_PARSING_UTIL_H_
-
-#include <map>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/optional.h"
-
-namespace base {
-class Value;
-}
-
-// TODO(jcivelli): http://crbug.com/687250 Remove this file and inline
-//                 PopulateRequiredFiles() in Entry::Deserialize.
-namespace catalog {
-
-using RequiredFileMap = std::map<std::string, base::FilePath>;
-
-base::Optional<RequiredFileMap> RetrieveRequiredFiles(
-    const base::Value& manifest);
-
-}  // namespace content
-
-#endif  // SERVICES_CATALOG_PUBLIC_CPP_MANIFEST_PARSING_UTIL_H_
diff --git a/services/catalog/public/tools/catalog.cc.tmpl b/services/catalog/public/tools/catalog.cc.tmpl
index 06327c5..85ebc0c 100644
--- a/services/catalog/public/tools/catalog.cc.tmpl
+++ b/services/catalog/public/tools/catalog.cc.tmpl
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This is a generated file. Please see the "catalog_cpp_source" template in
-// src/services/catalog/public/tools/catalog.gni for more details.
+// This is a generated file. Please see the "service_manifest" template in
+// src/services/service_manager/public/service_manifest.gni for more details.
 
 #include "{{path}}.h"
 
@@ -13,8 +13,15 @@
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
+{%  for info in packaged_services %}
+#include "{{info.header}}"
+{%- endfor %}
+{%  for info in overlays %}
+#include "{{info.header}}"
+{%- endfor %}
 
-{%- macro generate_manifest_builder(manifest) -%}
+{%- macro generate_manifest_builder(manifest, packaged_services=[],
+                                    overlays=[]) -%}
 service_manager::ManifestBuilder()
     .WithServiceName("{{manifest['name']}}")
 {%-   if 'display_name' in manifest %}
@@ -102,21 +109,36 @@
     .PackageService(
         {{generate_manifest_builder(packaged_service_manifest)|indent(8)}})
 {%-  endfor %}
+{%-  for info in packaged_services %}
+    .PackageService({{info.namespace}}::GetManifest())
+{%-  endfor %}
     .Build()
+{%-  for info in overlays %}
+        .Amend({{info.namespace}}::GetManifest())
+{%-  endfor %}
 {%- endmacro %}
 
 {% for namespace in namespaces %}
 namespace {{namespace}} {
 {%- endfor %}
 
-const std::vector<service_manager::Manifest>& {{function_name}}() {
-  static base::NoDestructor<std::vector<service_manager::Manifest>> catalog{ {
-{%- for entry in catalog['services'].itervalues() %}
-      {{generate_manifest_builder(entry['manifest'])|indent(6)}}
-{%- if not loop.last %},{% endif %}
-{%- endfor %} } };
-  return *catalog;
+{%  if root_manifest %}
+const service_manager::Manifest& {{function_name}}() {
+  static base::NoDestructor<service_manager::Manifest> manifest{
+      {{generate_manifest_builder(root_manifest,
+            packaged_services=packaged_services, overlays=overlays)
+            |indent(6)}} };
+  return *manifest;
 }
+{%  else %}
+const std::vector<service_manager::Manifest>& {{function_name}}() {
+  static base::NoDestructor<std::vector<service_manager::Manifest>> manifests{ {
+{%- for info in packaged_services %}
+      {{info.namespace}}::GetManifest(){%- if not loop.last %},{%- endif %}
+{%- endfor -%} }};
+  return *manifests;
+}
+{%  endif %}
 
 {%- for namespace in namespaces|reverse %}
 }  // namespace {{namespace}}
diff --git a/services/catalog/public/tools/catalog.gni b/services/catalog/public/tools/catalog.gni
index 212d28c..ca11a734 100644
--- a/services/catalog/public/tools/catalog.gni
+++ b/services/catalog/public/tools/catalog.gni
@@ -4,173 +4,53 @@
 
 import("//build/config/dcheck_always_on.gni")
 
-# Generates a static catalog manifest to be loaded at runtime. This manifest
-# contains the union of all individual service manifests specified by the
-# template parameters.
+# Generates code to produce a list service_manager::Manifest objects given a set
+# of service_manager targets to include in the list.
 #
-# The output of a catalog rule is always a file named:
+# This is a temporary helper to transition away from JSON manifests. The catalog
+# target always has a companion catalog_cpp_source target, which yields a
+# source_set defining the generated function.
 #
-#     ${target_gen_dir}/${target_name}.json
-#
-# A Service Manager embedder uses a catalog manifest as its singular source of
-# truth regarding available services in the system.
-#
-# Parameters:
-#
-#   embedded_services (optional)
-#       A list of service manifest targets whose outputs correspond to services
-#       embedded by the Service Manager embedder's binary. Outputs of targets
-#       listed here will be embedded in the catalog within its
-#       "embedded_services" list.
-#
-#   standalone_services (optional)
-#       A list of service manifest targets whose outputs correspond to services
-#       with standalone binaries which must be available to the Service Manager
-#       at runtime. Outputs of targets listed here will be embedded in the
-#       catalog within its "standalone_services" list.
-#
-#       Typically a standalone service binary is expected to live next to
-#       the Service Manager embedder's binary, with the name
-#       "${service_name}.service", with an additional ".exe" suffix on Windows.
-#       Binaries following this naming scheme are typically output by
-#       service_executable targets. See
-#       //services/service_manager/public/cpp/service_executable.gni.
-#
-#    executable_overrides (optional)
-#       A list of overrides to apply in catalog metadata for individual
-#       services. An override string must be of the form
-#
-#           "<service_name>:<executable_path>"
-#
-#       The special token @EXE_DIR may be used in |executable_path| to denote
-#       a path relative to the Service Manager embedder's binary, substituted
-#       at runtime. For example:
-#
-#           "content_browser:@EXE_DIR/chrome"
-#
-#       would indicate to the Service Manager embedder that the
-#       "content_browser" service can be started by running the "chrome"
-#       executable in the embedder's own directory.
-#
-#       This overrides the default binary name expectation described in
-#       |standalone_services| above.
-#
-#    catalog_deps (optional)
-#       A list of other catalog targets whose outputs will be included within
-#       this catalog. Targets in this list
-#
+# No new uses of these targets should be introduced.
 template("catalog") {
-  output_filename = "$target_gen_dir/${target_name}.json"
-  action(target_name) {
+  group(target_name) {
     testonly = defined(invoker.testonly) && invoker.testonly
-
-    script = "//services/catalog/public/tools/generate_manifest.py"
-
-    inputs = []
-    outputs = [
-      output_filename,
-    ]
-
-    args = [ "--output=" + rebase_path(output_filename, root_build_dir) ]
-
-    if (is_debug || dcheck_always_on) {
-      args += [ "--pretty" ]
-    }
-
-    deps = []
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
-
-    if (defined(invoker.embedded_services)) {
-      args += [ "--embedded-services" ]
-      foreach(manifest_target, invoker.embedded_services) {
-        manifest_target_dir = get_label_info(manifest_target, "target_gen_dir")
-        manifest_target_name = get_label_info(manifest_target, "name")
-        manifest_filename = "$manifest_target_dir/${manifest_target_name}.json"
-
-        inputs += [ "$manifest_filename" ]
-        deps += [ manifest_target ]
-        args += [ rebase_path(manifest_filename, root_build_dir) ]
-
-        # Ensure that each entry does in fact reference a service manifest rule.
-        label_no_toolchain =
-            get_label_info(manifest_target, "label_no_toolchain")
-        toolchain = get_label_info(manifest_target, "toolchain")
-        deps += [ "${label_no_toolchain}__is_service_manifest(${toolchain})" ]
-      }
-    }
-
-    if (defined(invoker.standalone_services)) {
-      args += [ "--standalone-services" ]
-      foreach(manifest_target, invoker.standalone_services) {
-        manifest_target_dir = get_label_info(manifest_target, "target_gen_dir")
-        manifest_target_name = get_label_info(manifest_target, "name")
-        manifest_filename = "$manifest_target_dir/${manifest_target_name}.json"
-
-        inputs += [ "$manifest_filename" ]
-        deps += [ manifest_target ]
-        args += [ rebase_path(manifest_filename, root_build_dir) ]
-
-        # Ensure that each entry does in fact reference a service manifest rule.
-        label_no_toolchain =
-            get_label_info(manifest_target, "label_no_toolchain")
-        toolchain = get_label_info(manifest_target, "toolchain")
-        deps += [ "${label_no_toolchain}__is_service_manifest(${toolchain})" ]
-      }
-    }
-
-    if (defined(invoker.executable_overrides)) {
-      args +=
-          [ "--override-service-executables" ] + invoker.executable_overrides
-    }
-
-    if (defined(invoker.catalog_deps)) {
-      args += [ "--include-catalogs" ]
-      foreach(catalog_target, invoker.catalog_deps) {
-        catalog_target_dir = get_label_info(catalog_target, "target_gen_dir")
-        catalog_target_name = get_label_info(catalog_target, "name")
-        catalog_filename = "$catalog_target_dir/${catalog_target_name}.json"
-
-        inputs += [ "$catalog_filename" ]
-        deps += [ catalog_target ]
-        args += [ rebase_path(catalog_filename, root_build_dir) ]
-      }
-    }
   }
+
+  # NOTE: There is no longer a practical difference between embedded and
+  # standalone services in terms of manifest data. Some targets use one or the
+  # other or both.
+  submanifests = []
+  if (defined(invoker.embedded_services)) {
+    submanifests += invoker.embedded_services
+  }
+  if (defined(invoker.standalone_services)) {
+    submanifests += invoker.standalone_services
+  }
+
+  write_file("$target_gen_dir/${target_name}.submanifests", submanifests)
 }
 
-# Generates a source_set target which defines a single string constant
-# containing the contents of a compiled catalog manifest.
-#
-# Parameters:
-#
-#   catalog
-#       The catalog target whose output should be stringified.
-#
-#   generated_function_name
-#       The fully qualified symbol name of the C++ string constant to define in
-#       the generate source_set.
-#
 template("catalog_cpp_source") {
   assert(defined(invoker.catalog), "catalog is required")
   assert(defined(invoker.generated_function_name),
          "generated_function_name is required")
 
+  generator_target_name = "${target_name}__generator"
+  generated_filename_base = "${target_gen_dir}/${target_name}"
+
   catalog_target = invoker.catalog
   catalog_target_dir = get_label_info(catalog_target, "target_gen_dir")
   catalog_target_name = get_label_info(catalog_target, "name")
-  catalog_filename = "$catalog_target_dir/${catalog_target_name}.json"
 
-  generator_target_name = "${target_name}__generator"
-  generated_filename_base = "${target_gen_dir}/${target_name}"
+  submanifests =
+      read_file("$catalog_target_dir/${catalog_target_name}.submanifests",
+                "list lines")
 
   action(generator_target_name) {
     testonly = defined(invoker.testonly) && invoker.testonly
     script = "//services/catalog/public/tools/sourcify_manifest.py"
     inputs = [
-      catalog_filename,
-
       "//services/catalog/public/tools/catalog.cc.tmpl",
       "//services/catalog/public/tools/catalog.h.tmpl",
     ]
@@ -178,28 +58,42 @@
       "${generated_filename_base}.cc",
       "${generated_filename_base}.h",
     ]
+
+    submanifest_info = []
+    foreach(submanifest, submanifests) {
+      manifest_dir = get_label_info(submanifest, "target_gen_dir")
+      manifest_target_name = get_label_info(submanifest, "name")
+      manifest_namespace_input =
+          "$manifest_dir/${manifest_target_name}.namespace"
+      manifest_namespace_path =
+          rebase_path(manifest_namespace_input, root_build_dir)
+      manifest_header_base =
+          rebase_path(manifest_dir, root_gen_dir) + "/${manifest_target_name}"
+      submanifest_info +=
+          [ "packaged@$manifest_namespace_path@$manifest_header_base" ]
+    }
+
+    submanifest_info_file =
+        "$target_gen_dir/${invoker.target_name}.submanifest_info"
+    write_file(submanifest_info_file, submanifest_info)
+
     args = [
-      "--input=" + rebase_path(catalog_filename, root_build_dir),
+      "--submanifest-info=" +
+          rebase_path(submanifest_info_file, root_build_dir),
       "--output-filename-base=" +
           rebase_path(generated_filename_base, root_build_dir),
       "--output-function-name=" + invoker.generated_function_name,
       "--module-path=" + rebase_path(generated_filename_base, root_gen_dir),
     ]
-    if (is_debug || dcheck_always_on) {
-      args += [ "--pretty" ]
-    }
-    deps = [
-      catalog_target,
-    ]
   }
 
   source_set(target_name) {
     testonly = defined(invoker.testonly) && invoker.testonly
     sources = get_target_outputs(":$generator_target_name")
     deps = [
-      ":$generator_target_name",
-      "//base",
-      "//services/service_manager/public/cpp",
-    ]
+             ":$generator_target_name",
+             "//base",
+             "//services/service_manager/public/cpp",
+           ] + submanifests
   }
 }
diff --git a/services/catalog/public/tools/catalog.h.tmpl b/services/catalog/public/tools/catalog.h.tmpl
index 402a877b..aed4b1d 100644
--- a/services/catalog/public/tools/catalog.h.tmpl
+++ b/services/catalog/public/tools/catalog.h.tmpl
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This is a generated file. Please see the "catalog_cpp_source" template in
-// src/services/catalog/public/tools/catalog.gni for more details.
+// This is a generated file. Please see the "service_manifest" template in
+// src/services/service_manager/public/service_manifest.gni for more details.
+
 {%- set header_guard = "%s_H_"|format(path)|upper|replace("/", "_")|
         replace(".", "_")|replace("-", "_") %}
 
@@ -18,7 +19,11 @@
 namespace {{namespace}} {
 {%- endfor %}
 
+{% if root_manifest -%}
+const service_manager::Manifest& {{function_name}}();
+{% else -%}
 const std::vector<service_manager::Manifest>& {{function_name}}();
+{%- endif %}
 
 {% for namespace in namespaces|reverse %}
 }  // namespace {{namespace}}
diff --git a/services/catalog/public/tools/sourcify_manifest.py b/services/catalog/public/tools/sourcify_manifest.py
index 1bcfc6ae..acfc971d 100755
--- a/services/catalog/public/tools/sourcify_manifest.py
+++ b/services/catalog/public/tools/sourcify_manifest.py
@@ -18,10 +18,20 @@
     "build", "android", "gyp"))
 from util import build_utils
 
+
 _H_FILE_TEMPLATE = "catalog.h.tmpl"
 _CC_FILE_TEMPLATE = "catalog.cc.tmpl"
 
 
+eater_relative = "../../../../../tools/json_comment_eater"
+eater_relative = os.path.join(os.path.abspath(__file__), eater_relative)
+sys.path.insert(0, os.path.normpath(eater_relative))
+try:
+  import json_comment_eater
+finally:
+  sys.path.pop(0)
+
+
 # Disable lint check for finding modules:
 # pylint: disable=F0401
 
@@ -44,49 +54,38 @@
 
 
 def ApplyTemplate(path_to_template, output_path, global_vars, **kwargs):
-  def make_ascii(maybe_unicode):
-    if type(maybe_unicode) is str:
-      return maybe_unicode
-    assert type(maybe_unicode) is unicode
-    return maybe_unicode.encode("ascii", "ignore")
-
   with build_utils.AtomicOutput(output_path) as output_file:
     jinja_env = jinja2.Environment(
         loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
         keep_trailing_newline=True, **kwargs)
     jinja_env.globals.update(global_vars)
-    jinja_env.filters.update({
-      "is_dict": lambda x : type(x) is dict,
-      "is_list": lambda x : type(x) is list,
-      "is_number": lambda x : type(x) is int or type(x) is float,
-      "is_bool": lambda x: type(x) is bool,
-      "is_string": lambda x: type(x) is str,
-      "is_unicode": lambda x: type(x) is unicode,
-      "make_ascii": make_ascii,
-    })
     output_file.write(jinja_env.get_template(path_to_template).render())
 
 
 def main():
   parser = argparse.ArgumentParser(
       description="Generates a C++ constant containing a catalog manifest.")
-  parser.add_argument("--input")
+  parser.add_argument("--root-manifest")
+  parser.add_argument("--submanifest-info")
   parser.add_argument("--output-filename-base")
   parser.add_argument("--output-function-name")
   parser.add_argument("--module-path")
   args, _ = parser.parse_known_args()
 
-  if args.input is None:
-    raise Exception("--input is required")
+  if args.submanifest_info is None:
+    raise Exception("--submanifest-info required")
   if args.output_filename_base is None:
     raise Exception("--output-filename-base is required")
   if args.output_function_name is None:
     raise Exception("--output-function-name is required")
   if args.module_path is None:
-    raise Exception("--module-path is required")
+    args.module_path = args.output_filename_base
 
-  with open(args.input, "r") as input_file:
-    catalog = json.load(input_file)
+  if args.root_manifest:
+    with open(args.root_manifest, "r") as input_file:
+      root_manifest = json.loads(json_comment_eater.Nom(input_file.read()))
+  else:
+    root_manifest = None
 
   qualified_function_name = args.output_function_name.split("::")
   namespaces = qualified_function_name[0:-1]
@@ -95,8 +94,23 @@
   def raise_error(error, value):
     raise Exception(error)
 
+  overlays = []
+  packaged_services = []
+  with open(args.submanifest_info, "r") as info_file:
+    for line in info_file.readlines():
+      submanifest_type, namespace_file, header_base = line.strip().split("@", 3)
+      with open(namespace_file, "r") as namespace_file:
+        namespace = namespace_file.readline().strip()
+      info = { "namespace": namespace, "header": header_base + ".h" }
+      if submanifest_type == "overlay":
+        overlays.append(info)
+      else:
+        packaged_services.append(info)
+
   global_vars = {
-    "catalog": catalog,
+    "root_manifest": root_manifest,
+    "overlays": overlays,
+    "packaged_services": packaged_services,
     "function_name": function_name,
     "namespaces": namespaces,
     "path": args.module_path,
diff --git a/services/catalog/test_data/connection_spec b/services/catalog/test_data/connection_spec
deleted file mode 100644
index 80da172..0000000
--- a/services/catalog/test_data/connection_spec
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "requires": {
-        "bar": [ "bar:bar" ]
-      }
-    }
-  }
-}
diff --git a/services/catalog/test_data/instance b/services/catalog/test_data/instance
deleted file mode 100644
index 3fa31be..0000000
--- a/services/catalog/test_data/instance
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
-  "interface_provider_specs": { }
-}
diff --git a/services/catalog/test_data/malformed b/services/catalog/test_data/malformed
deleted file mode 100644
index 28a269c..0000000
--- a/services/catalog/test_data/malformed
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
diff --git a/services/catalog/test_data/options b/services/catalog/test_data/options
deleted file mode 100644
index 203a4e6..0000000
--- a/services/catalog/test_data/options
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
-  "options": {
-    "instance_sharing": "singleton",
-    "can_connect_to_other_services_as_any_user": true,
-    "can_connect_to_other_services_with_any_instance_name": true,
-    "can_create_other_service_instances": true
-  },
-  "interface_provider_specs": { }
-}
diff --git a/services/catalog/test_data/required_files b/services/catalog/test_data/required_files
deleted file mode 100644
index 2e45d97e..0000000
--- a/services/catalog/test_data/required_files
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
-  "interface_provider_specs": { },
-  "required_files": {
-    "all_platforms": [
-      { "path": "/all/platforms/fuchsia", "platform": "fuchsia" },
-      { "path": "/all/platforms/linux", "platform": "linux" },
-      { "path": "/all/platforms/windows", "platform": "windows" },
-      { "path": "/all/platforms/macosx", "platform": "macosx" },
-      { "path": "/all/platforms/android", "platform": "android" }
-    ],
-    "fuchsia_only": [{ "path": "/fuchsia/only", "platform": "fuchsia" }],
-    "linux_only": [{ "path": "/linux/only", "platform": "linux" }],
-    "windows_only": [{ "path" : "/windows/only", "platform": "windows" }],
-    "macosx_only": [{ "path" : "/macosx/only", "platform": "macosx" }],
-    "android_only": [{ "path" : "/android/only", "platform": "android" }]
-  }
-}
diff --git a/services/catalog/test_data/serialization b/services/catalog/test_data/serialization
deleted file mode 100644
index 10fe188..0000000
--- a/services/catalog/test_data/serialization
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "foo": [ "mojo::Bar", "mojo::Baz" ],
-        "bar": [ "mojo::Bork" ]
-      },
-      "requires": {
-        "bar": [ "a", "b" ]
-      }
-    }
-  }
-}
diff --git a/services/catalog/test_data/simple b/services/catalog/test_data/simple
deleted file mode 100644
index 04cd6fe..0000000
--- a/services/catalog/test_data/simple
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "name": "foo",
-  "display_name": "Foo",
-  "sandbox_type": "none",
-  "interface_provider_specs": { }
-}
diff --git a/services/service_manager/BUILD.gn b/services/service_manager/BUILD.gn
index efd375a..e55963d 100644
--- a/services/service_manager/BUILD.gn
+++ b/services/service_manager/BUILD.gn
@@ -28,8 +28,6 @@
     "connect_params.h",
     "service_manager.cc",
     "service_manager.h",
-    "service_overrides.cc",
-    "service_overrides.h",
     "switches.cc",
     "switches.h",
   ]
diff --git a/services/service_manager/background/background_service_manager.cc b/services/service_manager/background/background_service_manager.cc
index c887ea7..6e718c4 100644
--- a/services/service_manager/background/background_service_manager.cc
+++ b/services/service_manager/background/background_service_manager.cc
@@ -26,26 +26,13 @@
 
 BackgroundServiceManager::BackgroundServiceManager(
     ServiceProcessLauncherDelegate* launcher_delegate,
-    std::unique_ptr<base::Value> catalog_contents)
-    : background_thread_("service_manager") {
-  background_thread_.Start();
-  background_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&BackgroundServiceManager::InitializeOnBackgroundThread,
-                     base::Unretained(this), launcher_delegate,
-                     std::move(catalog_contents), std::vector<Manifest>()));
-}
-
-BackgroundServiceManager::BackgroundServiceManager(
-    ServiceProcessLauncherDelegate* launcher_delegate,
     const std::vector<Manifest>& manifests)
     : background_thread_("service_manager") {
   background_thread_.Start();
   background_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&BackgroundServiceManager::InitializeOnBackgroundThread,
-                     base::Unretained(this), launcher_delegate, nullptr,
-                     manifests));
+                     base::Unretained(this), launcher_delegate, manifests));
 }
 
 BackgroundServiceManager::~BackgroundServiceManager() {
@@ -74,14 +61,8 @@
 
 void BackgroundServiceManager::InitializeOnBackgroundThread(
     ServiceProcessLauncherDelegate* launcher_delegate,
-    std::unique_ptr<base::Value> catalog_contents,
     const std::vector<Manifest>& manifests) {
-  if (!manifests.empty()) {
-    context_ = std::make_unique<Context>(launcher_delegate, manifests);
-  } else {
-    context_ = std::make_unique<Context>(launcher_delegate,
-                                         std::move(catalog_contents));
-  }
+  context_ = std::make_unique<Context>(launcher_delegate, manifests);
 }
 
 void BackgroundServiceManager::ShutDownOnBackgroundThread(
diff --git a/services/service_manager/background/background_service_manager.h b/services/service_manager/background/background_service_manager.h
index d614f5b..8260d0c 100644
--- a/services/service_manager/background/background_service_manager.h
+++ b/services/service_manager/background/background_service_manager.h
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/threading/thread.h"
-#include "base/values.h"
 #include "build/build_config.h"
 #include "services/service_manager/public/cpp/manifest.h"
 #include "services/service_manager/public/mojom/connector.mojom.h"
@@ -32,8 +31,6 @@
 class BackgroundServiceManager {
  public:
   BackgroundServiceManager(ServiceProcessLauncherDelegate* launcher_delegate,
-                           std::unique_ptr<base::Value> catalog_contents);
-  BackgroundServiceManager(ServiceProcessLauncherDelegate* launcher_delegate,
                            const std::vector<Manifest>& manifests);
   ~BackgroundServiceManager();
 
@@ -50,7 +47,6 @@
  private:
   void InitializeOnBackgroundThread(
       ServiceProcessLauncherDelegate* launcher_delegate,
-      std::unique_ptr<base::Value> catalog_contents,
       const std::vector<Manifest>& manifests);
   void ShutDownOnBackgroundThread(base::WaitableEvent* done_event);
   void RegisterServiceOnBackgroundThread(
diff --git a/services/service_manager/embedder/BUILD.gn b/services/service_manager/embedder/BUILD.gn
index df6fb926..feeac1e2 100644
--- a/services/service_manager/embedder/BUILD.gn
+++ b/services/service_manager/embedder/BUILD.gn
@@ -2,19 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-component("embedder") {
-  public = [
-    "manifest_utils.h",
-  ]
-
-  sources = [
-    "manifest_utils.cc",
-  ]
-
-  # iOS embeds the Service Manager but does not use service_manager::Main() (and
-  # cannot use or even build it as-is).
-  if (!is_ios) {
-    public += [
+if (!is_ios) {
+  # iOS embeds the Service Manager but does not use anything in this library.
+  # This avoids having an empty component library target, which can otherwise be
+  # problematic.
+  component("embedder") {
+    public = [
       "main.h",
       "main_delegate.h",
       "process_type.h",
@@ -22,60 +15,52 @@
       "set_process_title_linux.h",
       "shared_file_util.h",
     ]
-    sources += [
+
+    sources = [
       "main.cc",
       "main_delegate.cc",
       "set_process_title.cc",
       "set_process_title_linux.cc",
       "shared_file_util.cc",
     ]
-  }
 
-  if (is_mac) {
-    sources += [
-      "mac_init.h",
-      "mac_init.mm",
-    ]
+    if (is_mac) {
+      sources += [
+        "mac_init.h",
+        "mac_init.mm",
+      ]
 
-    libs = [ "Foundation.framework" ]
-  }
+      libs = [ "Foundation.framework" ]
+    }
 
-  deps = [
-    "//base:base_static",
-    "//base:i18n",
-  ]
-
-  public_deps = [
-    ":embedder_result_codes",
-    "//base",
-    "//services/service_manager/public/cpp",
-    "//services/service_manager/public/mojom",
-  ]
-
-  if (!is_ios) {
-    # deps of ServiceManager::Main and related functionality.
-    deps += [
+    deps = [
+      "//base:base_static",
+      "//base:i18n",
       "//base/allocator:buildflags",
       "//components/tracing:startup_tracing",
     ]
 
+    public_deps = [
+      ":embedder_result_codes",
+      ":embedder_switches",
+      "//base",
+      "//mojo/core/embedder",
+      "//services/service_manager/background:lib",
+      "//services/service_manager/public/cpp",
+      "//services/service_manager/public/cpp/service_executable:support",
+      "//services/service_manager/public/mojom",
+      "//services/service_manager/runner:init",
+      "//services/service_manager/runner/common",
+    ]
+
     if (!is_nacl) {
       # NaCl stuff should not depend on skia as it would require platform and
       # cpu properties set.
       deps += [ "//ui/base" ]
     }
 
-    public_deps += [
-      ":embedder_switches",
-      "//mojo/core/embedder",
-      "//services/service_manager/background:lib",
-      "//services/service_manager/public/cpp/service_executable:support",
-      "//services/service_manager/runner:init",
-      "//services/service_manager/runner/common",
-    ]
+    defines = [ "IS_SERVICE_MANAGER_EMBEDDER_IMPL" ]
   }
-
-  defines = [ "IS_SERVICE_MANAGER_EMBEDDER_IMPL" ]
 }
 
 component("embedder_switches") {
@@ -94,18 +79,3 @@
     "result_codes.h",
   ]
 }
-
-source_set("unittests") {
-  testonly = true
-
-  sources = [
-    "manifest_utils_unittest.cc",
-  ]
-
-  deps = [
-    ":embedder",
-    "//base",
-    "//base/test:test_support",
-    "//testing/gtest",
-  ]
-}
diff --git a/services/service_manager/embedder/main.cc b/services/service_manager/embedder/main.cc
index 53eeddcb..329b86e0 100644
--- a/services/service_manager/embedder/main.cc
+++ b/services/service_manager/embedder/main.cc
@@ -234,7 +234,7 @@
   ServiceProcessLauncherDelegateImpl service_process_launcher_delegate(
       delegate);
   service_manager::BackgroundServiceManager background_service_manager(
-      &service_process_launcher_delegate, delegate->CreateServiceCatalog());
+      &service_process_launcher_delegate, delegate->GetServiceManifests());
 
   base::RunLoop run_loop;
   delegate->OnServiceManagerInitialized(run_loop.QuitClosure(),
diff --git a/services/service_manager/embedder/main_delegate.cc b/services/service_manager/embedder/main_delegate.cc
index 1501a97b..ea4c1d7 100644
--- a/services/service_manager/embedder/main_delegate.cc
+++ b/services/service_manager/embedder/main_delegate.cc
@@ -27,8 +27,8 @@
 void MainDelegate::OverrideMojoConfiguration(
     mojo::core::Configuration* config) {}
 
-std::unique_ptr<base::Value> MainDelegate::CreateServiceCatalog() {
-  return nullptr;
+std::vector<Manifest> MainDelegate::GetServiceManifests() {
+  return std::vector<Manifest>();
 }
 
 bool MainDelegate::ShouldLaunchAsServiceProcess(const Identity& identity) {
diff --git a/services/service_manager/embedder/main_delegate.h b/services/service_manager/embedder/main_delegate.h
index d373d708..ba3589a5 100644
--- a/services/service_manager/embedder/main_delegate.h
+++ b/services/service_manager/embedder/main_delegate.h
@@ -6,6 +6,7 @@
 #define SERVICES_SERVICE_MANAGER_EMBEDDER_MAIN_DELEGATE_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/callback_forward.h"
 #include "base/component_export.h"
@@ -15,12 +16,12 @@
 #include "services/service_manager/background/background_service_manager.h"
 #include "services/service_manager/embedder/process_type.h"
 #include "services/service_manager/public/cpp/identity.h"
+#include "services/service_manager/public/cpp/manifest.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
 
 namespace base {
 class CommandLine;
-class Value;
 namespace mac {
 class ScopedNSAutoreleasePool;
 }
@@ -73,9 +74,10 @@
   // Allows the embedder to override the process-wide Mojop configuration.
   virtual void OverrideMojoConfiguration(mojo::core::Configuration* config);
 
-  // Create the service catalog to be used by the Service Manager. May return
-  // null to use the default (empty) catalog, if you're into that.
-  virtual std::unique_ptr<base::Value> CreateServiceCatalog();
+  // Gets the list of service manifests with which to initialize the Service
+  // Manager. This list must describe the complete set of usable services in
+  // the system and remains fixed for the lifetime of the Service Manager.
+  virtual std::vector<Manifest> GetServiceManifests();
 
   // Indicates whether a process started by the service manager for a given
   // target service identity should be run as a real service process (|true|)
diff --git a/services/service_manager/embedder/manifest_utils.cc b/services/service_manager/embedder/manifest_utils.cc
deleted file mode 100644
index a43c152..0000000
--- a/services/service_manager/embedder/manifest_utils.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/service_manager/embedder/manifest_utils.h"
-
-
-namespace service_manager {
-
-namespace {
-
-// Similar to base::DictionaryValue::MergeDictionary(), except concatenates
-// ListValue contents.
-// This is explicitly not part of base::DictionaryValue at brettw's request.
-void MergeDictionary(base::DictionaryValue* target,
-                     const base::DictionaryValue* source) {
-  for (base::DictionaryValue::Iterator it(*source); !it.IsAtEnd();
-       it.Advance()) {
-    const base::Value* merge_value = &it.value();
-    // Check whether we have to merge dictionaries.
-    if (merge_value->is_dict()) {
-      base::DictionaryValue* sub_dict;
-      if (target->GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) {
-        MergeDictionary(sub_dict,
-                        static_cast<const base::DictionaryValue*>(merge_value));
-        continue;
-      }
-    }
-    if (merge_value->is_list()) {
-      const base::ListValue* merge_list = nullptr;
-      if (merge_value->GetAsList(&merge_list)) {
-        base::ListValue* target_list = nullptr;
-        if (target->GetListWithoutPathExpansion(it.key(), &target_list)) {
-          for (size_t i = 0; i < merge_list->GetSize(); ++i) {
-            const base::Value* element = nullptr;
-            CHECK(merge_list->Get(i, &element));
-            target_list->Append(element->CreateDeepCopy());
-          }
-          continue;
-        }
-      }
-    }
-    // All other cases: Make a copy and hook it up.
-    target->SetKey(it.key(), merge_value->Clone());
-  }
-}
-
-}  // namespace
-
-void MergeManifestWithOverlay(base::Value* manifest, base::Value* overlay) {
-  if (!overlay)
-    return;
-
-  base::DictionaryValue* manifest_dictionary = nullptr;
-  bool result = manifest->GetAsDictionary(&manifest_dictionary);
-  DCHECK(result);
-  base::DictionaryValue* overlay_dictionary = nullptr;
-  result = overlay->GetAsDictionary(&overlay_dictionary);
-  DCHECK(result);
-  MergeDictionary(manifest_dictionary, overlay_dictionary);
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/embedder/manifest_utils.h b/services/service_manager/embedder/manifest_utils.h
deleted file mode 100644
index a6af881..0000000
--- a/services/service_manager/embedder/manifest_utils.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_EMBEDDER_MANIFEST_UTILS_H_
-#define SERVICES_SERVICE_MANAGER_EMBEDDER_MANIFEST_UTILS_H_
-
-#include "base/component_export.h"
-#include "base/values.h"
-
-namespace service_manager {
-
-// Merges |overlay| (if not null) into |manifest|.
-// Uses a strategy similar to base::DictionaryValue::MergeDictionary(), except
-// concatenates ListValue contents.
-void COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER)
-    MergeManifestWithOverlay(base::Value* manifest, base::Value* overlay);
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_EMBEDDER_MANIFEST_UTILS_H_
diff --git a/services/service_manager/embedder/manifest_utils_unittest.cc b/services/service_manager/embedder/manifest_utils_unittest.cc
deleted file mode 100644
index 9d8e46ac..0000000
--- a/services/service_manager/embedder/manifest_utils_unittest.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/service_manager/embedder/manifest_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace service_manager {
-
-TEST(MergeManifestWithOverlayTest, Merge) {
-  // |manifest| & |overlay| have three properties, "string", "list" and
-  // "dictionary", which are then merged.
-  base::DictionaryValue manifest;
-  manifest.SetString("string", "Hello, ");
-  std::unique_ptr<base::DictionaryValue> dict_value_original(
-      std::make_unique<base::DictionaryValue>());
-  dict_value_original->SetString("key1", "original");
-  dict_value_original->SetString("key3", "original");
-  manifest.Set("dictionary", std::move(dict_value_original));
-  std::unique_ptr<base::ListValue> list(std::make_unique<base::ListValue>());
-  list->AppendString("A");
-  list->AppendString("B");
-  manifest.Set("list", std::move(list));
-
-  base::DictionaryValue overlay;
-  overlay.SetString("string", "World!");
-  std::unique_ptr<base::DictionaryValue> dict_value_replacement(
-      std::make_unique<base::DictionaryValue>());
-  dict_value_replacement->SetString("key1", "new");
-  dict_value_replacement->SetString("key2", "new");
-  overlay.Set("dictionary", std::move(dict_value_replacement));
-  list = std::make_unique<base::ListValue>();
-  list->AppendString("C");
-  overlay.Set("list", std::move(list));
-
-  MergeManifestWithOverlay(&manifest, &overlay);
-
-  // Simple string value should have been clobbered.
-  std::string out_string;
-  EXPECT_TRUE(manifest.GetString("string", &out_string));
-  EXPECT_EQ(out_string, "World!");
-
-  // Dictionary should have been merged, with key1 being clobbered, key2 added
-  // and key3 preserved.
-  base::DictionaryValue* out_dictionary = nullptr;
-  EXPECT_TRUE(manifest.GetDictionary("dictionary", &out_dictionary));
-  EXPECT_EQ(3u, out_dictionary->size());
-  std::string value1, value2, value3;
-  EXPECT_TRUE(out_dictionary->GetString("key1", &value1));
-  EXPECT_TRUE(out_dictionary->GetString("key2", &value2));
-  EXPECT_TRUE(out_dictionary->GetString("key3", &value3));
-  EXPECT_EQ(value1, "new");
-  EXPECT_EQ(value2, "new");
-  EXPECT_EQ(value3, "original");
-
-  // List should have been merged, with the items from overlay appended to the
-  // items from manifest.
-  base::ListValue* out_list = nullptr;
-  EXPECT_TRUE(manifest.GetList("list", &out_list));
-  EXPECT_EQ(3u, out_list->GetSize());
-  std::string a, b, c;
-  EXPECT_TRUE(out_list->GetString(0, &a));
-  EXPECT_TRUE(out_list->GetString(1, &b));
-  EXPECT_TRUE(out_list->GetString(2, &c));
-  EXPECT_EQ("A", a);
-  EXPECT_EQ("B", b);
-  EXPECT_EQ("C", c);
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/public/cpp/manifest.cc b/services/service_manager/public/cpp/manifest.cc
index e018583d..464ad43 100644
--- a/services/service_manager/public/cpp/manifest.cc
+++ b/services/service_manager/public/cpp/manifest.cc
@@ -230,7 +230,7 @@
   return manifest;
 }
 
-void Manifest::Amend(Manifest other) {
+Manifest& Manifest::Amend(Manifest other) {
   for (auto& other_capability : other.exposed_capabilities) {
     auto it = std::find_if(
         exposed_capabilities.begin(), exposed_capabilities.end(),
@@ -272,6 +272,8 @@
     packaged_services.emplace_back(std::move(manifest));
   for (auto& file_info : other.preloaded_files)
     preloaded_files.emplace_back(std::move(file_info));
+
+  return *this;
 }
 
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/manifest.h b/services/service_manager/public/cpp/manifest.h
index 684a60eb..12294aa 100644
--- a/services/service_manager/public/cpp/manifest.h
+++ b/services/service_manager/public/cpp/manifest.h
@@ -267,7 +267,7 @@
   // Amends this Manifest with a subset of |other|. Namely, exposed and required
   // capabilities, exposed and required interface filter capabilities, packaged
   // services, and preloaded files are all added from |other| if present.
-  void Amend(Manifest other);
+  Manifest& Amend(Manifest other);
 
   std::string service_name;
   DisplayName display_name;
diff --git a/services/service_manager/public/service_manifest.gni b/services/service_manager/public/service_manifest.gni
index 1bf9463..b797200e 100644
--- a/services/service_manager/public/service_manifest.gni
+++ b/services/service_manager/public/service_manifest.gni
@@ -4,65 +4,129 @@
 
 import("//build/config/dcheck_always_on.gni")
 
-# Used to produce a Service Manifest for a Service.
+# Generates code to produce a compiled service_manager::Manifest from a JSON
+# description at build time.
 #
-# Service manifests may be subsequently aggregated into one or more catalog
-# manifests (see //services/catalog/public/tools/catalog.gni). A catalog
-# manifest provides the Service Manager at runtime with a static service layout
-# configuration to dictate which services are supported by the runtime
-# environment as well as how individual services may be launched and
-# interconnected.
+# This is a temporary helper for the transition away from JSON manifests. Do not
+# introduce new service_manifest targets.
 #
-# Note that this target may be used to produce partial manifests, and partial
-# manifests may be aggregated by using one service_manifest target as the
-# |source_manifest| of another (see below.)
+# This template yields a source_set target which defines a symbol named
+# "${name}::GetManifest()" where ${name} is the service name given in the
+# target.
 #
-# Parameters:
-#
-#   source (optional**)
-#       The manifest template for this service. Must be the name of a valid JSON
-#       file.
-#
-#   source_manifest (optional**)
-#       The manifest template for this service. Must be the name of another
-#       service_manifest target.
-#
-#       ** NOTE: Either |source| OR |source_manifest| MUST be specified.
-#
-#   name (optional)
-#       The name of the service whose manifest is to be generated. A script
-#       validates that the value of this parameter matches the name set in the
-#       source manifest and raises an error if it does not match.
-#
-#   overlays (optional)
-#       A list of other manifest targets whose outputs should be overlayed onto
-#       the source manifest before emitting the final output. Overlays are
-#       applied in-order as the last step of output generation, after any
-#       |packaged_services| manifests are embedded.
-#
-#   packaged_services (optional)
-#       A list of other manifest targets whose outputs should be packaged
-#       within this output manifest, specifically within a toplevel "services"
-#       list.
-#
-#   testonly (optional)
-#
-# Outputs:
-#
-#   An instantiation of this template produces a meta manifest from the source
-#   template and the output manifests of all its |overlay| and
-#   |packaged_services|dependencies. The output file is always
-#   "$target_gen_dir/${target_name}.json".
-#
+# All service_manifest targets should be replaced with in-tree C++ sources.
 template("service_manifest") {
-  assert(
-      defined(invoker.source) || defined(invoker.source_manifest),
-      "\"source\" or \"source_manifest\" must be defined for the $target_name target")
-  assert(
-      !defined(invoker.source) || !defined(invoker.source_manifest),
-      "Only one of \"source\" or \"source_manifest\" must be defined for the $target_name target")
+  assert(defined(invoker.source),
+         "\"source\" must be defined for the $target_name target")
 
-  action(target_name) {
+  generator_target_name = "${target_name}__generator"
+  generated_sources = [
+    "$target_gen_dir/${target_name}.cc",
+    "$target_gen_dir/${target_name}.h",
+  ]
+
+  # We prefer to use |name| for the generated function's namespace if a
+  # |generated_namespace| isn't explicitly defined. It turns out that we also
+  # have a few targets which don't specify a |name| though; they all have unique
+  # target names, so we fall back on that if necessary. The important detail is
+  # that all generated GetManifest() functions should live in their own
+  # namespace, and with the current (and final) set of service_manifest targets
+  # in the tree, these rules accomplish that.
+  if (defined(invoker.generated_namespace)) {
+    output_namespace = invoker.generated_namespace
+  } else if (defined(invoker.name)) {
+    output_namespace = invoker.name
+  } else {
+    output_namespace = invoker.target_name
+  }
+
+  write_file("$target_gen_dir/${target_name}.namespace", output_namespace)
+
+  source_set(target_name) {
+    testonly = defined(invoker.testonly) && invoker.testonly
+    sources = generated_sources
+    public_deps = [
+      ":$generator_target_name",
+    ]
+
+    deps = []
+    if (defined(invoker.packaged_services)) {
+      deps += invoker.packaged_services
+    }
+    if (defined(invoker.overlays)) {
+      deps += invoker.overlays
+    }
+  }
+
+  collator_target_name = "${target_name}__collator"
+
+  action(generator_target_name) {
+    testonly = defined(invoker.testonly) && invoker.testonly
+    script = "//services/catalog/public/tools/sourcify_manifest.py"
+
+    inputs = [
+      "//services/catalog/public/tools/catalog.cc.tmpl",
+      "//services/catalog/public/tools/catalog.h.tmpl",
+      invoker.source,
+    ]
+    outputs = generated_sources
+
+    submanifest_info = []
+    if (defined(invoker.packaged_services)) {
+      foreach(submanifest, invoker.packaged_services) {
+        manifest_dir = get_label_info(submanifest, "target_gen_dir")
+        manifest_target_name = get_label_info(submanifest, "name")
+        manifest_namespace_input =
+            "$manifest_dir/${manifest_target_name}.namespace"
+        manifest_namespace_path =
+            rebase_path(manifest_namespace_input, root_build_dir)
+        manifest_header_base =
+            rebase_path(manifest_dir, root_gen_dir) + "/${manifest_target_name}"
+        submanifest_info +=
+            [ "packaged@$manifest_namespace_path@$manifest_header_base" ]
+      }
+    }
+    if (defined(invoker.overlays)) {
+      foreach(submanifest, invoker.overlays) {
+        manifest_dir = get_label_info(submanifest, "target_gen_dir")
+        manifest_target_name = get_label_info(submanifest, "name")
+        manifest_namespace_input =
+            "$manifest_dir/${manifest_target_name}.namespace"
+        manifest_namespace_path =
+            rebase_path(manifest_namespace_input, root_build_dir)
+        manifest_header_base =
+            rebase_path(manifest_dir, root_gen_dir) + "/${manifest_target_name}"
+        submanifest_info +=
+            [ "overlay@$manifest_namespace_path@$manifest_header_base" ]
+      }
+    }
+
+    submanifest_info_file =
+        "${target_gen_dir}/${invoker.target_name}.submanifest_info"
+    write_file(submanifest_info_file, submanifest_info)
+
+    args = [
+      "--root-manifest=" + rebase_path(invoker.source, root_build_dir),
+      "--submanifest-info=" +
+          rebase_path(submanifest_info_file, root_build_dir),
+      "--output-function-name=${output_namespace}::GetManifest",
+      "--output-filename-base=" +
+          rebase_path("$target_gen_dir/${invoker.target_name}", root_build_dir),
+      "--module-path=" +
+          rebase_path("$target_gen_dir/${invoker.target_name}", root_gen_dir),
+    ]
+
+    # We inherit a public dependency on the collator because service_manifest
+    # dependents still expect to use its generated JSON output. We don't
+    # actually depend on the collated JSON at all here, since packaged services
+    # and overlays are added in the generated C++ code by referring to other
+    # generated C++ code.
+    public_deps = [
+      ":$collator_target_name",
+    ]
+  }
+
+  action(collator_target_name) {
     testonly = defined(invoker.testonly) && invoker.testonly
 
     script =
@@ -73,25 +137,16 @@
       deps += invoker.deps
     }
 
-    if (defined(invoker.source)) {
-      source = invoker.source
-    } else {
-      source_target_dir =
-          get_label_info(invoker.source_manifest, "target_gen_dir")
-      source_target_name = get_label_info(invoker.source_manifest, "name")
-      source = "$source_target_dir/${source_target_name}.json"
-      deps += [ invoker.source_manifest ]
-    }
     inputs = [
-      source,
+      invoker.source,
     ]
 
-    output = "$target_gen_dir/${target_name}.json"
+    output = "$target_gen_dir/${invoker.target_name}.json"
     outputs = [
       output,
     ]
 
-    rebase_parent = rebase_path(source, root_build_dir)
+    rebase_parent = rebase_path(invoker.source, root_build_dir)
     rebase_output = rebase_path(output, root_build_dir)
 
     args = [
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index a169c130..c42fa2a 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -946,24 +946,42 @@
 
 ServiceManager::ServiceManager(std::unique_ptr<ServiceProcessLauncherFactory>
                                    service_process_launcher_factory,
-                               const std::vector<Manifest>& manifests,
-                               catalog::ManifestProvider* manifest_provider)
-    : catalog_(nullptr, manifests, manifest_provider),
+                               const std::vector<Manifest>& manifests)
+    : catalog_(manifests),
       identity_to_instance_(std::make_unique<IdentityToInstanceMap>()),
       service_process_launcher_factory_(
           std::move(service_process_launcher_factory)) {
-  InitBuiltinServices();
-}
+  InterfaceProviderSpec spec;
+  spec.provides[kCapability_ServiceManager].insert(
+      "service_manager.mojom.ServiceManager");
+  spec.requires["*"].insert("service_manager:service_factory");
+  InterfaceProviderSpecMap specs;
+  specs[mojom::kServiceManager_ConnectorSpec] = std::move(spec);
 
-ServiceManager::ServiceManager(std::unique_ptr<ServiceProcessLauncherFactory>
-                                   service_process_launcher_factory,
-                               std::unique_ptr<base::Value> catalog_contents,
-                               catalog::ManifestProvider* manifest_provider)
-    : catalog_(std::move(catalog_contents), {}, manifest_provider),
-      identity_to_instance_(std::make_unique<IdentityToInstanceMap>()),
-      service_process_launcher_factory_(
-          std::move(service_process_launcher_factory)) {
-  InitBuiltinServices();
+  service_manager_instance_ = CreateInstance(
+      GetServiceManagerInstanceIdentity(), InstanceType::kSingleton,
+      std::move(specs), catalog::ServiceOptions());
+
+  mojom::ServicePtr service;
+  service_binding_.Bind(mojo::MakeRequest(&service));
+  service_manager_instance_->StartWithService(std::move(service));
+
+  InterfaceProviderSpec catalog_spec;
+  catalog_spec.provides["directory"].insert("filesystem.mojom.Directory");
+  catalog_spec.provides["catalog:catalog"].insert("catalog.mojom.Catalog");
+  catalog_spec.provides["control"].insert("catalog.mojom.CatalogControl");
+  InterfaceProviderSpecMap catalog_specs;
+  catalog_specs[mojom::kServiceManager_ConnectorSpec] = std::move(catalog_spec);
+
+  Identity id{catalog::mojom::kServiceName, kSystemInstanceGroup, base::Token{},
+              base::Token::CreateRandom()};
+  Instance* instance =
+      CreateInstance(id, InstanceType::kSingleton, std::move(catalog_specs),
+                     catalog::ServiceOptions());
+
+  mojom::ServicePtr catalog_service;
+  catalog_.BindServiceRequest(mojo::MakeRequest(&catalog_service));
+  instance->StartWithService(std::move(catalog_service));
 }
 
 ServiceManager::~ServiceManager() {
@@ -1218,43 +1236,6 @@
   Connect(std::move(params));
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// ServiceManager, private:
-
-void ServiceManager::InitBuiltinServices() {
-  InterfaceProviderSpec spec;
-  spec.provides[kCapability_ServiceManager].insert(
-      "service_manager.mojom.ServiceManager");
-  spec.requires["*"].insert("service_manager:service_factory");
-  InterfaceProviderSpecMap specs;
-  specs[mojom::kServiceManager_ConnectorSpec] = std::move(spec);
-
-  service_manager_instance_ = CreateInstance(
-      GetServiceManagerInstanceIdentity(), InstanceType::kSingleton,
-      std::move(specs), catalog::ServiceOptions());
-
-  mojom::ServicePtr service;
-  service_binding_.Bind(mojo::MakeRequest(&service));
-  service_manager_instance_->StartWithService(std::move(service));
-
-  InterfaceProviderSpec catalog_spec;
-  catalog_spec.provides["directory"].insert("filesystem.mojom.Directory");
-  catalog_spec.provides["catalog:catalog"].insert("catalog.mojom.Catalog");
-  catalog_spec.provides["control"].insert("catalog.mojom.CatalogControl");
-  InterfaceProviderSpecMap catalog_specs;
-  catalog_specs[mojom::kServiceManager_ConnectorSpec] = std::move(catalog_spec);
-
-  Identity id{catalog::mojom::kServiceName, kSystemInstanceGroup, base::Token{},
-              base::Token::CreateRandom()};
-  Instance* instance =
-      CreateInstance(id, InstanceType::kSingleton, std::move(catalog_specs),
-                     catalog::ServiceOptions());
-
-  mojom::ServicePtr catalog_service;
-  catalog_.BindServiceRequest(mojo::MakeRequest(&catalog_service));
-  instance->StartWithService(std::move(catalog_service));
-}
-
 void ServiceManager::OnInstanceError(Instance* instance) {
   // We never clean up the ServiceManager's own instance.
   if (instance == service_manager_instance_)
diff --git a/services/service_manager/service_manager.h b/services/service_manager/service_manager.h
index 2a046f9..8bf2428 100644
--- a/services/service_manager/service_manager.h
+++ b/services/service_manager/service_manager.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
-#include "base/values.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "services/catalog/catalog.h"
@@ -29,11 +28,6 @@
 #include "services/service_manager/public/mojom/service_factory.mojom.h"
 #include "services/service_manager/public/mojom/service_manager.mojom.h"
 #include "services/service_manager/runner/host/service_process_launcher_factory.h"
-#include "services/service_manager/service_overrides.h"
-
-namespace catalog {
-class ManifestProvider;
-}
 
 namespace service_manager {
 
@@ -50,25 +44,9 @@
   // |service_process_launcher_factory| is an instance of an object capable of
   // vending implementations of ServiceProcessLauncher, e.g. for out-of-process
   // execution.
-  explicit ServiceManager(
-      std::unique_ptr<ServiceProcessLauncherFactory>
-          service_process_launcher_factory,
-      const std::vector<Manifest>& manifests,
-      catalog::ManifestProvider* manifest_provider = nullptr);
-
-  // |service_process_launcher_factory| is an instance of an object capable of
-  // vending implementations of ServiceProcessLauncher, e.g. for out-of-process
-  // execution.
-  //
-  // |catalog_contents|, if not null, will be used to prepoulate the service
-  // manager catalog with a fixed data set. |manifest_provider|, if not null,
-  // will be consulted for dynamic manifest resolution if a manifest is not
-  // found within the catalog; if used, |manifest_provider| is not owned and
-  // must outlive this ServiceManager.
-  ServiceManager(std::unique_ptr<ServiceProcessLauncherFactory>
-                     service_process_launcher_factory,
-                 std::unique_ptr<base::Value> catalog_contents,
-                 catalog::ManifestProvider* manifest_provider);
+  explicit ServiceManager(std::unique_ptr<ServiceProcessLauncherFactory>
+                              service_process_launcher_factory,
+                          const std::vector<Manifest>& manifests);
   ~ServiceManager() override;
 
   // Provide a callback to be notified whenever an instance is destroyed.
@@ -128,8 +106,6 @@
     kSingleton,
   };
 
-  void InitBuiltinServices();
-
   // Called when |instance| encounters an error. Deletes |instance|.
   void OnInstanceError(Instance* instance);
 
diff --git a/services/service_manager/service_overrides.cc b/services/service_manager/service_overrides.cc
deleted file mode 100644
index 2dfa8b5..0000000
--- a/services/service_manager/service_overrides.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/service_manager/service_overrides.h"
-
-#include "base/base_paths.h"
-#include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-
-namespace service_manager {
-
-namespace {
-
-const char kExecutablePathKey[] = "executable_path";
-const char kPackageNameKey[] = "package_name";
-
-}  // namespace
-
-ServiceOverrides::Entry::Entry() {}
-
-ServiceOverrides::Entry::~Entry() {}
-
-ServiceOverrides::ServiceOverrides(std::unique_ptr<base::Value> overrides) {
-  const base::DictionaryValue* services;
-  if (!overrides->GetAsDictionary(&services)) {
-    LOG(ERROR) << "Expected top-level dictionary.";
-    return;
-  }
-
-  base::DictionaryValue::Iterator service_iter(*services);
-  for (; !service_iter.IsAtEnd(); service_iter.Advance()) {
-    Entry& new_entry = entries_[service_iter.key()];
-
-    const base::DictionaryValue* value;
-    if (!service_iter.value().GetAsDictionary(&value)) {
-      LOG(ERROR) << "Expected service entry to be a dictionary.";
-      return;
-    }
-
-    std::string executable_path_value;
-    if (value->GetString(kExecutablePathKey, &executable_path_value)) {
-      base::FilePath exe_dir;
-      CHECK(base::PathService::Get(base::DIR_EXE, &exe_dir));
-#if defined(OS_WIN)
-      executable_path_value += ".exe";
-      base::ReplaceFirstSubstringAfterOffset(
-          &executable_path_value, 0, "@EXE_DIR",
-          base::UTF16ToUTF8(exe_dir.value()));
-      new_entry.executable_path =
-          base::FilePath(base::UTF8ToUTF16(executable_path_value));
-#else
-      base::ReplaceFirstSubstringAfterOffset(
-          &executable_path_value, 0, "@EXE_DIR",
-          exe_dir.value());
-      new_entry.executable_path = base::FilePath(executable_path_value);
-#endif
-    }
-
-    value->GetString(kPackageNameKey, &new_entry.package_name);
-  }
-}
-
-ServiceOverrides::~ServiceOverrides() {}
-
-bool ServiceOverrides::GetExecutablePathOverride(
-    const std::string& service_name,
-    base::FilePath* path) const {
-  auto iter = entries_.find(service_name);
-  if (iter == entries_.end() || iter->second.executable_path.empty())
-    return false;
-
-  *path = iter->second.executable_path;
-  return true;
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/service_overrides.h b/services/service_manager/service_overrides.h
deleted file mode 100644
index 1478ef76..0000000
--- a/services/service_manager/service_overrides.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_SERVICE_OVERRIDES_H_
-#define SERVICES_SERVICE_MANAGER_SERVICE_OVERRIDES_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/values.h"
-
-namespace service_manager {
-
-class ServiceOverrides {
- public:
-  struct Entry {
-    Entry();
-    ~Entry();
-
-    base::FilePath executable_path;
-    std::string package_name;
-  };
-
-  explicit ServiceOverrides(std::unique_ptr<base::Value> overrides);
-  ~ServiceOverrides();
-
-  bool GetExecutablePathOverride(const std::string& service_name,
-                                 base::FilePath* path) const;
-
-  const std::map<std::string, Entry>& entries() const { return entries_; }
-
- private:
-  std::map<std::string, Entry> entries_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceOverrides);
-};
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_SERVICE_OVERRIDES_H_
diff --git a/services/service_manager/standalone/context.cc b/services/service_manager/standalone/context.cc
index b7908da..12594f8 100644
--- a/services/service_manager/standalone/context.cc
+++ b/services/service_manager/standalone/context.cc
@@ -70,21 +70,7 @@
 
 Context::Context(
     ServiceProcessLauncherDelegate* service_process_launcher_delegate,
-    const std::vector<Manifest>& manifests)
-    : Context(service_process_launcher_delegate, nullptr, manifests) {}
-
-Context::Context(
-    ServiceProcessLauncherDelegate* service_process_launcher_delegate,
-    std::unique_ptr<base::Value> catalog_contents)
-    : Context(service_process_launcher_delegate,
-              std::move(catalog_contents),
-              std::vector<Manifest>()) {}
-
-Context::Context(
-    ServiceProcessLauncherDelegate* service_process_launcher_delegate,
-    std::unique_ptr<base::Value> catalog_contents,
-    const std::vector<Manifest>& manifests)
-    : main_entry_time_(base::Time::Now()) {
+    const std::vector<Manifest>& manifests) {
   TRACE_EVENT0("service_manager", "Context::Context");
 
   std::unique_ptr<ServiceProcessLauncherFactory>
@@ -97,14 +83,8 @@
       std::make_unique<ServiceProcessLauncherFactoryImpl>(
           service_process_launcher_delegate);
 #endif
-  if (!manifests.empty()) {
-    service_manager_ = std::make_unique<ServiceManager>(
-        std::move(service_process_launcher_factory), manifests, nullptr);
-  } else {
-    service_manager_ = std::make_unique<ServiceManager>(
-        std::move(service_process_launcher_factory),
-        std::move(catalog_contents), nullptr);
-  }
+  service_manager_ = std::make_unique<ServiceManager>(
+      std::move(service_process_launcher_factory), manifests);
 }
 
 Context::~Context() = default;
diff --git a/services/service_manager/standalone/context.h b/services/service_manager/standalone/context.h
index 2fc0c97aa..234a9aa 100644
--- a/services/service_manager/standalone/context.h
+++ b/services/service_manager/standalone/context.h
@@ -11,7 +11,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "base/values.h"
 #include "services/service_manager/public/cpp/manifest.h"
 #include "services/service_manager/runner/host/service_process_launcher_delegate.h"
 
@@ -24,11 +23,6 @@
  public:
   Context(ServiceProcessLauncherDelegate* launcher_delegate,
           const std::vector<Manifest>& manifests);
-  Context(ServiceProcessLauncherDelegate* launcher_delegate,
-          std::unique_ptr<base::Value> catalog_contents);
-  Context(ServiceProcessLauncherDelegate* launcher_delegate,
-          std::unique_ptr<base::Value> catalog_contents,
-          const std::vector<Manifest>& manifests);
   ~Context();
 
   // Run the application specified on the command line, and run |on_quit| when
diff --git a/services/service_manager/tests/BUILD.gn b/services/service_manager/tests/BUILD.gn
index b3cc60a..db89a4b 100644
--- a/services/service_manager/tests/BUILD.gn
+++ b/services/service_manager/tests/BUILD.gn
@@ -26,11 +26,9 @@
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//services/catalog:lib",
-    "//services/catalog:unittests",
     "//services/service_manager",
     "//services/service_manager/background:lib",
     "//services/service_manager/background/tests:unittests",
-    "//services/service_manager/embedder:unittests",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp:unittests",
     "//services/service_manager/public/cpp/test:test_support",
diff --git a/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc b/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc
index e922c84..6927e6c8 100644
--- a/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc
+++ b/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc
@@ -103,7 +103,8 @@
 class ServiceManagerListenerTest : public testing::Test, public Service {
  public:
   ServiceManagerListenerTest()
-      : service_manager_(nullptr, GetTestManifests(), nullptr) {}
+      : service_manager_(nullptr, GetTestManifests()) {}
+
   ~ServiceManagerListenerTest() override = default;
 
   Connector* connector() { return service_binding_.GetConnector(); }
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
index 6e932e4..8175112 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
@@ -32,7 +32,6 @@
   out->content_source_id = data.content_source_id();
   out->frame_token = data.frame_token();
   out->send_frame_token_to_embedder = data.send_frame_token_to_embedder();
-  out->request_presentation_feedback = data.request_presentation_feedback();
   out->root_background_color = data.root_background_color();
   out->min_page_scale_factor = data.min_page_scale_factor();
   out->top_controls_height = data.top_controls_height();
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
index c63c28c..4c1f33e 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
+++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
@@ -92,11 +92,6 @@
     return metadata.send_frame_token_to_embedder;
   }
 
-  static bool request_presentation_feedback(
-      const viz::CompositorFrameMetadata& metadata) {
-    return metadata.request_presentation_feedback;
-  }
-
   static float min_page_scale_factor(
       const viz::CompositorFrameMetadata& metadata) {
     return metadata.min_page_scale_factor;
diff --git a/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom b/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
index 2b09a55..c5ebc770 100644
--- a/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
+++ b/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
@@ -30,7 +30,6 @@
   BeginFrameAck begin_frame_ack;
   uint32 frame_token;
   bool send_frame_token_to_embedder;
-  bool request_presentation_feedback;
 
   float min_page_scale_factor;
 
diff --git a/third_party/arcore-android-sdk/BUILD.gn b/third_party/arcore-android-sdk/BUILD.gn
index 9f7d9e4..c6b23c1 100644
--- a/third_party/arcore-android-sdk/BUILD.gn
+++ b/third_party/arcore-android-sdk/BUILD.gn
@@ -4,6 +4,12 @@
 
 import("//build/config/android/rules.gni")
 
+java_prebuilt("libdynamite_client_java") {
+  supports_android = true
+  proguard_configs = [ "proguard-arcore.txt" ]
+  jar_path = "libarcore_client_c.jar"
+}
+
 config("libarcore_config") {
   include_dirs = [ "src/libraries/include/" ]
 }
diff --git a/third_party/arcore-android-sdk/README.chromium b/third_party/arcore-android-sdk/README.chromium
index 86ba41a..1d04387 100644
--- a/third_party/arcore-android-sdk/README.chromium
+++ b/third_party/arcore-android-sdk/README.chromium
@@ -1,7 +1,8 @@
 Name: ARCore SDK
 Short Name: arcore
 URL: https://github.com/google-ar/arcore-android-sdk
-Version: 1.5
+Version: 1.1
+Date: 19 March 2018
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
@@ -11,7 +12,11 @@
 devices.
 
 Local Modifications:
-Added BUILD.gn for compilation in chrome.
+To address binary size concerns, we are using a minimal shim produced for
+Chromium that is not publicly distributed elsewhere. We have also stripped the
+.so's to minimize their size.
+
+Also, added BUILD.gn for compilation in chrome.
 
 Added the test-apks/ subdirectory for storing production versions of AR APKs,
 namely ArCore, for testing.
@@ -24,8 +29,6 @@
  * https://github.com/google-ar/arcore-unity-sdk/blob/master/LICENSE
 
 Changes:
-2018-12-11 - Upgrade ARCore to v1.5. Remove checked in .so files - we now
-             extract them from ARCore's .aar file at build time.
 2018-12-11 - Upgrade test-apks/arcore_current.apk to v1.6.
 2018-09-14 - Upgrade test-apks/arcore_current.apk to v1.4.
 2018-08-10 - First, removed arcore shim copy target from BUILD.gn since it is no
diff --git a/third_party/arcore-android-sdk/libarcore_client_c.jar b/third_party/arcore-android-sdk/libarcore_client_c.jar
new file mode 100644
index 0000000..335fe92
--- /dev/null
+++ b/third_party/arcore-android-sdk/libarcore_client_c.jar
Binary files differ
diff --git a/third_party/arcore-android-sdk/libarcore_dummy.so b/third_party/arcore-android-sdk/libarcore_dummy.so
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/arcore-android-sdk/libarcore_dummy.so
diff --git a/third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so b/third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so
new file mode 100755
index 0000000..ce3ab2df
--- /dev/null
+++ b/third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so
Binary files differ
diff --git a/third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so b/third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so
new file mode 100755
index 0000000..cfd9654f
--- /dev/null
+++ b/third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so
Binary files differ
diff --git a/third_party/arcore-android-sdk/proguard-arcore.txt b/third_party/arcore-android-sdk/proguard-arcore.txt
new file mode 100644
index 0000000..b1c85042
--- /dev/null
+++ b/third_party/arcore-android-sdk/proguard-arcore.txt
@@ -0,0 +1,41 @@
+# Keep ARCore public-facing classes
+-keepparameternames
+-renamesourcefileattribute SourceFile
+
+# These are part of the Java <-> native interfaces for ARCore.
+-keepclasseswithmembernames,includedescriptorclasses class com.google.ar.** {
+    native <methods>;
+}
+
+-keep public class com.google.ar.core.** {*;}
+
+-keep class com.google.ar.core.annotations.UsedByNative
+-keep @com.google.ar.core.annotations.UsedByNative class *
+-keepclassmembers class * {
+    @com.google.ar.core.annotations.UsedByNative *;
+}
+
+-keep class com.google.ar.core.annotations.UsedByReflection
+-keep @com.google.ar.core.annotations.UsedByReflection class *
+-keepclassmembers class * {
+    @com.google.ar.core.annotations.UsedByReflection *;
+}
+# Keep Dynamite classes
+
+# .aidl file will be proguarded, we should keep all Aidls.
+-keep class com.google.vr.dynamite.client.IObjectWrapper { *; }
+-keep class com.google.vr.dynamite.client.ILoadedInstanceCreator { *; }
+-keep class com.google.vr.dynamite.client.INativeLibraryLoader { *; }
+
+# Keep annotation files and the file got annotated.
+-keep class com.google.vr.dynamite.client.UsedByNative
+-keep @com.google.vr.dynamite.client.UsedByNative class *
+-keepclassmembers class * {
+    @com.google.vr.dynamite.client.UsedByNative *;
+}
+
+-keep class com.google.vr.dynamite.client.UsedByReflection
+-keep @com.google.vr.dynamite.client.UsedByReflection class *
+-keepclassmembers class * {
+    @com.google.vr.dynamite.client.UsedByReflection *;
+}
diff --git a/third_party/blink/public/web/web_navigation_control.h b/third_party/blink/public/web/web_navigation_control.h
index 5492cba..271c97bb 100644
--- a/third_party/blink/public/web/web_navigation_control.h
+++ b/third_party/blink/public/web/web_navigation_control.h
@@ -17,6 +17,7 @@
 class WebURL;
 struct WebURLError;
 class WebHistoryItem;
+struct WebNavigationInfo;
 struct WebNavigationParams;
 
 // This interface gives control to navigation-related functionality of
@@ -92,8 +93,7 @@
   // is actually being handled by the client.
   // TODO(dgozman): remove this together with placeholder document loader.
   virtual bool CreatePlaceholderDocumentLoader(
-      std::unique_ptr<WebNavigationParams>,
-      WebNavigationType,
+      const WebNavigationInfo&,
       std::unique_ptr<WebDocumentLoader::ExtraData>) = 0;
 
  protected:
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 5e631a67..d58b177 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -139,8 +139,8 @@
 }
 
 ScriptPromise DisplayLockContext::update(ScriptState* script_state) {
-  // Reject if we're unlocked.
-  if (state_ == kUnlocked)
+  // Reject if we're unlocked or disconnected.
+  if (state_ == kUnlocked || !element_->isConnected())
     return GetRejectedPromise(script_state);
 
   // If we have a resolver, then we're at least updating already, just return
@@ -151,16 +151,13 @@
   }
 
   update_resolver_ = ScriptPromiseResolver::Create(script_state);
-  // We only need to kick off an Update if we're in a locked state, all other
-  // states are already updating.
-  if (state_ == kLocked)
-    StartUpdate();
+  StartUpdateIfNeeded();
   return update_resolver_->Promise();
 }
 
 ScriptPromise DisplayLockContext::commit(ScriptState* script_state) {
-  // Reject if we're unlocked.
-  if (state_ == kUnlocked)
+  // Reject if we're unlocked or disonnected.
+  if (state_ == kUnlocked || !element_->isConnected())
     return GetRejectedPromise(script_state);
 
   // If we have a resolver, we must be committing already, just return the same
@@ -391,12 +388,19 @@
       layout_invalidation_reason::kDisplayLockCommitting);
 }
 
-void DisplayLockContext::StartUpdate() {
-  DCHECK_EQ(state_, kLocked);
-  state_ = kUpdating;
+void DisplayLockContext::StartUpdateIfNeeded() {
+  // We should not be calling this if we're unlocked.
+  DCHECK_NE(state_, kUnlocked);
+  // Any state other than kLocked means that we are already in the process of
+  // updating/committing, so we can piggy back on that process without kicking
+  // off any new updates.
+  if (state_ != kLocked)
+    return;
+
   // We don't need to mark anything dirty since the budget will take care of
   // that for us.
   update_budget_ = CreateNewBudget();
+  state_ = kUpdating;
   ScheduleAnimation();
 }
 
@@ -509,6 +513,8 @@
 }
 
 void DisplayLockContext::ScheduleAnimation() {
+  DCHECK(element_->isConnected());
+
   // Schedule an animation to perform the lifecycle phases.
   element_->GetDocument().GetPage()->Animator().ScheduleVisualUpdate(
       element_->GetDocument().GetFrame());
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index b8956f9..06c767c 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -149,7 +149,7 @@
   // Initiate a commit.
   void StartCommit();
   // Initiate an update.
-  void StartUpdate();
+  void StartUpdateIfNeeded();
 
   // The following functions propagate dirty bits from the locked element up to
   // the ancestors in order to be reached. They return true if the element or
diff --git a/third_party/blink/renderer/core/editing/commands/editor_command.cc b/third_party/blink/renderer/core/editing/commands/editor_command.cc
index 2e631eeb..ccb6ef7 100644
--- a/third_party/blink/renderer/core/editing/commands/editor_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/editor_command.cc
@@ -60,6 +60,7 @@
 #include "third_party/blink/renderer/core/editing/visible_position.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/html_br_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -1185,6 +1186,13 @@
   if (Node* root = HighestEditableRoot(selection.Start())) {
     if (!root->hasChildren())
       return false;
+
+    // When the editable contains a BR only, it appears as an empty line, in
+    // which case allowing select-all confuses users.
+    if (root->firstChild() == root->lastChild() &&
+        IsHTMLBRElement(root->firstChild()))
+      return false;
+
     // TODO(amaralp): Return false if already fully selected.
   }
   // TODO(amaralp): Address user-select handling.
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index cb3816c..72d0d17 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -12538,9 +12538,7 @@
       TestWebFrameClient::BeginNavigation(std::move(info));
       return;
     }
-    Frame()->CreatePlaceholderDocumentLoader(
-        WebNavigationParams::CreateFromInfo(*info), info->navigation_type,
-        nullptr /* extra_data */);
+    Frame()->CreatePlaceholderDocumentLoader(*info, nullptr /* extra_data */);
   }
 
  private:
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index f9d1baf5..bca23d8 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2195,13 +2195,12 @@
 }
 
 bool WebLocalFrameImpl::CreatePlaceholderDocumentLoader(
-    std::unique_ptr<WebNavigationParams> navigation_params,
-    WebNavigationType navigation_type,
+    const WebNavigationInfo& info,
     std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
-  DCHECK(!navigation_params->request.IsNull());
-  DCHECK(!navigation_params->request.Url().ProtocolIs("javascript"));
+  DCHECK(!info.url_request.IsNull());
+  DCHECK(!info.url_request.Url().ProtocolIs("javascript"));
   return GetFrame()->Loader().CreatePlaceholderDocumentLoader(
-      std::move(navigation_params), navigation_type, std::move(extra_data));
+      info, std::move(extra_data));
 }
 
 void WebLocalFrameImpl::SendOrientationChangeEvent() {
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index ca6ec16..99644b9 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -319,8 +319,7 @@
   void ClientDroppedNavigation() override;
   void MarkAsLoading() override;
   bool CreatePlaceholderDocumentLoader(
-      std::unique_ptr<WebNavigationParams>,
-      WebNavigationType,
+      const WebNavigationInfo&,
       std::unique_ptr<WebDocumentLoader::ExtraData>) override;
 
   void InitializeCoreFrame(Page&, FrameOwner*, const AtomicString& name);
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_host.cc b/third_party/blink/renderer/core/inspector/dev_tools_host.cc
index 64c10cbf..4b454e0 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_host.cc
+++ b/third_party/blink/renderer/core/inspector/dev_tools_host.cc
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
 #include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
 #include "third_party/blink/renderer/core/inspector/inspector_frontend_client.h"
-#include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
@@ -214,27 +213,6 @@
   }
 }
 
-String DevToolsHost::getSelectionBackgroundColor() {
-  return LayoutTheme::GetTheme().ActiveSelectionBackgroundColor().Serialized();
-}
-
-String DevToolsHost::getSelectionForegroundColor() {
-  return LayoutTheme::GetTheme().ActiveSelectionForegroundColor().Serialized();
-}
-
-String DevToolsHost::getInactiveSelectionBackgroundColor() {
-  return LayoutTheme::GetTheme()
-      .InactiveSelectionBackgroundColor()
-      .Serialized();
-}
-
-String DevToolsHost::getInactiveSelectionForegroundColor() {
-  return LayoutTheme::GetTheme()
-      .InactiveSelectionForegroundColor()
-      .Serialized();
-}
-
-
 bool DevToolsHost::isHostedMode() {
   return false;
 }
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_host.h b/third_party/blink/renderer/core/inspector/dev_tools_host.h
index 7e47396..8f35f29 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_host.h
+++ b/third_party/blink/renderer/core/inspector/dev_tools_host.h
@@ -69,11 +69,6 @@
                        WebVector<WebMenuItemInfo> items);
   void sendMessageToEmbedder(const String& message);
 
-  String getSelectionBackgroundColor();
-  String getSelectionForegroundColor();
-  String getInactiveSelectionBackgroundColor();
-  String getInactiveSelectionForegroundColor();
-
   bool isHostedMode();
 
   LocalFrame* FrontendFrame() { return frontend_frame_; }
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_host.idl b/third_party/blink/renderer/core/inspector/dev_tools_host.idl
index cd4481da..1586096 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_host.idl
+++ b/third_party/blink/renderer/core/inspector/dev_tools_host.idl
@@ -41,10 +41,5 @@
     [Custom] void showContextMenuAtPoint(float x, float y, any items, optional Document document);
     void sendMessageToEmbedder(DOMString message);
 
-    DOMString getSelectionBackgroundColor();
-    DOMString getSelectionForegroundColor();
-    DOMString getInactiveSelectionBackgroundColor();
-    DOMString getInactiveSelectionForegroundColor();
-
     boolean isHostedMode();
 };
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 697a18b..ee8a02e 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -1121,8 +1121,7 @@
 }
 
 bool FrameLoader::CreatePlaceholderDocumentLoader(
-    std::unique_ptr<WebNavigationParams> navigation_params,
-    WebNavigationType navigation_type,
+    const WebNavigationInfo& info,
     std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
   if (!CancelProvisionalLoaderForNewNavigation(
           true /* cancel_scheduled_navigations */,
@@ -1130,8 +1129,14 @@
     return false;
   }
 
-  provisional_document_loader_ = CreateDocumentLoader(
-      navigation_type, std::move(navigation_params), std::move(extra_data));
+  auto navigation_params = std::make_unique<WebNavigationParams>();
+  navigation_params->request = info.url_request;
+  navigation_params->frame_load_type = info.frame_load_type;
+  navigation_params->is_client_redirect = info.is_client_redirect;
+  navigation_params->navigation_timings.input_start = info.input_start;
+  provisional_document_loader_ =
+      CreateDocumentLoader(info.navigation_type, std::move(navigation_params),
+                           std::move(extra_data));
   provisional_document_loader_->AppendRedirect(
       provisional_document_loader_->Url());
   frame_->GetFrameScheduler()->DidStartProvisionalLoad(frame_->IsMainFrame());
diff --git a/third_party/blink/renderer/core/loader/frame_loader.h b/third_party/blink/renderer/core/loader/frame_loader.h
index e284aba..b2bb56586 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/third_party/blink/renderer/core/loader/frame_loader.h
@@ -66,6 +66,7 @@
 class SerializedScriptValue;
 class TracedValue;
 struct FrameLoadRequest;
+struct WebNavigationInfo;
 struct WebNavigationParams;
 
 namespace mojom {
@@ -125,8 +126,7 @@
   // lives temporarily so that the rest of Blink code knows the navigation
   // is in place.
   bool CreatePlaceholderDocumentLoader(
-      std::unique_ptr<WebNavigationParams>,
-      WebNavigationType,
+      const WebNavigationInfo&,
       std::unique_ptr<WebDocumentLoader::ExtraData>);
 
   // This runs the "stop document loading" algorithm in HTML:
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 38f5047..d58c79e 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -1019,6 +1019,11 @@
   // Now hit test ourselves.
   if (hit_test_self && VisibleToHitTestRequest(result.GetHitTestRequest())) {
     LayoutRect bounds_rect(physical_offset, size);
+    if (UNLIKELY(result.GetHitTestRequest().GetType() &
+                 HitTestRequest::kHitTestVisualOverflow)) {
+      bounds_rect = PhysicalFragment().SelfInkOverflow().ToLayoutRect();
+      bounds_rect.MoveBy(physical_offset);
+    }
     if (location_in_container.Intersects(bounds_rect)) {
       Node* node = box_fragment_.NodeForHitTest();
       if (!result.InnerNode() && node) {
@@ -1067,6 +1072,12 @@
 
   // TODO(layout-dev): Clip to line-top/bottom.
   LayoutRect rect = LayoutRect(PixelSnappedIntRect(border_rect));
+  if (UNLIKELY(result.GetHitTestRequest().GetType() &
+               HitTestRequest::kHitTestVisualOverflow)) {
+    rect = text_paint_fragment.SelfInkOverflow();
+    rect.MoveBy(border_rect.Location());
+  }
+
   if (FragmentVisibleToHitTestRequest(text_paint_fragment,
                                       result.GetHitTestRequest()) &&
       location_in_container.Intersects(rect)) {
diff --git a/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js b/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js
index 7627ba2..010108b 100644
--- a/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js
+++ b/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js
@@ -320,35 +320,31 @@
    */
   const InspectorFrontendHostImpl = class {
     /**
-     * @override
      * @return {string}
      */
     getSelectionBackgroundColor() {
-      return DevToolsHost.getSelectionBackgroundColor();
+      return '#6e86ff';
     }
 
     /**
-     * @override
      * @return {string}
      */
     getSelectionForegroundColor() {
-      return DevToolsHost.getSelectionForegroundColor();
+      return '#ffffff';
     }
 
     /**
-     * @override
      * @return {string}
      */
     getInactiveSelectionBackgroundColor() {
-      return DevToolsHost.getInactiveSelectionBackgroundColor();
+      return '#c9c8c8';
     }
 
     /**
-     * @override
      * @return {string}
      */
     getInactiveSelectionForegroundColor() {
-      return DevToolsHost.getInactiveSelectionForegroundColor();
+      return '#323232';
     }
 
     /**
diff --git a/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css b/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css
index 78d8f5a..31e1a8f 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css
+++ b/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css
@@ -36,11 +36,6 @@
 
 .elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected .selected-hint:before {
     opacity: 0.6;
-    color: var(--selection-inactive-fg-color);
-}
-
-.elements-disclosure li.selected:focus .selected-hint:before {
-    color: var(--selection-fg-color);
 }
 
 .elements-disclosure li.parent::before {
@@ -94,7 +89,7 @@
 }
 
 .elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) .selection {
-    background-color: var(--selection-inactive-bg-color);
+    background-color: var(--editor-selection-inactive-bg-color);
 }
 
 .elements-disclosure .elements-tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] .highlight > * {
@@ -131,20 +126,8 @@
     padding-left: 2px;
 }
 
-.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus {
-    color: var(--selection-fg-color);
-}
-
-.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.parent.selected:focus::before {
-    background-color: var(--selection-fg-color);
-}
-
-.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus * {
-    color: inherit;
-}
-
 .elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .selection {
-    background-color: var(--selection-bg-color);
+    background-color: var(--editor-selection-bg-color);
 }
 
 .elements-tree-outline ol.shadow-root-depth-4 {
@@ -308,13 +291,6 @@
     display: none;
 }
 
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .webkit-html-tag-name,
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .webkit-html-close-tag-name,
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .webkit-html-attribute-value,
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .devtools-link {
-    color: var(--selection-fg-color);
-}
-
 .elements-disclosure .gutter-container {
     position: absolute;
     top: 0;
diff --git a/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js b/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js
index 3a5bc6c..06d4a8f 100644
--- a/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js
+++ b/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js
@@ -56,38 +56,6 @@
    * @override
    * @return {string}
    */
-  getSelectionBackgroundColor() {
-    return '#6e86ff';
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  getSelectionForegroundColor() {
-    return '#ffffff';
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  getInactiveSelectionBackgroundColor() {
-    return '#c9c8c8';
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  getInactiveSelectionForegroundColor() {
-    return '#323232';
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
   platform() {
     let match = navigator.userAgent.match(/Windows NT/);
     if (match)
diff --git a/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js b/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js
index 93b1dc5..def2675 100644
--- a/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js
+++ b/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -110,26 +110,6 @@
   indexPath(requestId, fileSystemPath, excludedFolders) {},
 
   /**
-   * @return {string}
-   */
-  getSelectionBackgroundColor() {},
-
-  /**
-   * @return {string}
-   */
-  getSelectionForegroundColor() {},
-
-  /**
-   * @return {string}
-   */
-  getInactiveSelectionBackgroundColor() {},
-
-  /**
-   * @return {string}
-   */
-  getInactiveSelectionForegroundColor() {},
-
-  /**
    * Requests inspected page to be placed atop of the inspector frontend with specified bounds.
    * @param {{x: number, y: number, width: number, height: number}} bounds
    */
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js
index 6f1c7e5..76abe4fa 100644
--- a/third_party/blink/renderer/devtools/front_end/main/Main.js
+++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -152,7 +152,7 @@
 
     Runtime.experiments.setDefaultExperiments([
       'colorContrastRatio', 'stepIntoAsync', 'oopifInlineDOM', 'consoleBelowPrompt', 'timelineTracingJSProfile',
-      'pinnedExpressions', 'consoleKeyboardNavigation'
+      'pinnedExpressions', 'consoleKeyboardNavigation', 'sourcesLogpoints'
     ]);
   }
 
diff --git a/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js b/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
index c98cc69..3c13460 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
+++ b/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
@@ -19,6 +19,7 @@
     /** @type {?UI.TextEditor} */
     this._editor = null;
     const isNewBreakpointsEnabled = Runtime.experiments.isEnabled('sourcesLogpoints');
+    this.element.tabIndex = -1;
 
     const logpointPrefix = Sources.BreakpointEditDialog._LogpointPrefix;
     const logpointSuffix = Sources.BreakpointEditDialog._LogpointSuffix;
diff --git a/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css b/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css
index e2ec0db..154d0a0 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css
+++ b/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css
@@ -38,12 +38,11 @@
   border-radius: 0;
   z-index: 30;
   background-color: var(--toolbar-bg-color);
-  width: 100%;
-  max-width: 600px;
+  width: 555px;
   pointer-events: auto;
-  margin-bottom: 5px;
+  margin: 2px 0 2px -1px;
   padding: 0 10px 10px 5px;
-  border-left: 3px solid var(--divider-color);
+  border: 1px solid var(--divider-color);
 }
 
 :host-context(.sources-edit-breakpoint-dialog) .condition-editor {
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
index 64670ab..1335b70 100644
--- a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
+++ b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
@@ -42,8 +42,6 @@
     this.registerRequiredCSS('cm/codemirror.css');
     this.registerRequiredCSS('text_editor/cmdevtools.css');
 
-    TextEditor.CodeMirrorUtils.appendThemeStyle(this.element);
-
     this._codeMirror = new CodeMirror(this.element, {
       lineNumbers: options.lineNumbers,
       matchBrackets: true,
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js
index 770ad2a..2ad76a5 100644
--- a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js
+++ b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js
@@ -89,46 +89,6 @@
 };
 
 /**
- * @param {!Element} element
- */
-TextEditor.CodeMirrorUtils.appendThemeStyle = function(element) {
-  if (UI.themeSupport.hasTheme())
-    return;
-
-  const backgroundColor = InspectorFrontendHost.getSelectionBackgroundColor();
-  const foregroundColor = InspectorFrontendHost.getSelectionForegroundColor();
-  const inactiveBackgroundColor = InspectorFrontendHost.getInactiveSelectionBackgroundColor();
-  const inactiveForegroundColor = InspectorFrontendHost.getInactiveSelectionForegroundColor();
-  const style = createElement('style');
-  style.textContent = `
-    .CodeMirror .CodeMirror-selected {
-      background-color: ${inactiveBackgroundColor};
-    }
-
-    .CodeMirror .CodeMirror-selectedtext:not(.CodeMirror-persist-highlight) {
-      color: ${inactiveForegroundColor} !important;
-    }
-
-    .CodeMirror-focused .CodeMirror-selected {
-      background-color: ${backgroundColor};
-    }
-
-    .CodeMirror-focused .CodeMirror-selectedtext:not(.CodeMirror-persist-highlight) {
-      color: ${foregroundColor} !important;
-    }
-
-    .CodeMirror .CodeMirror-line::selection,
-    .CodeMirror .CodeMirror-line > span::selection,
-    .CodeMirror .CodeMirror-line > span > span::selection {
-      background: ${backgroundColor};
-      color: ${foregroundColor} !important;
-    }
-  `;
-  element.appendChild(style);
-};
-
-
-/**
  * @implements {TextUtils.TokenizerFactory}
  * @unrestricted
  */
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css b/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
index 97f3383..c690f4e1 100644
--- a/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
+++ b/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
@@ -117,7 +117,7 @@
 }
 
 .pretty-printed .CodeMirror-linenumber {
-    color: var( --accent-color-b);
+    color: var(--accent-color);
 }
 
 .cm-highlight {
@@ -571,7 +571,7 @@
 }
 
 .pretty-printed .CodeMirror-linenumber {
-    color: var(--accent-color-b);
+    color: var(--accent-color);
 }
 
 .CodeMirror-foldmarker {
@@ -633,3 +633,17 @@
 .CodeMirror-foldgutter-folded::before {
     -webkit-mask-position: 0 0;
 }
+
+.CodeMirror .CodeMirror-selected {
+    background-color: var(--editor-selection-inactive-bg-color);
+}
+
+.CodeMirror-focused .CodeMirror-selected {
+    background-color: var(--editor-selection-bg-color);
+}
+
+.CodeMirror .CodeMirror-line::selection,
+.CodeMirror .CodeMirror-line > span::selection,
+.CodeMirror .CodeMirror-line > span > span::selection {
+    background: var(--editor-selection-bg-color);
+}
diff --git a/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css b/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
index 40892fe..1ab2d02 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
+++ b/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
@@ -420,3 +420,11 @@
 .expandable-inline-button:hover {
     background-color: #d5d5d5;
 }
+
+::selection {
+    background-color: #bbdefb;
+}
+
+.-theme-with-dark-background *::selection {
+    background-color: #9e9e9e;;
+}
diff --git a/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css b/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css
index eb057ad8..0475592 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css
+++ b/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css
@@ -33,9 +33,7 @@
 }
 
 :root {
-    --accent-color: #03a9f4;
-    --accent-color-b: #2196f3;
-    --accent-color-c: #3e82f7;
+    --accent-color: #42a5f5;
     --focus-bg-color: hsl(214, 40%, 92%);
     --toolbar-bg-color: #f3f3f3;
     --toolbar-hover-bg-color: #eaeaea;
@@ -48,12 +46,12 @@
                    0 2px 6px rgba(0, 0, 0, 0.1);
     --divider-color: #d0d0d0;
     --focus-ring-inactive-shadow: 0 0 0 1px #e0e0e0;
+    --editor-selection-bg-color: #cfe8fc;
+    --editor-selection-inactive-bg-color: #e0e0e0;
 }
 
 .-theme-with-dark-background {
-    --accent-color: #32699f;
-    --accent-color-b: #2f84da;
-    --accent-color-c: #1f4061;
+    --accent-color: #2f84da;
     --focus-bg-color: hsl(214, 19%, 27%);
     --toolbar-bg-color: #333333;
     --toolbar-hover-bg-color: #202020;
@@ -66,11 +64,13 @@
                    0 2px 6px 2px rgba(0, 0, 0, 0.1);
     --divider-color: #525252;
     --focus-ring-inactive-shadow: 0 0 0 1px #5a5a5a;
+    --editor-selection-bg-color: #454545;
+    --editor-selection-inactive-bg-color: #454545;
 }
 
 :root {
-    --focus-ring-active-shadow: 0 0 0 1px var(--accent-color);
-    --selection-bg-color: var(--accent-color-b);
+    --focus-ring-active-shadow: 0 0 0 1px #bef7ff;
+    --selection-bg-color: var(--accent-color);
     --divider-border: 1px solid var(--divider-color);
 }
 
diff --git a/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css b/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css
index fff72480..0e94772a 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css
+++ b/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css
@@ -246,7 +246,7 @@
     height: 2px;
     position: absolute;
     bottom: -1px;
-    background-color: #03a9f4;
+    background-color: var(--accent-color);
     left: 0;
     z-index: 50;
     transform-origin: 0 100%;
diff --git a/third_party/blink/renderer/devtools/front_end/ui/toolbar.css b/third_party/blink/renderer/devtools/front_end/ui/toolbar.css
index d45a3f95..4a9b6e2 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/toolbar.css
+++ b/third_party/blink/renderer/devtools/front_end/ui/toolbar.css
@@ -144,12 +144,12 @@
 .toolbar-button.toolbar-state-on .toolbar-glyph,
 .toolbar-blue-on-hover .toolbar-button:not(.toolbar-state-on):enabled:hover:not(:active),
 .-theme-selection-color {
-    background-color: var(--accent-color-b);
+    background-color: var(--accent-color);
 }
 
 .toolbar-button.toolbar-state-on .toolbar-text,
 .-theme-selection-color {
-    color: var(--accent-color-b);
+    color: var(--accent-color);
 }
 
 .toolbar-blue-on-hover .toolbar-button:not(.toolbar-state-on):enabled:hover .toolbar-glyph {
@@ -163,12 +163,12 @@
 .toolbar-button.toolbar-state-on:enabled:hover:not(:active) .toolbar-glyph,
 .toolbar-blue-on-hover .toolbar-button:not(.toolbar-state-on):enabled:active:hover,
 .-theme-selection-color {
-    background-color: var(--accent-color-b);
+    background-color: var(--accent-color);
 }
 
 .toolbar-button.toolbar-state-on:enabled:hover:not(:active) .toolbar-text,
 .-theme-selection-color {
-    color: var(--accent-color-b);
+    color: var(--accent-color);
 }
 
 .toolbar-toggled-gray .toolbar-button.toolbar-state-on {
diff --git a/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc b/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc
index 27f4931a..fff684f 100644
--- a/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc
+++ b/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc
@@ -240,8 +240,8 @@
 
   auto* ax_cell = cache->GetOrCreate(cell);
   EXPECT_TRUE(ax_cell->IsTableCellLikeRole());
-  EXPECT_EQ(8U, ax_cell->AriaColumnIndex());
-  EXPECT_EQ(5U, ax_cell->AriaRowIndex());
+  EXPECT_EQ(0U, ax_cell->AriaColumnIndex());
+  EXPECT_EQ(0U, ax_cell->AriaRowIndex());
 
   auto* ax_cell2 = cache->GetOrCreate(cell2);
   EXPECT_TRUE(ax_cell2->IsTableCellLikeRole());
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 5f62ae8..e87e766 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -2654,84 +2654,19 @@
 }
 
 unsigned AXObject::ComputeAriaColumnIndex() const {
-  if (!IsTableCellLikeRole())
-    return 0;
-
-  // First see if it has an ARIA column index explicitly set.
-  uint32_t col_index;
-  if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex, col_index) &&
-      col_index >= 1) {
-    return col_index;
-  }
-
-  // Get the previous sibling.
-  // TODO(dmazzoni): this code depends on the DOM; move this code out of Blink
-  // and make it more general.
-  AXObject* previous = nullptr;
-  if (GetNode()) {
-    Node* previousNode = ElementTraversal::PreviousSibling(*GetNode());
-    previous = AXObjectCache().GetOrCreate(previousNode);
-  }
-
-  // It has a previous sibling, so if that cell has a column index, this one's
-  // index is one greater.
-  if (previous) {
-    col_index = previous->AriaColumnIndex();
-    if (col_index)
-      return col_index + 1;
-    return 0;
-  }
-
-  // No previous cell, so check the row to see if it sets a column index.
-  const AXObject* row = TableRowParent();
-  if (!row)
-    return 0;
-  if (row->HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex,
-                                         col_index)) {
-    return col_index;
-  }
-
-  // Otherwise there's no ARIA column index.
-  return 0;
+  // Return the ARIA column index if it has been set. Otherwise return a default
+  // value of 0.
+  uint32_t col_index = 0;
+  HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex, col_index);
+  return col_index;
 }
 
 unsigned AXObject::ComputeAriaRowIndex() const {
-  if (!IsTableCellLikeRole() && !IsTableRowLikeRole())
-    return 0;
-
-  // First check if there's an ARIA row index explicitly set.
-  uint32_t row_index;
-  if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kRowIndex, row_index) &&
-      row_index >= 1) {
-    return row_index;
-  }
-
-  // If this is a cell, return the ARIA row index of the containing row.
-  if (IsTableCellLikeRole()) {
-    const AXObject* row = TableRowParent();
-    if (row)
-      return row->AriaRowIndex();
-    return 0;
-  }
-
-  // Otherwise, this is a row. Find the previous sibling row.
-  // TODO(dmazzoni): this code depends on the DOM; move this code out of Blink
-  // and make it more general.
-  if (!GetNode())
-    return 0;
-  Node* previousNode = ElementTraversal::PreviousSibling(*GetNode());
-  AXObject* previous = AXObjectCache().GetOrCreate(previousNode);
-  if (!previous || !previous->IsTableRowLikeRole())
-    return 0;
-
-  // If the previous row has an ARIA row index, this one is the same index
-  // plus one.
-  row_index = previous->AriaRowIndex();
-  if (row_index)
-    return row_index + 1;
-
-  // Otherwise there's no ARIA row index.
-  return 0;
+  // Return the ARIA row index if it has been set. Otherwise return a default
+  // value of 0.
+  uint32_t row_index = 0;
+  HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kRowIndex, row_index);
+  return row_index;
 }
 
 AXObject::AXObjectVector AXObject::TableRowChildren() const {
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
index 478a69ec..9d508a43 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
@@ -48,9 +48,6 @@
   }
   ResetPrefetchCache();
 
-  // Reset all cursor prefetch caches except for this cursor.
-  IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id_, this);
-
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
       std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
   cursor_->Advance(count, GetCallbacksProxy(std::move(callbacks_impl)));
@@ -94,9 +91,6 @@
     ResetPrefetchCache();
   }
 
-  // Reset all cursor prefetch caches except for this cursor.
-  IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id_, this);
-
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
       std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
   cursor_->CursorContinue(IDBKey::Clone(key), IDBKey::Clone(primary_key),
diff --git a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
index 21bb8db..41c03834 100644
--- a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
+++ b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
@@ -11,8 +11,9 @@
 namespace blink {
 
 /**
- * TraceWrapperV8Reference is used to trace from Blink to V8. The reference is
- * (strongly) traced by wrapper tracing.
+ * TraceWrapperV8Reference is used to hold references from Blink to V8 that are
+ * known to both garbage collectors. The reference is a regular traced reference
+ * for wrapper tracing as well as unified heap garbage collections.
  *
  * TODO(mlippautz): Use a better handle type than v8::Persistent.
  */
@@ -37,16 +38,6 @@
     handle_.SetWeak();
   }
 
-  template <typename P>
-  void Set(v8::Isolate* isolate,
-           v8::Local<T> handle,
-           P* parameters,
-           void (*callback)(const v8::WeakCallbackInfo<P>&),
-           v8::WeakCallbackType type = v8::WeakCallbackType::kParameter) {
-    InternalSet(isolate, handle);
-    handle_.SetWeak(parameters, callback, type);
-  }
-
   ALWAYS_INLINE v8::Local<T> NewLocal(v8::Isolate* isolate) const {
     return v8::Local<T>::New(isolate, handle_);
   }
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index 650d1f90..197d649 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -120,6 +120,7 @@
     "heap_test.cc",
     "heap_test_utilities.cc",
     "heap_test_utilities.h",
+    "heap_thread_test.cc",
     "heap_traits_test.cc",
     "incremental_marking_test.cc",
     "name_trait_test.cc",
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc
index 2120b6a..4b1c81e 100644
--- a/third_party/blink/renderer/platform/heap/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -5362,300 +5362,6 @@
   EXPECT_EQ(0u, map->size());
 }
 
-static Mutex& MainThreadMutex() {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, main_mutex, ());
-  return main_mutex;
-}
-
-static ThreadCondition& MainThreadCondition() {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadCondition, main_condition,
-                                  (MainThreadMutex()));
-  return main_condition;
-}
-
-static void ParkMainThread() {
-  MainThreadCondition().Wait();
-}
-
-static void WakeMainThread() {
-  MutexLocker locker(MainThreadMutex());
-  MainThreadCondition().Signal();
-}
-
-static Mutex& WorkerThreadMutex() {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, worker_mutex, ());
-  return worker_mutex;
-}
-
-static ThreadCondition& WorkerThreadCondition() {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadCondition, worker_condition,
-                                  (WorkerThreadMutex()));
-  return worker_condition;
-}
-
-static void ParkWorkerThread() {
-  WorkerThreadCondition().Wait();
-}
-
-static void WakeWorkerThread() {
-  MutexLocker locker(WorkerThreadMutex());
-  WorkerThreadCondition().Signal();
-}
-
-class ThreadedStrongificationTester {
- public:
-  static void Test() {
-    IntWrapper::destructor_calls_ = 0;
-
-    MutexLocker locker(MainThreadMutex());
-    std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
-        ThreadCreationParams(WebThreadType::kTestThread)
-            .SetThreadNameForTest("Test Worker Thread"));
-    PostCrossThreadTask(*worker_thread->GetTaskRunner(), FROM_HERE,
-                        CrossThreadBind(WorkerThreadMain));
-
-    // Wait for the worker thread initialization. The worker
-    // allocates a weak collection where both collection and
-    // contents are kept alive via persistent pointers.
-    ParkMainThread();
-
-    // Perform two garbage collections where the worker thread does
-    // not wake up in between. This will cause us to remove marks
-    // and mark unmarked objects dead. The collection on the worker
-    // heap is found through the persistent and the backing should
-    // be marked.
-    PreciselyCollectGarbage();
-    PreciselyCollectGarbage();
-
-    // Wake up the worker thread so it can continue. It will sweep
-    // and perform another GC where the backing store of its
-    // collection should be strongified.
-    WakeWorkerThread();
-
-    // Wait for the worker thread to sweep its heaps before checking.
-    ParkMainThread();
-  }
-
- private:
-  using WeakCollectionType =
-      HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper>>;
-
-  static WeakCollectionType* AllocateCollection() {
-    // Create a weak collection that is kept alive by a persistent
-    // and keep the contents alive with a persistents as
-    // well.
-    Persistent<IntWrapper> wrapper1 = IntWrapper::Create(32);
-    Persistent<IntWrapper> wrapper2 = IntWrapper::Create(32);
-    Persistent<IntWrapper> wrapper3 = IntWrapper::Create(32);
-    Persistent<IntWrapper> wrapper4 = IntWrapper::Create(32);
-    Persistent<IntWrapper> wrapper5 = IntWrapper::Create(32);
-    Persistent<IntWrapper> wrapper6 = IntWrapper::Create(32);
-    Persistent<WeakCollectionType> weak_collection =
-        MakeGarbageCollected<WeakCollectionType>();
-    weak_collection->insert(wrapper1, wrapper1);
-    weak_collection->insert(wrapper2, wrapper2);
-    weak_collection->insert(wrapper3, wrapper3);
-    weak_collection->insert(wrapper4, wrapper4);
-    weak_collection->insert(wrapper5, wrapper5);
-    weak_collection->insert(wrapper6, wrapper6);
-
-    // Signal the main thread that the worker is done with its allocation.
-    WakeMainThread();
-
-    // Wait for the main thread to do two GCs without sweeping
-    // this thread heap.
-    ParkWorkerThread();
-
-    return weak_collection;
-  }
-
-  static void WorkerThreadMain() {
-    MutexLocker locker(WorkerThreadMutex());
-
-    ThreadState::AttachCurrentThread();
-
-    {
-      Persistent<WeakCollectionType> collection = AllocateCollection();
-      {
-        // Prevent weak processing with an iterator and GC.
-        WeakCollectionType::iterator it = collection->begin();
-        ConservativelyCollectGarbage();
-
-        // The backing should be strongified because of the iterator.
-        EXPECT_EQ(6u, collection->size());
-        EXPECT_EQ(32, it->value->Value());
-      }
-
-      // Disregarding the iterator but keeping the collection alive
-      // with a persistent should lead to weak processing.
-      PreciselyCollectGarbage();
-      EXPECT_EQ(0u, collection->size());
-    }
-
-    WakeMainThread();
-    ThreadState::DetachCurrentThread();
-  }
-
-  static volatile uintptr_t worker_object_pointer_;
-};
-
-#if defined(THREAD_SANITIZER)
-// https://crbug.com/915200
-#define MAYBE_ThreadedStrongification DISABLED_ThreadedStrongification
-#else
-#define MAYBE_ThreadedStrongification ThreadedStrongification
-#endif
-
-TEST(HeapTest, MAYBE_ThreadedStrongification) {
-  ThreadedStrongificationTester::Test();
-}
-
-class MemberSameThreadCheckTester {
- public:
-  void Test() {
-    IntWrapper::destructor_calls_ = 0;
-
-    MutexLocker locker(MainThreadMutex());
-    std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
-        ThreadCreationParams(WebThreadType::kTestThread)
-            .SetThreadNameForTest("Test Worker Thread"));
-    PostCrossThreadTask(
-        *worker_thread->GetTaskRunner(), FROM_HERE,
-        CrossThreadBind(&MemberSameThreadCheckTester::WorkerThreadMain,
-                        CrossThreadUnretained(this)));
-
-    ParkMainThread();
-  }
-
- private:
-  Member<IntWrapper> wrapper_;
-
-  void WorkerThreadMain() {
-    MutexLocker locker(WorkerThreadMutex());
-
-    ThreadState::AttachCurrentThread();
-
-    // Setting an object created on the worker thread to a Member allocated on
-    // the main thread is not allowed.
-    wrapper_ = IntWrapper::Create(42);
-
-    WakeMainThread();
-    ThreadState::DetachCurrentThread();
-  }
-};
-
-#if DCHECK_IS_ON()
-// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
-// crbug.com/709069
-#if !defined(OS_MACOSX)
-TEST(HeapDeathTest, MemberSameThreadCheck) {
-  EXPECT_DEATH(MemberSameThreadCheckTester().Test(), "");
-}
-#endif
-#endif
-
-class PersistentSameThreadCheckTester {
- public:
-  void Test() {
-    IntWrapper::destructor_calls_ = 0;
-
-    MutexLocker locker(MainThreadMutex());
-    std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
-        ThreadCreationParams(WebThreadType::kTestThread)
-            .SetThreadNameForTest("Test Worker Thread"));
-    PostCrossThreadTask(
-        *worker_thread->GetTaskRunner(), FROM_HERE,
-        CrossThreadBind(&PersistentSameThreadCheckTester::WorkerThreadMain,
-                        CrossThreadUnretained(this)));
-
-    ParkMainThread();
-  }
-
- private:
-  Persistent<IntWrapper> wrapper_;
-
-  void WorkerThreadMain() {
-    MutexLocker locker(WorkerThreadMutex());
-
-    ThreadState::AttachCurrentThread();
-
-    // Setting an object created on the worker thread to a Persistent allocated
-    // on the main thread is not allowed.
-    wrapper_ = IntWrapper::Create(42);
-
-    WakeMainThread();
-    ThreadState::DetachCurrentThread();
-  }
-};
-
-#if DCHECK_IS_ON()
-// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
-// crbug.com/709069
-#if !defined(OS_MACOSX)
-TEST(HeapDeathTest, PersistentSameThreadCheck) {
-  EXPECT_DEATH(PersistentSameThreadCheckTester().Test(), "");
-}
-#endif
-#endif
-
-class MarkingSameThreadCheckTester {
- public:
-  void Test() {
-    IntWrapper::destructor_calls_ = 0;
-
-    MutexLocker locker(MainThreadMutex());
-    std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
-        ThreadCreationParams(WebThreadType::kTestThread)
-            .SetThreadNameForTest("Test Worker Thread"));
-    Persistent<MainThreadObject> main_thread_object =
-        MakeGarbageCollected<MainThreadObject>();
-    PostCrossThreadTask(
-        *worker_thread->GetTaskRunner(), FROM_HERE,
-        CrossThreadBind(&MarkingSameThreadCheckTester::WorkerThreadMain,
-                        CrossThreadUnretained(this),
-                        WrapCrossThreadPersistent(main_thread_object.Get())));
-    ParkMainThread();
-    // This will try to mark MainThreadObject when it tries to mark IntWrapper
-    // it should crash.
-    PreciselyCollectGarbage();
-  }
-
- private:
-  class MainThreadObject : public GarbageCollectedFinalized<MainThreadObject> {
-   public:
-    void Trace(blink::Visitor* visitor) { visitor->Trace(wrapper_set_); }
-    void AddToSet(IntWrapper* wrapper) { wrapper_set_.insert(42, wrapper); }
-
-   private:
-    HeapHashMap<int, Member<IntWrapper>> wrapper_set_;
-  };
-
-  void WorkerThreadMain(MainThreadObject* main_thread_object) {
-    MutexLocker locker(WorkerThreadMutex());
-
-    ThreadState::AttachCurrentThread();
-
-    // Adding a reference to an object created on the worker thread to a
-    // HeapHashMap created on the main thread is not allowed.
-    main_thread_object->AddToSet(IntWrapper::Create(42));
-
-    WakeMainThread();
-    ThreadState::DetachCurrentThread();
-  }
-};
-
-#if DCHECK_IS_ON()
-// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
-// crbug.com/709069
-#if !defined(OS_MACOSX)
-TEST(HeapDeathTest, MarkingSameThreadCheck) {
-  // This will crash during marking, at the DCHECK in Visitor::markHeader() or
-  // earlier.
-  EXPECT_DEATH(MarkingSameThreadCheckTester().Test(), "");
-}
-#endif
-#endif
-
 static bool AllocateAndReturnBool() {
   ConservativelyCollectGarbage();
   return true;
@@ -5714,24 +5420,6 @@
   a->Verify();
 }
 
-class DestructorLockingObject
-    : public GarbageCollectedFinalized<DestructorLockingObject> {
- public:
-  static DestructorLockingObject* Create() {
-    return MakeGarbageCollected<DestructorLockingObject>();
-  }
-
-  DestructorLockingObject() = default;
-  virtual ~DestructorLockingObject() {
-    ++destructor_calls_;
-  }
-
-  static int destructor_calls_;
-  void Trace(blink::Visitor* visitor) {}
-};
-
-int DestructorLockingObject::destructor_calls_ = 0;
-
 template <typename T>
 class TraceIfNeededTester
     : public GarbageCollectedFinalized<TraceIfNeededTester<T>> {
@@ -6369,78 +6057,6 @@
 
 namespace {
 
-void WorkerThreadMainForCrossThreadWeakPersistentTest(
-    DestructorLockingObject** object) {
-  // Step 2: Create an object and store the pointer.
-  MutexLocker locker(WorkerThreadMutex());
-  ThreadState::AttachCurrentThread();
-  *object = DestructorLockingObject::Create();
-  WakeMainThread();
-  ParkWorkerThread();
-
-  // Step 4: Run a GC.
-  ThreadState::Current()->CollectGarbage(
-      BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
-      BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
-  WakeMainThread();
-  ParkWorkerThread();
-
-  // Step 6: Finish.
-  ThreadState::DetachCurrentThread();
-  WakeMainThread();
-}
-
-}  // anonymous namespace
-
-#if defined(THREAD_SANITIZER)
-// https://crbug.com/915200
-#define MAYBE_CrossThreadWeakPersistent DISABLED_CrossThreadWeakPersistent
-#else
-#define MAYBE_CrossThreadWeakPersistent CrossThreadWeakPersistent
-#endif
-
-TEST(HeapTest, MAYBE_CrossThreadWeakPersistent) {
-  // Create an object in the worker thread, have a CrossThreadWeakPersistent
-  // pointing to it on the main thread, clear the reference in the worker
-  // thread, run a GC in the worker thread, and see if the
-  // CrossThreadWeakPersistent is cleared.
-
-  DestructorLockingObject::destructor_calls_ = 0;
-
-  // Step 1: Initiate a worker thread, and wait for |object| to get allocated on
-  // the worker thread.
-  MutexLocker main_thread_mutex_locker(MainThreadMutex());
-  std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
-      ThreadCreationParams(WebThreadType::kTestThread)
-          .SetThreadNameForTest("Test Worker Thread"));
-  DestructorLockingObject* object = nullptr;
-  PostCrossThreadTask(
-      *worker_thread->GetTaskRunner(), FROM_HERE,
-      CrossThreadBind(WorkerThreadMainForCrossThreadWeakPersistentTest,
-                      CrossThreadUnretained(&object)));
-  ParkMainThread();
-
-  // Step 3: Set up a CrossThreadWeakPersistent.
-  ASSERT_TRUE(object);
-  CrossThreadWeakPersistent<DestructorLockingObject>
-      cross_thread_weak_persistent(object);
-  object = nullptr;
-  EXPECT_EQ(0, DestructorLockingObject::destructor_calls_);
-
-  // Pretend we have no pointers on stack during the step 4.
-  WakeWorkerThread();
-  ParkMainThread();
-
-  // Step 5: Make sure the weak persistent is cleared.
-  EXPECT_FALSE(cross_thread_weak_persistent.Get());
-  EXPECT_EQ(1, DestructorLockingObject::destructor_calls_);
-
-  WakeWorkerThread();
-  ParkMainThread();
-}
-
-namespace {
-
 class ThreadedClearOnShutdownTester : public ThreadedTesterBase {
  public:
   static void Test() {
diff --git a/third_party/blink/renderer/platform/heap/heap_thread_test.cc b/third_party/blink/renderer/platform/heap/heap_thread_test.cc
new file mode 100644
index 0000000..b1f86ce
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/heap_thread_test.cc
@@ -0,0 +1,269 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+
+namespace blink {
+namespace heap_thread_test {
+
+static Mutex& ActiveThreadMutex() {
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, active_thread_mutex, ());
+  return active_thread_mutex;
+}
+
+static ThreadCondition& ActiveThreadCondition() {
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadCondition, active_thread_condition,
+                                  (ActiveThreadMutex()));
+  return active_thread_condition;
+}
+
+enum ActiveThreadState {
+  kNoThreadActive,
+  kMainThreadActive,
+  kWorkerThreadActive,
+};
+
+static ActiveThreadState& ActiveThread() {
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(ActiveThreadState, active_thread,
+                                  (kNoThreadActive));
+  return active_thread;
+}
+
+static void WakeMainThread() {
+  ActiveThread() = kMainThreadActive;
+  ActiveThreadCondition().Signal();
+}
+
+static void WakeWorkerThread() {
+  ActiveThread() = kWorkerThreadActive;
+  ActiveThreadCondition().Signal();
+}
+
+static void ParkMainThread() {
+  while (ActiveThread() != kMainThreadActive) {
+    ActiveThreadCondition().Wait();
+  }
+}
+
+static void ParkWorkerThread() {
+  while (ActiveThread() != kWorkerThreadActive) {
+    ActiveThreadCondition().Wait();
+  }
+}
+
+class Object : public GarbageCollected<Object> {
+ public:
+  Object() {}
+  ~Object() {}
+  void Trace(blink::Visitor* visitor) {}
+};
+
+class AlternatingThreadTester {
+ public:
+  void Test() {
+    MutexLocker locker(ActiveThreadMutex());
+    ActiveThread() = kMainThreadActive;
+
+    std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
+        ThreadCreationParams(WebThreadType::kTestThread)
+            .SetThreadNameForTest("Test Worker Thread"));
+    PostCrossThreadTask(
+        *worker_thread->GetTaskRunner(), FROM_HERE,
+        CrossThreadBind(&AlternatingThreadTester::StartWorkerThread,
+                        CrossThreadUnretained(this)));
+
+    MainThreadMain();
+  }
+
+  void SwitchToWorkerThread() {
+    WakeWorkerThread();
+    ParkMainThread();
+  }
+
+  void SwitchToMainThread() {
+    WakeMainThread();
+    ParkWorkerThread();
+  }
+
+ protected:
+  // Override with code you want to execute on the main thread.
+  virtual void MainThreadMain() = 0;
+  // Override with code you want to execute on the worker thread. At the end,
+  // the ThreadState is detached and we switch back to the main thread
+  // automatically.
+  virtual void WorkerThreadMain() = 0;
+
+ private:
+  void StartWorkerThread() {
+    ThreadState::AttachCurrentThread();
+
+    MutexLocker locker(ActiveThreadMutex());
+
+    WorkerThreadMain();
+
+    ThreadState::DetachCurrentThread();
+    WakeMainThread();
+  }
+};
+
+class MemberSameThreadCheckTester : public AlternatingThreadTester {
+ private:
+  void MainThreadMain() override { SwitchToWorkerThread(); }
+
+  void WorkerThreadMain() override {
+    // Setting an object created on the worker thread to a Member allocated on
+    // the main thread is not allowed.
+    object_ = MakeGarbageCollected<Object>();
+  }
+
+  Member<Object> object_;
+};
+
+#if DCHECK_IS_ON()
+// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
+// crbug.com/709069
+#if !defined(OS_MACOSX)
+TEST(HeapDeathTest, MemberSameThreadCheck) {
+  EXPECT_DEATH(MemberSameThreadCheckTester().Test(), "");
+}
+#endif
+#endif
+
+class PersistentSameThreadCheckTester : public AlternatingThreadTester {
+ private:
+  void MainThreadMain() override { SwitchToWorkerThread(); }
+
+  void WorkerThreadMain() override {
+    // Setting an object created on the worker thread to a Persistent allocated
+    // on the main thread is not allowed.
+    object_ = MakeGarbageCollected<Object>();
+  }
+
+  Persistent<Object> object_;
+};
+
+#if DCHECK_IS_ON()
+// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
+// crbug.com/709069
+#if !defined(OS_MACOSX)
+TEST(HeapDeathTest, PersistentSameThreadCheck) {
+  EXPECT_DEATH(PersistentSameThreadCheckTester().Test(), "");
+}
+#endif
+#endif
+
+class MarkingSameThreadCheckTester : public AlternatingThreadTester {
+ private:
+  class MainThreadObject : public GarbageCollectedFinalized<MainThreadObject> {
+   public:
+    void Trace(blink::Visitor* visitor) { visitor->Trace(set_); }
+    void AddToSet(Object* object) { set_.insert(42, object); }
+
+   private:
+    HeapHashMap<int, Member<Object>> set_;
+  };
+
+  void MainThreadMain() override {
+    main_thread_object_ = MakeGarbageCollected<MainThreadObject>();
+
+    SwitchToWorkerThread();
+
+    // This will try to mark MainThreadObject when it tries to mark Object
+    // it should crash.
+    PreciselyCollectGarbage();
+  }
+
+  void WorkerThreadMain() override {
+    // Adding a reference to an object created on the worker thread to a
+    // HeapHashMap created on the main thread is not allowed.
+    main_thread_object_->AddToSet(MakeGarbageCollected<Object>());
+  }
+
+  CrossThreadPersistent<MainThreadObject> main_thread_object_;
+};
+
+#if DCHECK_IS_ON()
+// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
+// crbug.com/709069
+#if !defined(OS_MACOSX)
+TEST(HeapDeathTest, MarkingSameThreadCheck) {
+  // This will crash during marking, at the DCHECK in Visitor::markHeader() or
+  // earlier.
+  EXPECT_DEATH(MarkingSameThreadCheckTester().Test(), "");
+}
+#endif
+#endif
+
+class DestructorLockingObject
+    : public GarbageCollectedFinalized<DestructorLockingObject> {
+ public:
+  static DestructorLockingObject* Create() {
+    return MakeGarbageCollected<DestructorLockingObject>();
+  }
+
+  DestructorLockingObject() = default;
+  virtual ~DestructorLockingObject() { ++destructor_calls_; }
+
+  static int destructor_calls_;
+  void Trace(blink::Visitor* visitor) {}
+};
+
+int DestructorLockingObject::destructor_calls_ = 0;
+
+class CrossThreadWeakPersistentTester : public AlternatingThreadTester {
+ private:
+  void MainThreadMain() override {
+    // Create an object in the worker thread, have a CrossThreadWeakPersistent
+    // pointing to it on the main thread, run a GC in the worker thread, and see
+    // if the CrossThreadWeakPersistent is cleared.
+
+    DestructorLockingObject::destructor_calls_ = 0;
+
+    // Step 1: Initiate a worker thread, and wait for |Object| to get allocated
+    // on the worker thread.
+    SwitchToWorkerThread();
+
+    // Step 3: Set up a CrossThreadWeakPersistent.
+    ASSERT_TRUE(object_);
+    EXPECT_EQ(0, DestructorLockingObject::destructor_calls_);
+
+    // Pretend we have no pointers on stack during the step 4.
+    SwitchToWorkerThread();
+
+    // Step 5: Make sure the weak persistent is cleared.
+    EXPECT_FALSE(object_.Get());
+    EXPECT_EQ(1, DestructorLockingObject::destructor_calls_);
+
+    SwitchToWorkerThread();
+  }
+
+  void WorkerThreadMain() override {
+    // Step 2: Create an object and store the pointer.
+    object_ = DestructorLockingObject::Create();
+    SwitchToMainThread();
+
+    // Step 4: Run a GC.
+    ThreadState::Current()->CollectGarbage(
+        BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
+        BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
+    SwitchToMainThread();
+  }
+
+  CrossThreadWeakPersistent<DestructorLockingObject> object_;
+};
+
+TEST(HeapThreadTest, CrossThreadWeakPersistent) {
+  CrossThreadWeakPersistentTester().Test();
+}
+
+}  // namespace heap_thread_test
+}  // namespace blink
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index 1545cb0..c9dac30f 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -314,7 +314,6 @@
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-forced-layout.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-updated-layout.html [ Failure ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
-crbug.com/591099 virtual/intersection-observer-v2/intersection-observer/v2/text-shadow.html [ Failure ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
diff --git a/third_party/blink/web_tests/display-lock/lock-before-append/commit-while-disconnected-expected.html b/third_party/blink/web_tests/display-lock/lock-before-append/commit-while-disconnected-expected.html
new file mode 100644
index 0000000..1333caeb
--- /dev/null
+++ b/third_party/blink/web_tests/display-lock/lock-before-append/commit-while-disconnected-expected.html
@@ -0,0 +1,4 @@
+<!doctype HTML>
+
+<div id="log">PASS</div>
+
diff --git a/third_party/blink/web_tests/display-lock/lock-before-append/commit-while-disconnected.html b/third_party/blink/web_tests/display-lock/lock-before-append/commit-while-disconnected.html
new file mode 100644
index 0000000..a5643b93
--- /dev/null
+++ b/third_party/blink/web_tests/display-lock/lock-before-append/commit-while-disconnected.html
@@ -0,0 +1,33 @@
+<!doctype HTML>
+
+<!--
+Runs an acquire(), then commits without connecting the element.
+-->
+
+<div id="log"></div>
+
+<script>
+// TODO(vmpstr): In WPT this needs to be replaced with reftest-wait.
+if (window.testRunner)
+  window.testRunner.waitUntilDone();
+
+function finishTest(status_string) {
+  if (document.getElementById("log").innerHTML === "")
+    document.getElementById("log").innerHTML = status_string;
+  if (window.testRunner)
+    window.testRunner.notifyDone();
+}
+
+function runTest() {
+  let container = document.createElement("div");
+  container.id = "container";
+
+  container.getDisplayLock().acquire({ timeout: Infinity }).then(() => {
+    container.getDisplayLock().commit().then(
+      () => { finishTest("FAIL"); },
+      () => { finishTest("PASS"); });
+  });
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/blink/web_tests/display-lock/lock-before-append/update-while-disconnected-expected.html b/third_party/blink/web_tests/display-lock/lock-before-append/update-while-disconnected-expected.html
new file mode 100644
index 0000000..1333caeb
--- /dev/null
+++ b/third_party/blink/web_tests/display-lock/lock-before-append/update-while-disconnected-expected.html
@@ -0,0 +1,4 @@
+<!doctype HTML>
+
+<div id="log">PASS</div>
+
diff --git a/third_party/blink/web_tests/display-lock/lock-before-append/update-while-disconnected.html b/third_party/blink/web_tests/display-lock/lock-before-append/update-while-disconnected.html
new file mode 100644
index 0000000..9f0e4ed
--- /dev/null
+++ b/third_party/blink/web_tests/display-lock/lock-before-append/update-while-disconnected.html
@@ -0,0 +1,33 @@
+<!doctype HTML>
+
+<!--
+Runs an acquire(), then updates without connecting the element.
+-->
+
+<div id="log"></div>
+
+<script>
+// TODO(vmpstr): In WPT this needs to be replaced with reftest-wait.
+if (window.testRunner)
+  window.testRunner.waitUntilDone();
+
+function finishTest(status_string) {
+  if (document.getElementById("log").innerHTML === "")
+    document.getElementById("log").innerHTML = status_string;
+  if (window.testRunner)
+    window.testRunner.notifyDone();
+}
+
+function runTest() {
+  let container = document.createElement("div");
+  container.id = "container";
+
+  container.getDisplayLock().acquire({ timeout: Infinity }).then(() => {
+    container.getDisplayLock().update().then(
+      () => { finishTest("FAIL"); },
+      () => { finishTest("PASS"); });
+  });
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/blink/web_tests/editing/selection/select_all/select_all_contenteditable_br.html b/third_party/blink/web_tests/editing/selection/select_all/select_all_contenteditable_br.html
new file mode 100644
index 0000000..9dc9134
--- /dev/null
+++ b/third_party/blink/web_tests/editing/selection/select_all/select_all_contenteditable_br.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id="div" contenteditable><br>foo</div>
+<script>
+test(function() {
+    var div = document.getElementById('div');
+    div.focus();
+    assert_true(document.queryCommandEnabled('SelectAll'));
+}, 'SelectAll is enabled if the contenteditable contains BR (at the beginning) and other content');
+</script>
diff --git a/third_party/blink/web_tests/editing/selection/select_all/select_all_contenteditable_br_only.html b/third_party/blink/web_tests/editing/selection/select_all/select_all_contenteditable_br_only.html
new file mode 100644
index 0000000..44c03d4
--- /dev/null
+++ b/third_party/blink/web_tests/editing/selection/select_all/select_all_contenteditable_br_only.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id="div" contenteditable><br></div>
+<script>
+test(function() {
+    var div = document.getElementById('div');
+    div.focus();
+    assert_false(document.queryCommandEnabled('SelectAll'));
+}, 'SelectAll is not enabled if the contenteditable contains a BR only');
+</script>
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index bf947922..7051d91 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -85,8 +85,6 @@
           '../../chrome/android/webapk/libs/runtime_library_version.gni'),
       'lib/armeabi-v7a/libarcore_sdk_c_minimal.so': (
           '../../third_party/arcore-android-sdk'),
-      'lib/armeabi-v7a/libarcore_sdk_c.so': (
-          '../../third_party/arcore-android-sdk'),
     }
 
     self.apk_expected_other_files = set([
diff --git a/tools/clang/plugins/FindBadConstructsAction.cpp b/tools/clang/plugins/FindBadConstructsAction.cpp
index 916f0de..efaf1b3 100644
--- a/tools/clang/plugins/FindBadConstructsAction.cpp
+++ b/tools/clang/plugins/FindBadConstructsAction.cpp
@@ -47,10 +47,6 @@
     if (args[i] == "check-base-classes") {
       // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed.
       options_.check_base_classes = true;
-    } else if (args[i] == "enforce-in-thirdparty-webkit") {
-      // TODO(dcheng): Remove completely.
-    } else if (args[i] == "check-enum-max-value") {
-      // TODO(dcheng): Remove completely.
     } else if (args[i] == "check-ipc") {
       options_.check_ipc = true;
     } else if (args[i] == "check-gmock-objects") {
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index a7654e3d..5d3c2bf 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -190,9 +190,6 @@
     settings.enable_latency_recovery = false;
   }
 
-  settings.always_request_presentation_time =
-      command_line->HasSwitch(cc::switches::kAlwaysRequestPresentationTime);
-
   animation_host_ = cc::AnimationHost::CreateMainInstance();
 
   cc::LayerTreeHost::InitParams params;
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc
index 76085ec..60e1d52 100644
--- a/ui/events/ozone/evdev/event_device_info.cc
+++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -458,11 +458,21 @@
 
 // static
 ui::InputDeviceType EventDeviceInfo::GetInputDeviceTypeFromId(input_id id) {
-  constexpr uint16_t kGoogleVendorId = 0x18d1;
-  constexpr uint16_t kHammerProductId = 0x5030;
-  if (id.bustype == BUS_USB && id.vendor == kGoogleVendorId &&
-      id.product == kHammerProductId)
-    return InputDeviceType::INPUT_DEVICE_INTERNAL;
+  static constexpr struct {
+    uint16_t vid;
+    uint16_t pid;
+  } kUSBInternalDevices[] = {
+    { 0x18d1, 0x5030 }, // Google, Hammer PID
+    { 0x1fd2, 0x8103 }  // LG, Internal TouchScreen PID
+  };
+
+  if (id.bustype == BUS_USB) {
+    for (size_t i = 0; i < arraysize(kUSBInternalDevices); ++i) {
+      if (id.vendor == kUSBInternalDevices[i].vid &&
+          id.product == kUSBInternalDevices[i].pid)
+        return InputDeviceType::INPUT_DEVICE_INTERNAL;
+    }
+  }
 
   switch (id.bustype) {
     case BUS_I2C:
diff --git a/ui/views/test/platform_test_helper_mus.cc b/ui/views/test/platform_test_helper_mus.cc
index 01b727aa..da05fee0 100644
--- a/ui/views/test/platform_test_helper_mus.cc
+++ b/ui/views/test/platform_test_helper_mus.cc
@@ -53,7 +53,6 @@
   ServiceManagerConnection()
       : thread_("Persistent service_manager connections"),
         default_service_binding_(&default_service_) {
-    catalog::Catalog::SetDefaultCatalogManifest(CreateViewsUnittestsCatalog());
     base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                              base::WaitableEvent::InitialState::NOT_SIGNALED);
     base::Thread::Options options;
@@ -109,8 +108,8 @@
 
   void SetUpConnectionsOnBackgroundThread(base::WaitableEvent* wait) {
     background_service_manager_ =
-        std::make_unique<service_manager::BackgroundServiceManager>(nullptr,
-                                                                    nullptr);
+        std::make_unique<service_manager::BackgroundServiceManager>(
+            nullptr, CreateViewsUnittestsCatalog());
     service_manager::mojom::ServicePtr service;
     default_service_binding_.Bind(mojo::MakeRequest(&service));
     background_service_manager_->RegisterService(