diff --git a/DEPS b/DEPS
index 9553c1d..0663d3bc 100644
--- a/DEPS
+++ b/DEPS
@@ -195,11 +195,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': 'c1c3c6d70d326a27b7b9fa82203ff2db28043be7',
+  'skia_revision': 'c4245f475be744ef91f55764b43d9dcaefe63d3b',
   # 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': '26d2954fbe8d1d68f3daf3fc59f1826dd91d6383',
+  'v8_revision': 'f8df7e0af9c692d5e3b3aa3aa4bd17aa686d4134',
   # 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.
@@ -207,7 +207,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': '9ae6d7f2ee9e12b707483dc9cadd7c3529595016',
+  'angle_revision': 'd852ad24adc0c62ecb520835c1a835a42d3495e2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -215,7 +215,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': '5f4456e3c52fbe17db79da16b1122f21dbcd3582',
+  'pdfium_revision': '807e4fa951b9aae0c9355abae7d379b70a5f8677',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -258,7 +258,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': '5abddab6695ed03674a936d0fe48ce68bd1efd3e',
+  'catapult_revision': '3f714d9026a262760813a0ae24d85bec686e9def',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'c0263ae980bf6d062fac2e520e6046beece610f5',
+  'devtools_frontend_revision': '467b0b16324b77b597e69237ae934f80118e55f6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -1542,7 +1542,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f1b37b7a9dad80220a166305ef17a5da9f1fbfe1',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@384ea8475558f5142f755fc4cdb9db0ea7d853b5',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/accessibility/accessibility_focus_ring_group.cc b/ash/accessibility/accessibility_focus_ring_group.cc
index a157cdc..cbbbd78 100644
--- a/ash/accessibility/accessibility_focus_ring_group.cc
+++ b/ash/accessibility/accessibility_focus_ring_group.cc
@@ -115,10 +115,8 @@
       return;
     }
 
-    double fraction = delta / transition_time;
-
     // Ease-in effect.
-    fraction = pow(fraction, 0.3);
+    const double fraction = pow(delta / transition_time, 0.3);
 
     // Handle corner case where we're animating but we don't have previous
     // rings.
@@ -129,8 +127,8 @@
         previous_focus_rings_[0], focus_rings_[0], fraction));
   } else {
     ash::ComputeOpacity(&(focus_animation_info_), timestamp);
-    for (size_t i = 0; i < focus_layers_.size(); ++i)
-      focus_layers_[i]->SetOpacity(focus_animation_info_.opacity);
+    for (auto& focus_layer : focus_layers_)
+      focus_layer->SetOpacity(focus_animation_info_.opacity);
   }
 }
 
diff --git a/ash/accessibility/layer_animation_info.cc b/ash/accessibility/layer_animation_info.cc
index 70897ef..a19d9aef 100644
--- a/ash/accessibility/layer_animation_info.cc
+++ b/ash/accessibility/layer_animation_info.cc
@@ -33,9 +33,7 @@
     opacity = 1.0 - (change_delta / (fade_in_time + fade_out_time));
 
   // Layer::SetOpacity will throw an error if we're not within 0...1.
-  opacity = base::ClampToRange(opacity, 0.0f, 1.0f);
-
-  animation_info->opacity = opacity;
+  animation_info->opacity = base::ClampToRange(opacity, 0.0f, 1.0f);
 }
 
 }  // namespace ash
\ No newline at end of file
diff --git a/ash/accessibility/spoken_feedback_enabler.cc b/ash/accessibility/spoken_feedback_enabler.cc
index 1a2656ba..ff047db 100644
--- a/ash/accessibility/spoken_feedback_enabler.cc
+++ b/ash/accessibility/spoken_feedback_enabler.cc
@@ -33,8 +33,7 @@
 
 void SpokenFeedbackEnabler::OnTimer() {
   base::TimeTicks now = ui::EventTimeForNow();
-  double tick_count_f = (now - start_time_) / kTimerDelay;
-  int tick_count = base::ClampRound(tick_count_f);
+  int tick_count = base::ClampRound((now - start_time_) / kTimerDelay);
 
   AccessibilityControllerImpl* controller =
       Shell::Get()->accessibility_controller();
diff --git a/ash/accessibility/touch_accessibility_enabler.cc b/ash/accessibility/touch_accessibility_enabler.cc
index b413cbe..ec8a1e1 100644
--- a/ash/accessibility/touch_accessibility_enabler.cc
+++ b/ash/accessibility/touch_accessibility_enabler.cc
@@ -159,9 +159,8 @@
 }
 
 void TouchAccessibilityEnabler::OnTimer() {
-  base::TimeTicks now = Now();
-  double tick_count_f = (now - two_finger_start_time_) / kTimerDelay;
-  int tick_count = base::ClampRound(tick_count_f);
+  const int tick_count =
+      base::ClampRound((Now() - two_finger_start_time_) / kTimerDelay);
 
   if (tick_count == kTimerTicksOfFirstSoundFeedback) {
     base::RecordAction(
diff --git a/ash/fast_ink/fast_ink_points.cc b/ash/fast_ink/fast_ink_points.cc
index bcd2813..fb1ee72 100644
--- a/ash/fast_ink/fast_ink_points.cc
+++ b/ash/fast_ink/fast_ink_points.cc
@@ -95,8 +95,9 @@
 
 float FastInkPoints::GetFadeoutFactor(int index) const {
   DCHECK(!life_duration_.is_zero());
-  DCHECK(0 <= index && index < GetNumberOfPoints());
-  base::TimeDelta age = collection_latest_time_ - points_[index].time;
+  DCHECK_GE(index, 0);
+  DCHECK_LT(index, GetNumberOfPoints());
+  const base::TimeDelta age = collection_latest_time_ - points_[index].time;
   return std::min(age / life_duration_, 1.0);
 }
 
diff --git a/ash/public/cpp/fps_counter.cc b/ash/public/cpp/fps_counter.cc
index c205e16..189682c0 100644
--- a/ash/public/cpp/fps_counter.cc
+++ b/ash/public/cpp/fps_counter.cc
@@ -35,9 +35,7 @@
 
   base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
   float refresh_rate = compositor_->refresh_rate();
-  int expected_frame_number =
-      std::floor(refresh_rate * elapsed.InMillisecondsF() /
-                 base::Time::kMillisecondsPerSecond);
+  const int expected_frame_number = (refresh_rate * elapsed).InSeconds();
   int actual_frame_number = end_frame_number - start_frame_number_;
   int smoothness = actual_frame_number < expected_frame_number
                        ? smoothness =
diff --git a/ash/public/cpp/power_utils.cc b/ash/public/cpp/power_utils.cc
index 698defb..931230c 100644
--- a/ash/public/cpp/power_utils.cc
+++ b/ash/public/cpp/power_utils.cc
@@ -32,9 +32,9 @@
                                   int* minutes) {
   DCHECK(hours);
   DCHECK(minutes);
-  const int total_minutes = base::ClampRound(time.InSecondsF() / 60);
-  *hours = total_minutes / 60;
-  *minutes = total_minutes % 60;
+  *minutes = base::ClampRound(time / base::TimeDelta::FromMinutes(1));
+  *hours = *minutes / 60;
+  *minutes %= 60;
 }
 
 }  // namespace power_utils
diff --git a/ash/system/power/power_notification_controller.cc b/ash/system/power/power_notification_controller.cc
index 57d3d9e..be46891 100644
--- a/ash/system/power/power_notification_controller.cc
+++ b/ash/system/power/power_notification_controller.cc
@@ -200,7 +200,7 @@
   // The notification includes a rounded minutes value, so round the estimate
   // received from the power manager to match.
   const int remaining_minutes =
-      base::ClampRound(remaining_time->InSecondsF() / 60.0);
+      base::ClampRound(*remaining_time / base::TimeDelta::FromMinutes(1));
 
   if (remaining_minutes >= kNoWarningMinutes ||
       PowerStatus::Get()->IsBatteryFull()) {
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py
index 8e23c67..4723eee 100644
--- a/build/fuchsia/device_target.py
+++ b/build/fuchsia/device_target.py
@@ -85,7 +85,7 @@
     self._port = port if port else 22
     self._system_log_file = system_log_file
     self._host = host
-    self._fuchsia_out_dir = os.path.expanduser(fuchsia_out_dir)
+    self._fuchsia_out_dir = fuchsia_out_dir
     self._node_name = node_name
     self._os_check = os_check
     self._amber_repo = None
@@ -98,6 +98,7 @@
         raise Exception('Only one of "--fuchsia-out-dir" or "--ssh_config" can '
                         'be specified.')
 
+      self._fuchsia_out_dir = os.path.expanduser(fuchsia_out_dir)
       # Use SSH keys from the Fuchsia output directory.
       self._ssh_config_path = os.path.join(self._fuchsia_out_dir, 'ssh-keys',
                                            'ssh_config')
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 9e15f93..d9420410 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200815.3.1
+0.20200816.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 66548964..d9420410 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200815.2.1
+0.20200816.3.1
diff --git a/build/linux/sysroot_scripts/libwayland-client-symbols b/build/linux/sysroot_scripts/libwayland-client-symbols
new file mode 100644
index 0000000..d6bffeb
--- /dev/null
+++ b/build/linux/sysroot_scripts/libwayland-client-symbols
@@ -0,0 +1,74 @@
+libwayland-client.so.0 libwayland-client0 #MINVER#
+ wl_array_add@Base 1.4.0
+ wl_array_copy@Base 1.4.0
+ wl_array_init@Base 1.4.0
+ wl_array_release@Base 1.4.0
+ wl_buffer_interface@Base 1.4.0
+ wl_callback_interface@Base 1.4.0
+ wl_compositor_interface@Base 1.4.0
+ wl_data_device_interface@Base 1.4.0
+ wl_data_device_manager_interface@Base 1.4.0
+ wl_data_offer_interface@Base 1.4.0
+ wl_data_source_interface@Base 1.4.0
+ wl_display_cancel_read@Base 1.4.0
+ wl_display_connect@Base 1.4.0
+ wl_display_connect_to_fd@Base 1.4.0
+ wl_display_create_queue@Base 1.4.0
+ wl_display_disconnect@Base 1.4.0
+ wl_display_dispatch@Base 1.4.0
+ wl_display_dispatch_pending@Base 1.4.0
+ wl_display_dispatch_queue@Base 1.4.0
+ wl_display_dispatch_queue_pending@Base 1.4.0
+ wl_display_flush@Base 1.4.0
+ wl_display_get_error@Base 1.4.0
+ wl_display_get_fd@Base 1.4.0
+ wl_display_get_protocol_error@Base 1.4.0
+ wl_display_interface@Base 1.4.0
+ wl_display_prepare_read@Base 1.4.0
+ wl_display_prepare_read_queue@Base 1.4.0
+ wl_display_read_events@Base 1.4.0
+ wl_display_roundtrip@Base 1.4.0
+ wl_display_roundtrip_queue@Base 1.4.0
+ wl_event_queue_destroy@Base 1.4.0
+ wl_keyboard_interface@Base 1.4.0
+ wl_list_empty@Base 1.4.0
+ wl_list_init@Base 1.4.0
+ wl_list_insert@Base 1.4.0
+ wl_list_insert_list@Base 1.4.0
+ wl_list_length@Base 1.4.0
+ wl_list_remove@Base 1.4.0
+ wl_log_set_handler_client@Base 1.4.0
+ wl_output_interface@Base 1.4.0
+ wl_pointer_interface@Base 1.4.0
+ wl_proxy_add_dispatcher@Base 1.4.0
+ wl_proxy_add_listener@Base 1.4.0
+ wl_proxy_create@Base 1.4.0
+ wl_proxy_create_wrapper@Base 1.4.0
+ wl_proxy_destroy@Base 1.4.0
+ wl_proxy_get_class@Base 1.4.0
+ wl_proxy_get_id@Base 1.4.0
+ wl_proxy_get_listener@Base 1.4.0
+ wl_proxy_get_tag@Base 1.4.0
+ wl_proxy_get_user_data@Base 1.4.0
+ wl_proxy_get_version@Base 1.4.0
+ wl_proxy_marshal@Base 1.4.0
+ wl_proxy_marshal_array@Base 1.4.0
+ wl_proxy_marshal_array_constructor@Base 1.4.0
+ wl_proxy_marshal_array_constructor_versioned@Base 1.4.0
+ wl_proxy_marshal_constructor@Base 1.4.0
+ wl_proxy_marshal_constructor_versioned@Base 1.4.0
+ wl_proxy_set_queue@Base 1.4.0
+ wl_proxy_set_tag@Base 1.4.0
+ wl_proxy_set_user_data@Base 1.4.0
+ wl_proxy_wrapper_destroy@Base 1.4.0
+ wl_region_interface@Base 1.4.0
+ wl_registry_interface@Base 1.4.0
+ wl_seat_interface@Base 1.4.0
+ wl_shell_interface@Base 1.4.0
+ wl_shell_surface_interface@Base 1.4.0
+ wl_shm_interface@Base 1.4.0
+ wl_shm_pool_interface@Base 1.4.0
+ wl_subcompositor_interface@Base 1.4.0
+ wl_subsurface_interface@Base 1.4.0
+ wl_surface_interface@Base 1.4.0
+ wl_touch_interface@Base 1.4.0
diff --git a/build/linux/sysroot_scripts/libxkbcommon0-symbols b/build/linux/sysroot_scripts/libxkbcommon0-symbols
new file mode 100644
index 0000000..5750fc0
--- /dev/null
+++ b/build/linux/sysroot_scripts/libxkbcommon0-symbols
@@ -0,0 +1,93 @@
+libxkbcommon.so.0 libxkbcommon0 #MINVER#
+ xkb_context_get_log_level@Base 0.4.1
+ xkb_context_get_log_verbosity@Base 0.4.1
+ xkb_context_get_user_data@Base 0.4.1
+ xkb_context_include_path_append@Base 0.4.1
+ xkb_context_include_path_append_default@Base 0.4.1
+ xkb_context_include_path_clear@Base 0.4.1
+ xkb_context_include_path_get@Base 0.4.1
+ xkb_context_include_path_reset_defaults@Base 0.4.1
+ xkb_context_new@Base 0.4.1
+ xkb_context_num_include_paths@Base 0.4.1
+ xkb_context_ref@Base 0.4.1
+ xkb_context_set_log_fn@Base 0.4.1
+ xkb_context_set_log_level@Base 0.4.1
+ xkb_context_set_log_verbosity@Base 0.4.1
+ xkb_context_set_user_data@Base 0.4.1
+ xkb_context_unref@Base 0.4.1
+ xkb_key_get_syms@Base 0.4.1
+ xkb_key_mod_index_is_consumed@Base 0.4.1
+ xkb_key_mod_mask_remove_consumed@Base 0.4.1
+ xkb_key_num_groups@Base 0.4.1
+ xkb_key_repeats@Base 0.4.1
+ xkb_keymap_get_as_string@Base 0.4.1
+ xkb_keymap_key_for_each@Base 0.4.1
+ xkb_keymap_key_get_syms_by_level@Base 0.4.1
+ xkb_keymap_key_repeats@Base 0.4.1
+ xkb_keymap_layout_get_index@Base 0.4.1
+ xkb_keymap_layout_get_name@Base 0.4.1
+ xkb_keymap_led_get_index@Base 0.4.1
+ xkb_keymap_led_get_name@Base 0.4.1
+ xkb_keymap_max_keycode@Base 0.4.1
+ xkb_keymap_min_keycode@Base 0.4.1
+ xkb_keymap_mod_get_index@Base 0.4.1
+ xkb_keymap_mod_get_name@Base 0.4.1
+ xkb_keymap_new_from_buffer@Base 0.4.1
+ xkb_keymap_new_from_file@Base 0.4.1
+ xkb_keymap_new_from_names@Base 0.4.1
+ xkb_keymap_new_from_string@Base 0.4.1
+ xkb_keymap_num_layouts@Base 0.4.1
+ xkb_keymap_num_layouts_for_key@Base 0.4.1
+ xkb_keymap_num_leds@Base 0.4.1
+ xkb_keymap_num_levels_for_key@Base 0.4.1
+ xkb_keymap_num_mods@Base 0.4.1
+ xkb_keymap_ref@Base 0.4.1
+ xkb_keymap_unref@Base 0.4.1
+ xkb_keysym_from_name@Base 0.4.1
+ xkb_keysym_get_name@Base 0.4.1
+ xkb_keysym_to_utf32@Base 0.4.1
+ xkb_keysym_to_utf8@Base 0.4.1
+ xkb_map_get_as_string@Base 0.4.1
+ xkb_map_group_get_index@Base 0.4.1
+ xkb_map_group_get_name@Base 0.4.1
+ xkb_map_led_get_index@Base 0.4.1
+ xkb_map_led_get_name@Base 0.4.1
+ xkb_map_mod_get_index@Base 0.4.1
+ xkb_map_mod_get_name@Base 0.4.1
+ xkb_map_new_from_file@Base 0.4.1
+ xkb_map_new_from_names@Base 0.4.1
+ xkb_map_new_from_string@Base 0.4.1
+ xkb_map_num_groups@Base 0.4.1
+ xkb_map_num_leds@Base 0.4.1
+ xkb_map_num_mods@Base 0.4.1
+ xkb_map_ref@Base 0.4.1
+ xkb_map_unref@Base 0.4.1
+ xkb_state_get_keymap@Base 0.4.1
+ xkb_state_get_map@Base 0.4.1
+ xkb_state_group_index_is_active@Base 0.4.1
+ xkb_state_group_name_is_active@Base 0.4.1
+ xkb_state_key_get_consumed_mods@Base 0.4.1
+ xkb_state_key_get_layout@Base 0.4.1
+ xkb_state_key_get_level@Base 0.4.1
+ xkb_state_key_get_one_sym@Base 0.4.1
+ xkb_state_key_get_syms@Base 0.4.1
+ xkb_state_key_get_utf32@Base 0.4.1
+ xkb_state_key_get_utf8@Base 0.4.1
+ xkb_state_layout_index_is_active@Base 0.4.1
+ xkb_state_layout_name_is_active@Base 0.4.1
+ xkb_state_led_index_is_active@Base 0.4.1
+ xkb_state_led_name_is_active@Base 0.4.1
+ xkb_state_mod_index_is_active@Base 0.4.1
+ xkb_state_mod_index_is_consumed@Base 0.4.1
+ xkb_state_mod_indices_are_active@Base 0.4.1
+ xkb_state_mod_mask_remove_consumed@Base 0.4.1
+ xkb_state_mod_name_is_active@Base 0.4.1
+ xkb_state_mod_names_are_active@Base 0.4.1
+ xkb_state_new@Base 0.4.1
+ xkb_state_ref@Base 0.4.1
+ xkb_state_serialize_group@Base 0.4.1
+ xkb_state_serialize_layout@Base 0.4.1
+ xkb_state_serialize_mods@Base 0.4.1
+ xkb_state_unref@Base 0.4.1
+ xkb_state_update_key@Base 0.4.1
+ xkb_state_update_mask@Base 0.4.1
diff --git a/build/linux/sysroot_scripts/sysroot-creator.sh b/build/linux/sysroot_scripts/sysroot-creator.sh
index 4b46e995..6aed2153 100644
--- a/build/linux/sysroot_scripts/sysroot-creator.sh
+++ b/build/linux/sysroot_scripts/sysroot-creator.sh
@@ -326,16 +326,27 @@
   sed -i -e 's|/usr/lib/${arch}-${os}/||g'  ${lscripts}
   sed -i -e 's|/lib/${arch}-${os}/||g' ${lscripts}
 
-  # Unversion libdbus symbols.  This is required because libdbus-1-3
-  # switched from unversioned symbols to versioned ones, and we must
-  # still support distros using the unversioned library.  This hack
-  # can be removed once support for Ubuntu Trusty and Debian Jessie
-  # are dropped.
+  # Unversion libdbus, libxkbcommon, and libwayland-client symbols.
+  # This is required because libdbus-1-3, libwayland-client0 and
+  # libxkbcommon0 switched from unversioned symbols to versioned
+  # ones, and we must still support distros using the unversioned library.
+  # This hack can be removed once support for Ubuntu Trusty and Debian
+  # Jessie are dropped.
   ${strip} -R .gnu.version_d -R .gnu.version \
     "${INSTALL_ROOT}/lib/${arch}-${os}/libdbus-1.so.3"
   cp "${SCRIPT_DIR}/libdbus-1-3-symbols" \
     "${INSTALL_ROOT}/debian/libdbus-1-3/DEBIAN/symbols"
 
+  ${strip} -R .gnu.version_d -R .gnu.version \
+    "${INSTALL_ROOT}/usr/lib/${arch}-${os}/libwayland-client.so.0.3.0"
+  cp "${SCRIPT_DIR}/libwayland-client-symbols" \
+    "${INSTALL_ROOT}/debian/libwayland-client0/DEBIAN/symbols"
+
+  ${strip} -R .gnu.version_d -R .gnu.version \
+    "${INSTALL_ROOT}/usr/lib/${arch}-${os}/libxkbcommon.so.0.0.0"
+  cp "${SCRIPT_DIR}/libxkbcommon0-symbols" \
+    "${INSTALL_ROOT}/debian/libxkbcommon0/DEBIAN/symbols"
+
   # Shared objects depending on libdbus-1.so.3 have unsatisfied undefined
   # versioned symbols. To avoid LLD --no-allow-shlib-undefined errors, rewrite
   # DT_NEEDED entries from libdbus-1.so.3 to a different string. LLD will
diff --git a/chrome/VERSION b/chrome/VERSION
index 40d6444..552f0e9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=86
 MINOR=0
-BUILD=4236
+BUILD=4237
 PATCH=0
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index eec87817..9d269f2 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -915,6 +915,7 @@
   "java/res/layout/homepage_editor.xml",
   "java/res/layout/icon_row_menu_footer.xml",
   "java/res/layout/incognito_description_layout.xml",
+  "java/res/layout/incognito_interstitial_bottom_sheet_view.xml",
   "java/res/layout/incognito_toggle_tabs.xml",
   "java/res/layout/infobar_control_url_ellipsizer.xml",
   "java/res/layout/infobar_translate_compact_content.xml",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
index 12a9c82..2c637a69 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -265,7 +265,12 @@
         model.getHeaderModel().addObserver((source, propertyKey) -> {
             if (propertyKey == AssistantHeaderModel.CHIPS_VISIBLE
                     || propertyKey == AssistantHeaderModel.CHIPS) {
-                animateChildren(rootView);
+                // The PostTask is necessary as a workaround for the sticky button occasionally not
+                // showing, since the chip changes are now issued in the following UI iteration, the
+                // same needs to be done for the corresponding animations.
+                // TODO(b/164389932): Figure out a better fix that doesn't require issuing the
+                // change in the following UI iteration.
+                PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> animateChildren(rootView));
             }
         });
 
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java
index 7afb8db..6558853 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java
@@ -14,6 +14,7 @@
 import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.autofill_assistant.AssistantTextUtils;
 import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChipAdapter;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.sync.settings.SyncAndServicesSettings;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
 import org.chromium.components.browser_ui.widget.textbubble.TextBubble;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 import org.chromium.ui.widget.ViewRectProvider;
@@ -134,15 +136,21 @@
     }
 
     private void maybeShowChips(AssistantHeaderModel model, ViewHolder view) {
-        if (model.get(AssistantHeaderModel.CHIPS_VISIBLE)
-                && !model.get(AssistantHeaderModel.CHIPS).isEmpty()) {
-            view.mChipsContainer.setVisibility(View.VISIBLE);
-            view.mProfileIconView.setVisibility(View.GONE);
-        } else {
-            view.mChipsContainer.setVisibility(View.GONE);
-
-            view.mProfileIconView.setVisibility(View.VISIBLE);
-        }
+        // The PostTask is necessary as a workaround for the sticky button occasionally not showing,
+        // this makes sure that the change happens after any possibly clashing animation currently
+        // happening.
+        // TODO(b/164389932): Figure out a better fix that doesn't require issuing the change in the
+        // following UI iteration.
+        PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
+            if (model.get(AssistantHeaderModel.CHIPS_VISIBLE)
+                    && !model.get(AssistantHeaderModel.CHIPS).isEmpty()) {
+                view.mChipsContainer.setVisibility(View.VISIBLE);
+                view.mProfileIconView.setVisibility(View.GONE);
+            } else {
+                view.mChipsContainer.setVisibility(View.GONE);
+                view.mProfileIconView.setVisibility(View.VISIBLE);
+            }
+        });
     }
 
     private void setProfileMenuListener(ViewHolder view, @Nullable Runnable feedbackCallback) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index d0419072..00ab7d26 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -1332,7 +1332,13 @@
         return TextUtils.join(", ", domainNames);
     }
 
-    private String getDomain(Tab tab) {
+    @VisibleForTesting
+    protected static String getDomain(Tab tab) {
+        // TODO(crbug.com/1116613) Investigate how uninitialized Tabs are appearing
+        // here.
+        if (!tab.isInitialized()) {
+            return "";
+        }
         String domain = UrlUtilities.getDomainAndRegistry(tab.getUrlString(), false);
 
         if (domain.isEmpty()) return tab.getUrlString();
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
index 1ef890d..cd3b4df5 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -86,6 +86,7 @@
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
+import org.chromium.chrome.browser.tab.MockTab;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabCreationState;
 import org.chromium.chrome.browser.tab.TabImpl;
@@ -2189,6 +2190,13 @@
         mCallbackCaptor.getValue().onResult(mFaviconDrawable);
     }
 
+    @Test
+    public void testGetDomainOnDestroyedTab() {
+        Tab tab = new MockTab(TAB1_ID, false);
+        tab.destroy();
+        assertEquals("", TabListMediator.getDomain(tab));
+    }
+
     private void initAndAssertAllProperties() {
         List<Tab> tabs = new ArrayList<>();
         for (int i = 0; i < mTabModel.getCount(); i++) {
diff --git a/chrome/android/java/res/layout/account_picker_bottom_sheet_view.xml b/chrome/android/java/res/layout/account_picker_bottom_sheet_view.xml
index 33f8628..59058fa 100644
--- a/chrome/android/java/res/layout/account_picker_bottom_sheet_view.xml
+++ b/chrome/android/java/res/layout/account_picker_bottom_sheet_view.xml
@@ -20,6 +20,7 @@
         app:srcCompat="@drawable/drag_handlebar" />
 
     <ImageView
+        android:id="@+id/account_picker_bottom_sheet_logo"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
@@ -91,4 +92,12 @@
         android:layout_marginTop="32dp"
         android:layout_marginBottom="132dp"
         android:visibility="gone" />
+
+    <include
+        android:id="@+id/incognito_interstitial_bottom_sheet_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        layout="@layout/incognito_interstitial_bottom_sheet_view"/>
+
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/incognito_interstitial_bottom_sheet_view.xml b/chrome/android/java/res/layout/incognito_interstitial_bottom_sheet_view.xml
new file mode 100644
index 0000000..0eece5c9d
--- /dev/null
+++ b/chrome/android/java/res/layout/incognito_interstitial_bottom_sheet_view.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="8dp"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/incognito_interstitial_learn_more"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="112dp"
+        android:layout_marginEnd="24dp"
+        android:layout_gravity="center_vertical"
+        android:text="@string/learn_more"
+        android:textAppearance="@style/TextAppearance.TextMediumThick.Blue" />
+
+    <org.chromium.ui.widget.ButtonCompat
+        android:id="@+id/incognito_interstitial_continue_button"
+        style="@style/FilledButton.Flat"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="24dp"
+        android:text="@string/continue_button"/>
+
+</LinearLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
index 59fec37f..c759e37 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
@@ -78,6 +78,8 @@
      */
     @Override
     public void goIncognitoMode() {
+        mModel.set(AccountPickerBottomSheetProperties.ACCOUNT_PICKER_BOTTOM_SHEET_STATE,
+                AccountPickerBottomSheetState.INCOGNITO_INTERSTITIAL);
         mAccountPickerDelegate.goIncognitoMode();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
index 2fcac14..a91c3ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
@@ -28,7 +28,8 @@
     @IntDef({AccountPickerBottomSheetState.NO_ACCOUNTS,
             AccountPickerBottomSheetState.COLLAPSED_ACCOUNT_LIST,
             AccountPickerBottomSheetState.EXPANDED_ACCOUNT_LIST,
-            AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS})
+            AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS,
+            AccountPickerBottomSheetState.INCOGNITO_INTERSTITIAL})
     @Retention(RetentionPolicy.SOURCE)
     @interface AccountPickerBottomSheetState {
         /**
@@ -67,6 +68,15 @@
          * |Continue as| is clicked. This state does not lead to any other state.
          */
         int SIGNIN_IN_PROGRESS = 3;
+
+        /**
+         * When the account list is expanded, the user sees the account list of all the accounts
+         * on device and some additional rows like |Add account to device| and |Go incognito mode|.
+         *
+         * This state can only be reached from EXPANDED_ACCOUNT_LIST and would represent that the
+         * user has clicked the "Go incognito mode" option.
+         */
+        int INCOGNITO_INTERSTITIAL = 4;
     }
 
     // PropertyKeys for the selected account view when the account list is collapsed.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
index 0c172e7..a7755e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
@@ -32,6 +32,7 @@
     private final TextView mAccountPickerTitle;
     private final RecyclerView mAccountListView;
     private final View mSelectedAccountView;
+    private final View mIncognitoInterstitialView;
     private final ButtonCompat mContinueAsButton;
 
     AccountPickerBottomSheetView(Context context) {
@@ -40,6 +41,8 @@
                 R.layout.account_picker_bottom_sheet_view, null);
         mAccountPickerTitle = mContentView.findViewById(R.id.account_picker_bottom_sheet_title);
         mAccountListView = mContentView.findViewById(R.id.account_picker_account_list);
+        mIncognitoInterstitialView =
+                mContentView.findViewById(R.id.incognito_interstitial_bottom_sheet_view);
         mAccountListView.setLayoutManager(new LinearLayoutManager(
                 mAccountListView.getContext(), LinearLayoutManager.VERTICAL, false));
         mSelectedAccountView = mContentView.findViewById(R.id.account_picker_selected_account);
@@ -126,6 +129,19 @@
                 .setVisibility(View.VISIBLE);
     }
 
+    void setUpIncognitoInterstitialView() {
+        // TODO(crbug.com/1103262): Setup the incognito interstitial strings.
+        ImageView logo = mContentView.findViewById(R.id.account_picker_bottom_sheet_logo);
+        logo.setImageResource(R.drawable.location_bar_incognito_badge);
+
+        mAccountPickerTitle.setVisibility(View.GONE);
+        mContentView.findViewById(R.id.account_picker_bottom_sheet_subtitle)
+                .setVisibility(View.GONE);
+        mContentView.findViewById(R.id.account_picker_horizontal_divider).setVisibility(View.GONE);
+        mAccountListView.setVisibility(View.GONE);
+        mIncognitoInterstitialView.setVisibility(View.VISIBLE);
+    }
+
     @Override
     public View getContentView() {
         return mContentView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
index 31776a4..20187b1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
@@ -56,6 +56,9 @@
             case AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS:
                 view.setUpSignInInProgressView();
                 break;
+            case AccountPickerBottomSheetState.INCOGNITO_INTERSTITIAL:
+                view.setUpIncognitoInterstitialView();
+                break;
             default:
                 throw new IllegalArgumentException(
                         "Cannot bind AccountPickerBottomSheetView for the state:"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java
index 764d02e..e3c3de8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java
@@ -49,9 +49,9 @@
 
         private IncognitoAccountRowProperties() {}
 
-        static PropertyModel createModel(Runnable runnableIncognitoAccount) {
+        static PropertyModel createModel(Runnable runnableIncognitoMode) {
             return new PropertyModel.Builder(ALL_KEYS)
-                    .with(ON_CLICK_LISTENER, runnableIncognitoAccount)
+                    .with(ON_CLICK_LISTENER, runnableIncognitoMode)
                     .build();
         }
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
index bb7c71a..8f58516e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -339,6 +339,18 @@
         onView(withText(R.string.signin_incognito_mode_secondary)).check(matches(isDisplayed()));
         onView(withText(R.string.signin_incognito_mode_primary)).perform(click());
         verify(mAccountPickerDelegateMock).goIncognitoMode();
+        checkIncognitoInterstitialSheet();
+    }
+
+    private void checkIncognitoInterstitialSheet() {
+        onView(withId(R.id.account_picker_bottom_sheet_logo)).check(matches(isDisplayed()));
+        onView(withId(R.id.account_picker_bottom_sheet_title)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.account_picker_bottom_sheet_subtitle))
+                .check(matches(not(isDisplayed())));
+        onView(withId(R.id.account_picker_horizontal_divider)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.account_picker_account_list)).check(matches(not(isDisplayed())));
+
+        onView(withId(R.id.incognito_interstitial_bottom_sheet_view)).check(matches(isDisplayed()));
     }
 
     private void checkZeroAccountBottomSheet() {
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 0938af9..cb0a127 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5688,6 +5688,15 @@
   <message name="IDS_SUGGESTION_ENTER_KEY" desc="This string is the enter key annotation to educate users how to accept a personal information suggestion.">
     Enter
   </message>
+   <message name="IDS_SUGGESTION_EMOJI_SUGGESTED" desc="String announced by screenreader when emoji suggestion pops up.">
+    Emoji suggested. Press up or down to navigate and enter to insert.
+  </message>
+  <message name="IDS_SUGGESTION_EMOJI_CHOSEN" desc="String announced by screenreader when users selected an emoji in the pop-up.">
+    <ph name="EMOJI_NAME">$1<ex>Party popper</ex></ph>. <ph name="EMOJI_INDEX">$2<ex>5</ex></ph> of <ph name="EMOJI_COUNT">$3<ex>5</ex></ph>.
+  </message>
+  <message name="IDS_SUGGESTION_DISMISSED" desc="String announced by screenreader when suggestion pop-up disappears.">
+    Suggestion dismissed
+  </message>
 
   <!-- Strings for Custom Tab UI -->
   <message name="IDS_CUSTOM_TABS_ACTION_MENU_ACCESSIBLE_NAME" desc="Accessible name for the overflow menu of the Chrome Custom Tab toolbar.">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_DISMISSED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_DISMISSED.png.sha1
new file mode 100644
index 0000000..703bdd6
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_DISMISSED.png.sha1
@@ -0,0 +1 @@
+2f8b8b4390763a991e2c1178f57b5750257c74f8
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_EMOJI_CHOSEN.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_EMOJI_CHOSEN.png.sha1
new file mode 100644
index 0000000..c4681b4
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_EMOJI_CHOSEN.png.sha1
@@ -0,0 +1 @@
+5d2f70d718fddea280e54e37fa6f267ac92cbdda
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_EMOJI_SUGGESTED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_EMOJI_SUGGESTED.png.sha1
new file mode 100644
index 0000000..703bdd6
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_SUGGESTION_EMOJI_SUGGESTED.png.sha1
@@ -0,0 +1 @@
+2f8b8b4390763a991e2c1178f57b5750257c74f8
\ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp
index 0001881..ba8dbfd 100644
--- a/chrome/app/os_settings_search_tag_strings.grdp
+++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -874,6 +874,12 @@
   <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_INPUT_ADD_LANGUAGE" desc="Text for search result item which, when clicked, navigates the user to languages and input settings, with an option to add a new language.">
     Add languages
   </message>
+  <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_ADD_INPUT_METHOD" translateable="false" desc="Text for search result item which, when clicked, navigates the user to input settings, with the option to add input methods (keyboard layouts and input method editors).">
+    Add input methods
+  </message>
+  <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_SPELL_CHECK" translateable="false" desc="Text for search result item which, when clicked, navigates the user to input settings, with all the options for spell check settings">
+    Spell check
+  </message>
   <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_INPUT_METHODS" desc="Text for search result item which, when clicked, navigates the user to input settings, with the option to enable/disable input in supported languages.">
     Manage input methods
   </message>
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index cea041cd..314cd596 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -277,6 +277,15 @@
   <message name="IDS_OS_SETTINGS_LANGUAGES_OPEN_OPTIONS_PAGE_LABEL" translateable="false" desc="Title for the button to open the options page for a input method (keyboard layout and input method editor).">
       Open options page for <ph name="INPUT_METHOD_NAME">$1<ex>US keyboard</ex></ph>
   </message>
+  <message name="IDS_OS_SETTINGS_LANGUAGES_ADD_INPUT_METHOD_LABEL" translateable="false" desc="Button under the list of input methods which opens a dialog that lets the user add keyboard layouts and input method editors.">
+    Add input methods
+  </message>
+  <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_TITLE" translateable="false" desc="Title for the section containing all the options for spell check settings. The options include picking between using the system's spell check or using Google's web service and a list of the enabled languages which support spell checking.">
+    Spell check
+  </message>
+  <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_DISABLED_REASON" translateable="false" desc="Text that indicates to the user that spell check options are disabled because none of the languages they have added have spell check support.">
+    Spell check isn’t supported for the languages you selected
+  </message>
   <message name="IDS_OS_SETTINGS_LANGUAGES_LIST_TITLE" desc="Title for the list of the user's preferred written languages.">
     Languages
   </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index df908b1..607d640 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -126,7 +126,6 @@
 #include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/sync/base/sync_base_switches.h"
 #include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/engine/sync_engine_switches.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/browser/translate_ranker_impl.h"
@@ -1541,23 +1540,10 @@
 const FeatureEntry::FeatureParam kTabGridLayoutAndroid_NewTabTile[] = {
     {"tab_grid_layout_android_new_tab_tile", "NewTabTile"}};
 
-const FeatureEntry::FeatureParam
-    kTabGridLayoutAndroid_ThumbnailAspectRatio_2[] = {
-        {"thumbnail_aspect_ratio", "2.0"},
-        {"allow_to_refetch", "true"}};
-
-const FeatureEntry::FeatureParam
-    kTabGridLayoutAndroid_ThumbnailAspectRatio_three_quarter[] = {
-        {"thumbnail_aspect_ratio", "0.75"},
-        {"allow_to_refetch", "true"}};
-
-const FeatureEntry::FeatureParam
-    kTabGridLayoutAndroid_ThumbnailAspectRatio_half[] = {
-        {"thumbnail_aspect_ratio", "0.5"},
-        {"allow_to_refetch", "true"}};
-
-const FeatureEntry::FeatureParam kTabGridLayoutAndroid_DisableRefetch[] = {
-    {"allow_to_refetch", "false"}};
+const FeatureEntry::FeatureParam kTabGridLayoutAndroid_TallNTV[] = {
+    {"thumbnail_aspect_ratio", "0.85"},
+    {"allow_to_refetch", "true"},
+    {"tab_grid_layout_android_new_tab", "NewTabVariation"}};
 
 const FeatureEntry::FeatureParam kTabGridLayoutAndroid_SearchChip[] = {
     {"enable_search_term_chip", "true"}};
@@ -1567,18 +1553,8 @@
      base::size(kTabGridLayoutAndroid_NewTabVariation), nullptr},
     {"New Tab Tile", kTabGridLayoutAndroid_NewTabTile,
      base::size(kTabGridLayoutAndroid_NewTabTile), nullptr},
-    {"thumbnail aspect ratio - 2:1",
-     kTabGridLayoutAndroid_ThumbnailAspectRatio_2,
-     base::size(kTabGridLayoutAndroid_ThumbnailAspectRatio_2), nullptr},
-    {"thumbnail aspect ratio - 1:2",
-     kTabGridLayoutAndroid_ThumbnailAspectRatio_half,
-     base::size(kTabGridLayoutAndroid_ThumbnailAspectRatio_half), nullptr},
-    {"thumbnail aspect ratio - 3:4",
-     kTabGridLayoutAndroid_ThumbnailAspectRatio_three_quarter,
-     base::size(kTabGridLayoutAndroid_ThumbnailAspectRatio_three_quarter),
-     nullptr},
-    {"Disable refetch", kTabGridLayoutAndroid_DisableRefetch,
-     base::size(kTabGridLayoutAndroid_DisableRefetch), nullptr},
+    {"Tall NTV", kTabGridLayoutAndroid_TallNTV,
+     base::size(kTabGridLayoutAndroid_TallNTV), nullptr},
     {"Search term chip", kTabGridLayoutAndroid_SearchChip,
      base::size(kTabGridLayoutAndroid_SearchChip), nullptr},
 };
@@ -5434,11 +5410,6 @@
      FEATURE_VALUE_TYPE(autofill::features::kAutofillTouchToFill)},
 #endif  // defined(OS_ANDROID)
 
-    {"enable-sync-trusted-vault",
-     flag_descriptions::kEnableSyncTrustedVaultName,
-     flag_descriptions::kEnableSyncTrustedVaultDescription, kOsAll,
-     FEATURE_VALUE_TYPE(switches::kSyncSupportTrustedVaultPassphrase)},
-
 #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX)
     {"global-media-controls", flag_descriptions::kGlobalMediaControlsName,
      flag_descriptions::kGlobalMediaControlsDescription,
diff --git a/chrome/browser/apps/app_service/app_icon_factory.cc b/chrome/browser/apps/app_service/app_icon_factory.cc
index 66dbd088..00e154a 100644
--- a/chrome/browser/apps/app_service/app_icon_factory.cc
+++ b/chrome/browser/apps/app_service/app_icon_factory.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/favicon_base/favicon_types.h"
@@ -247,6 +248,26 @@
       std::move(compressed_data_callback));
 }
 
+base::Optional<IconPurpose> GetIconPurpose(
+    const std::string& web_app_id,
+    const web_app::AppIconManager& icon_manager,
+    int icon_size_in_px) {
+#if defined(OS_CHROMEOS)
+  if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon) &&
+      icon_manager.HasSmallestIcon(web_app_id, {IconPurpose::MASKABLE},
+                                   icon_size_in_px)) {
+    return base::make_optional(IconPurpose::MASKABLE);
+  }
+#endif
+
+  if (icon_manager.HasSmallestIcon(web_app_id, {IconPurpose::ANY},
+                                   icon_size_in_px)) {
+    return base::make_optional(IconPurpose::ANY);
+  }
+
+  return base::nullopt;
+}  // namespace
+
 // This pipeline is meant to:
 // * Simplify loading icons, as things like effects and type are common
 //   to all loading.
@@ -445,19 +466,27 @@
   // constructor.
   icon_scale_for_compressed_response_ = icon_scale_;
 
-  base::Optional<IconPurpose> icon_purpose_to_read;
-  if (icon_manager.HasSmallestIcon(web_app_id, {IconPurpose::MASKABLE},
-                                   icon_size_in_px_)) {
-    icon_purpose_to_read = IconPurpose::MASKABLE;
-  } else if (icon_manager.HasSmallestIcon(web_app_id, {IconPurpose::ANY},
-                                          icon_size_in_px_)) {
-    icon_purpose_to_read = IconPurpose::ANY;
-  }
+  base::Optional<IconPurpose> icon_purpose_to_read =
+      GetIconPurpose(web_app_id, icon_manager, icon_size_in_px_);
+
   if (!icon_purpose_to_read.has_value()) {
     MaybeLoadFallbackOrCompleteEmpty();
     return;
   }
 
+  // Per https://www.w3.org/TR/appmanifest/#icon-masks, we apply a white
+  // background in case the maskable icon contains transparent pixels in its
+  // safe zone, and clear the standard icon effect, apply the mask to the icon
+  // without shrinking it.
+  if (icon_purpose_to_read.value() == IconPurpose::MASKABLE) {
+    icon_effects_ = static_cast<apps::IconEffects>(
+        icon_effects_ & ~apps::IconEffects::kCrOsStandardIcon);
+    icon_effects_ = static_cast<apps::IconEffects>(
+        icon_effects_ | apps::IconEffects::kCrOsStandardBackground);
+    icon_effects_ = static_cast<apps::IconEffects>(
+        icon_effects_ | apps::IconEffects::kCrOsStandardMask);
+  }
+
   switch (icon_type_) {
     case apps::mojom::IconType::kCompressed:
       if (icon_effects_ == apps::IconEffects::kNone &&
@@ -1041,9 +1070,13 @@
   }
 
   if (icon_effects & IconEffects::kCrOsStandardMask) {
-    auto mask_image = LoadMaskImage(GetScaleToSize(*image_skia));
-    *image_skia =
-        gfx::ImageSkiaOperations::CreateMaskedImage(*image_skia, mask_image);
+    if (icon_effects & IconEffects::kCrOsStandardBackground) {
+      *image_skia = apps::ApplyBackgroundAndMask(*image_skia);
+    } else {
+      auto mask_image = LoadMaskImage(GetScaleToSize(*image_skia));
+      *image_skia =
+          gfx::ImageSkiaOperations::CreateMaskedImage(*image_skia, mask_image);
+    }
   }
 
   if (icon_effects & IconEffects::kCrOsStandardIcon) {
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index 7bb928f..a01de13 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/apps/app_service/file_utils.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_icon.h"
@@ -33,6 +34,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/arc/app_permissions/arc_app_permissions_bridge.h"
 #include "components/arc/arc_service_manager.h"
+#include "components/arc/arc_util.h"
 #include "components/arc/intent_helper/intent_constants.h"
 #include "components/arc/mojom/app_permissions.mojom.h"
 #include "components/arc/mojom/file_system.mojom.h"
@@ -750,46 +752,88 @@
     return;
   }
 
-  arc::mojom::ActivityNamePtr activity = arc::mojom::ActivityName::New();
-  activity->package_name = app_info->package_name;
-  activity->activity_name = app_info->activity;
+  if (app_info->ready) {
+    arc::mojom::ActivityNamePtr activity = arc::mojom::ActivityName::New();
+    activity->package_name = app_info->package_name;
+    activity->activity_name = app_info->activity;
 
-  // At the moment, the only case we have mime_type field set is to share
-  // files, in this case, convert the file urls to content urls and use
-  // arc file system instance to launch the app with files.
-  if (intent->mime_type.has_value()) {
-    if (!intent->file_urls.has_value()) {
-      LOG(ERROR) << "Share files failed, share intent is not valid";
+    // At the moment, the only case we have mime_type field set is to share
+    // files, in this case, convert the file urls to content urls and use
+    // arc file system instance to launch the app with files.
+    if (intent->mime_type.has_value()) {
+      if (!intent->file_urls.has_value()) {
+        LOG(ERROR) << "Share files failed, share intent is not valid";
+        return;
+      }
+      file_manager::util::ConvertToContentUrls(
+          apps::GetFileSystemURL(profile_, intent->file_urls.value()),
+          base::BindOnce(&OnContentUrlResolved, std::move(intent),
+                         std::move(activity)));
       return;
     }
-    file_manager::util::ConvertToContentUrls(
-        apps::GetFileSystemURL(profile_, intent->file_urls.value()),
-        base::BindOnce(&OnContentUrlResolved, std::move(intent),
-                       std::move(activity)));
+
+    auto* arc_service_manager = arc::ArcServiceManager::Get();
+    arc::mojom::IntentHelperInstance* instance = nullptr;
+    if (arc_service_manager) {
+      instance = ARC_GET_INSTANCE_FOR_METHOD(
+          arc_service_manager->arc_bridge_service()->intent_helper(),
+          HandleIntent);
+    }
+    if (!instance) {
+      return;
+    }
+
+    auto arc_intent = CreateArcIntent(std::move(intent));
+
+    if (!arc_intent) {
+      LOG(ERROR) << "Launch App failed, launch intent is not valid";
+      return;
+    }
+
+    instance->HandleIntent(std::move(arc_intent), std::move(activity));
+
+    prefs->SetLastLaunchTime(app_id);
     return;
   }
 
-  auto* arc_service_manager = arc::ArcServiceManager::Get();
-  arc::mojom::IntentHelperInstance* instance = nullptr;
-  if (arc_service_manager) {
-    instance = ARC_GET_INSTANCE_FOR_METHOD(
-        arc_service_manager->arc_bridge_service()->intent_helper(),
-        HandleIntent);
+  if (arc::IsArcPlayStoreEnabledForProfile(profile_)) {
+    // Handle the case when default app tries to re-activate OptIn flow.
+    if (arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile_) &&
+        !arc::ArcSessionManager::Get()->enable_requested() &&
+        prefs->IsDefault(app_id)) {
+      arc::SetArcPlayStoreEnabledForProfile(profile_, true);
+      // PlayStore item has special handling for shelf controllers. In order
+      // to avoid unwanted initial animation for PlayStore item do not create
+      // deferred launch request when PlayStore item enables Google Play
+      // Store.
+      if (app_id == arc::kPlayStoreAppId) {
+        prefs->SetLastLaunchTime(app_id);
+        return;
+      }
+    }
+  } else {
+    if (prefs->IsDefault(app_id)) {
+      // The setting can fail if the preference is managed.  However, the
+      // caller is responsible to not call this function in such case.  DCHECK
+      // is here to prevent possible mistake.
+      if (!arc::SetArcPlayStoreEnabledForProfile(profile_, true)) {
+        return;
+      }
+      DCHECK(arc::IsArcPlayStoreEnabledForProfile(profile_));
+
+      // PlayStore item has special handling for shelf controllers. In order
+      // to avoid unwanted initial animation for PlayStore item do not create
+      // deferred launch request when PlayStore item enables Google Play
+      // Store.
+      if (app_id == arc::kPlayStoreAppId) {
+        prefs->SetLastLaunchTime(app_id);
+        return;
+      }
+    } else {
+      // Only reachable when ARC always starts.
+      DCHECK(arc::ShouldArcAlwaysStart());
+    }
   }
-  if (!instance) {
-    return;
-  }
-
-  auto arc_intent = CreateArcIntent(std::move(intent));
-
-  if (!arc_intent) {
-    LOG(ERROR) << "Launch App failed, launch intent is not valid";
-    return;
-  }
-
-  instance->HandleIntent(std::move(arc_intent), std::move(activity));
-
-  prefs->SetLastLaunchTime(app_id);
 }
 
 void ArcApps::SetPermission(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/web_apps_chromeos.cc b/chrome/browser/apps/app_service/web_apps_chromeos.cc
index b781aca..a0a7df2 100644
--- a/chrome/browser/apps/app_service/web_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/web_apps_chromeos.cc
@@ -393,10 +393,6 @@
                              icon_effects | IconEffects::kCrOsStandardMask)
                        : static_cast<IconEffects>(
                              icon_effects | IconEffects::kCrOsStandardIcon);
-
-    // TODO(crbug.com/1083331): If the icon is maskable, modify the icon effect,
-    // don't apply the kResizeAndPad effect to shrink the icon, add the
-    // kCrOsStandardBackground and kCrOsStandardMask icon effects.
   } else {
     icon_effects =
         static_cast<IconEffects>(icon_effects | IconEffects::kResizeAndPad);
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc
index 4f2485d8..621d6f2 100644
--- a/chrome/browser/banners/app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -223,7 +223,7 @@
   if (app_id.has_value() && *app_id == installed_app_id &&
       registrar().GetAppUserDisplayMode(*app_id) ==
           blink::mojom::DisplayMode::kStandalone) {
-    OnInstall(registrar().GetAppDisplayMode(*app_id));
+    OnInstall(registrar().GetEffectiveDisplayModeFromManifest(*app_id));
     SetInstallableWebAppCheckResult(InstallableWebAppCheckResult::kNo);
   }
 }
diff --git a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
index 1f3f82e..6d158b3 100644
--- a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/banners/app_banner_manager_browsertest_base.h"
 #include "chrome/browser/banners/app_banner_manager_desktop.h"
@@ -34,6 +35,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/common/extension.h"
@@ -64,8 +66,30 @@
     chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
   }
 
+  AppBannerManagerDesktopBrowserTest(
+      const AppBannerManagerDesktopBrowserTest&) = delete;
+  AppBannerManagerDesktopBrowserTest& operator=(
+      const AppBannerManagerDesktopBrowserTest&) = delete;
+};
+
+// A dedicated test fixture for DisplayOverride, which is supported
+// only for the new web apps mode, and requires a command line switch
+// to enable manifest parsing.
+class AppBannerManagerDesktopBrowserTest_DisplayOverride
+    : public AppBannerManagerDesktopBrowserTest {
+ public:
+  AppBannerManagerDesktopBrowserTest_DisplayOverride() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kWebAppManifestDisplayOverride);
+  }
+
+  AppBannerManagerDesktopBrowserTest_DisplayOverride(
+      const AppBannerManagerDesktopBrowserTest_DisplayOverride&) = delete;
+  AppBannerManagerDesktopBrowserTest_DisplayOverride& operator=(
+      const AppBannerManagerDesktopBrowserTest_DisplayOverride&) = delete;
+
  private:
-  DISALLOW_COPY_AND_ASSIGN(AppBannerManagerDesktopBrowserTest);
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest,
@@ -328,4 +352,103 @@
   EXPECT_TRUE(manager->IsPromptAvailableForTesting());
 }
 
+IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest_DisplayOverride,
+                       InstallPromptAfterUserMenuInstall) {
+  base::HistogramTester tester;
+
+  TestAppBannerManagerDesktop* manager =
+      TestAppBannerManagerDesktop::FromWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents());
+
+  {
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+
+    ui_test_utils::NavigateToURL(
+        browser(), GetBannerURLWithManifestAndQuery(
+                       "/banners/manifest_display_override.json", "action",
+                       "stash_event"));
+    run_loop.Run();
+    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+  }
+
+  // Install the app via the menu instead of the banner.
+  chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
+  browser()->command_controller()->ExecuteCommand(IDC_INSTALL_PWA);
+  manager->AwaitAppInstall();
+  chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
+
+  EXPECT_FALSE(manager->IsPromptAvailableForTesting());
+
+  tester.ExpectUniqueSample(kInstallDisplayModeHistogram,
+                            blink::mojom::DisplayMode::kMinimalUi, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest_DisplayOverride,
+                       WebAppBannerResolvesUserChoice) {
+  base::HistogramTester tester;
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  auto* manager = TestAppBannerManagerDesktop::FromWebContents(web_contents);
+
+  {
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+
+    ui_test_utils::NavigateToURL(
+        browser(),
+        GetBannerURLWithManifestAndQuery(
+            "/banners/manifest_display_override_display_is_browser.json",
+            "action", "stash_event"));
+    run_loop.Run();
+    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+  }
+
+  {
+    // Trigger the installation prompt and wait for installation to occur.
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+    ExecuteScript(browser(), "callStashedPrompt();", true /* with_gesture */);
+    run_loop.Run();
+    EXPECT_EQ(State::COMPLETE, manager->state());
+  }
+
+  // Ensure that the userChoice promise resolves.
+  const base::string16 title = base::ASCIIToUTF16("Got userChoice: accepted");
+  content::TitleWatcher watcher(web_contents, title);
+  EXPECT_EQ(title, watcher.WaitAndGetTitle());
+
+  tester.ExpectUniqueSample(kInstallDisplayModeHistogram,
+                            blink::mojom::DisplayMode::kStandalone, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest_DisplayOverride,
+                       PolicyAppInstalled_NoPrompt) {
+  TestAppBannerManagerDesktop* manager =
+      TestAppBannerManagerDesktop::FromWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents());
+
+  // Install web app by policy.
+  web_app::ExternalInstallOptions options =
+      web_app::CreateInstallOptions(GetBannerURLWithManifest(
+          "/banners/manifest_display_override_contains_browser.json"));
+  options.install_source = web_app::ExternalInstallSource::kExternalPolicy;
+  options.user_display_mode = web_app::DisplayMode::kBrowser;
+  web_app::PendingAppManagerInstall(browser()->profile(), options);
+
+  // Run promotability check.
+  {
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+
+    ui_test_utils::NavigateToURL(browser(), GetBannerURL());
+    run_loop.Run();
+    EXPECT_EQ(State::COMPLETE, manager->state());
+  }
+
+  EXPECT_EQ(AppBannerManager::InstallableWebAppCheckResult::kNoAlreadyInstalled,
+            manager->GetInstallableWebAppCheckResultForTesting());
+  EXPECT_FALSE(manager->IsPromptAvailableForTesting());
+}
+
 }  // namespace banners
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 55d07ac..513fedf 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -118,6 +118,7 @@
     "//chromeos/components/print_management/mojom",
     "//chromeos/components/proximity_auth",
     "//chromeos/components/quick_answers/public/cpp:prefs",
+    "//chromeos/components/remote_apps/mojom",
     "//chromeos/components/scanning",
     "//chromeos/components/smbfs",
     "//chromeos/components/smbfs/mojom",
@@ -2418,12 +2419,15 @@
     "release_notes/release_notes_storage.h",
     "remote_apps/id_generator.cc",
     "remote_apps/id_generator.h",
+    "remote_apps/remote_apps_impl.cc",
+    "remote_apps/remote_apps_impl.h",
     "remote_apps/remote_apps_manager.cc",
     "remote_apps/remote_apps_manager.h",
     "remote_apps/remote_apps_manager_factory.cc",
     "remote_apps/remote_apps_manager_factory.h",
     "remote_apps/remote_apps_model.cc",
     "remote_apps/remote_apps_model.h",
+    "remote_apps/remote_apps_types.h",
     "reset/metrics.h",
     "scanning/lorgnette_scanner_manager.cc",
     "scanning/lorgnette_scanner_manager.h",
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
index 8e5abb7..7f1255a4 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
 
+#include <memory>
+#include <utility>
+
 #include "ash/shell.h"
 #include "base/feature_list.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
@@ -16,8 +19,11 @@
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/test/connection_holder_util.h"
 #include "components/arc/test/fake_accessibility_helper_instance.h"
+#include "components/exo/buffer.h"
+#include "components/exo/client_controlled_accelerators.h"
 #include "components/exo/shell_surface.h"
 #include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
 #include "components/exo/test/exo_test_helper.h"
 #include "components/exo/wm_helper.h"
 #include "components/exo/wm_helper_chromeos.h"
@@ -29,6 +35,12 @@
 
 namespace arc {
 
+struct ArcTestWindow {
+  std::unique_ptr<exo::Buffer> buffer;
+  std::unique_ptr<exo::Surface> surface;
+  std::unique_ptr<exo::ClientControlledShellSurface> shell_surface;
+};
+
 class ArcAccessibilityHelperBridgeBrowserTest : public InProcessBrowserTest {
   void SetUpCommandLine(base::CommandLine* command_line) override {
     arc::SetArcAvailableCommandLineForTesting(command_line);
@@ -61,6 +73,25 @@
   }
 
  protected:
+  // Create and initialize a window for this test, i.e. an Arc++-specific
+  // version of ExoTestHelper::CreateWindow.
+  ArcTestWindow MakeTestWindow(std::string name) {
+    ArcTestWindow ret;
+    exo::test::ExoTestHelper helper;
+    ret.surface = std::make_unique<exo::Surface>();
+    ret.buffer = std::make_unique<exo::Buffer>(
+        helper.CreateGpuMemoryBuffer(gfx::Size(640, 480)));
+    ret.shell_surface = helper.CreateClientControlledShellSurface(
+        ret.surface.get(), /*is_modal=*/false);
+    ret.surface->Attach(ret.buffer.get());
+    ret.surface->Commit();
+
+    // Forcefully set task_id for each window.
+    exo::SetShellApplicationId(
+        ret.shell_surface->GetWidget()->GetNativeWindow(), std::move(name));
+    return ret;
+  }
+
   std::unique_ptr<FakeAccessibilityHelperInstance>
       fake_accessibility_helper_instance_;
   std::unique_ptr<exo::WMHelper> wm_helper_;
@@ -72,38 +103,21 @@
             fake_accessibility_helper_instance_->filter_type());
   EXPECT_FALSE(fake_accessibility_helper_instance_->explore_by_touch_enabled());
 
-  exo::test::ExoTestHelper exo_test_helper;
-  exo::test::ExoTestWindow test_window_1 =
-      exo_test_helper.CreateWindow(640, 480, false /* is_modal */);
-  exo::test::ExoTestWindow test_window_2 =
-      exo_test_helper.CreateWindow(640, 480, false /* is_modal */);
-
-  // Forcefully set task_id to each window.
-  exo::SetShellApplicationId(
-      test_window_1.shell_surface()->GetWidget()->GetNativeWindow(),
-      "org.chromium.arc.1");
-  exo::SetShellApplicationId(
-      test_window_2.shell_surface()->GetWidget()->GetNativeWindow(),
-      "org.chromium.arc.2");
+  ArcTestWindow test_window_1 = MakeTestWindow("org.chromium.arc.1");
+  ArcTestWindow test_window_2 = MakeTestWindow("org.chromium.arc.2");
 
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window_1.shell_surface()->GetWidget()->GetNativeWindow());
-  ASSERT_EQ(test_window_1.shell_surface()->GetWidget()->GetNativeWindow(),
+      test_window_1.shell_surface->GetWidget()->GetNativeWindow());
+  ASSERT_EQ(test_window_1.shell_surface->GetWidget()->GetNativeWindow(),
             activation_client->GetActiveWindow());
   ASSERT_FALSE(
-      test_window_1.shell_surface()
-          ->GetWidget()
-          ->GetNativeWindow()
-          ->GetProperty(
-              aura::client::kAccessibilityTouchExplorationPassThrough));
+      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+          aura::client::kAccessibilityTouchExplorationPassThrough));
   ASSERT_FALSE(
-      test_window_2.shell_surface()
-          ->GetWidget()
-          ->GetNativeWindow()
-          ->GetProperty(
-              aura::client::kAccessibilityTouchExplorationPassThrough));
+      test_window_2.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+          aura::client::kAccessibilityTouchExplorationPassThrough));
 
   chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
@@ -113,11 +127,8 @@
 
   // Use ChromeVox by default. Touch exploration pass through is still false.
   EXPECT_FALSE(
-      test_window_1.shell_surface()
-          ->GetWidget()
-          ->GetNativeWindow()
-          ->GetProperty(
-              aura::client::kAccessibilityTouchExplorationPassThrough));
+      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+          aura::client::kAccessibilityTouchExplorationPassThrough));
 
   ArcAccessibilityHelperBridge* bridge =
       ArcAccessibilityHelperBridge::GetForBrowserContext(browser()->profile());
@@ -126,53 +137,38 @@
   // (current active window) would become true.
   bridge->SetNativeChromeVoxArcSupport(false);
 
-  EXPECT_TRUE(test_window_1.shell_surface()
-                  ->GetWidget()
-                  ->GetNativeWindow()
-                  ->GetProperty(
-                      aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_TRUE(
+      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+          aura::client::kAccessibilityTouchExplorationPassThrough));
 
   // Activate test_window_2 and confirm that it still be false.
   activation_client->ActivateWindow(
-      test_window_2.shell_surface()->GetWidget()->GetNativeWindow());
-  ASSERT_EQ(test_window_2.shell_surface()->GetWidget()->GetNativeWindow(),
+      test_window_2.shell_surface->GetWidget()->GetNativeWindow());
+  ASSERT_EQ(test_window_2.shell_surface->GetWidget()->GetNativeWindow(),
             activation_client->GetActiveWindow());
   EXPECT_FALSE(
-      test_window_2.shell_surface()
-          ->GetWidget()
-          ->GetNativeWindow()
-          ->GetProperty(
-              aura::client::kAccessibilityTouchExplorationPassThrough));
+      test_window_2.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+          aura::client::kAccessibilityTouchExplorationPassThrough));
 
   EXPECT_TRUE(fake_accessibility_helper_instance_->explore_by_touch_enabled());
 }
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest,
                        RequestTreeSyncOnWindowIdChange) {
-  exo::test::ExoTestHelper exo_test_helper;
-  exo::test::ExoTestWindow test_window_1 =
-      exo_test_helper.CreateWindow(640, 480, false /* is_modal */);
-  exo::test::ExoTestWindow test_window_2 =
-      exo_test_helper.CreateWindow(640, 480, false /* is_modal */);
-
-  exo::SetShellApplicationId(
-      test_window_1.shell_surface()->GetWidget()->GetNativeWindow(),
-      "org.chromium.arc.1");
-  exo::SetShellApplicationId(
-      test_window_2.shell_surface()->GetWidget()->GetNativeWindow(),
-      "org.chromium.arc.2");
+  ArcTestWindow test_window_1 = MakeTestWindow("org.chromium.arc.1");
+  ArcTestWindow test_window_2 = MakeTestWindow("org.chromium.arc.2");
 
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window_1.shell_surface()->GetWidget()->GetNativeWindow());
+      test_window_1.shell_surface->GetWidget()->GetNativeWindow());
 
   chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
   exo::SetShellClientAccessibilityId(
-      test_window_1.shell_surface()->GetWidget()->GetNativeWindow(), 10);
+      test_window_1.shell_surface->GetWidget()->GetNativeWindow(), 10);
   exo::SetShellClientAccessibilityId(
-      test_window_2.shell_surface()->GetWidget()->GetNativeWindow(), 20);
+      test_window_2.shell_surface->GetWidget()->GetNativeWindow(), 20);
 
   EXPECT_TRUE(
       fake_accessibility_helper_instance_->last_requested_tree_window_key()
@@ -184,7 +180,7 @@
                ->get_window_id());
 
   activation_client->ActivateWindow(
-      test_window_2.shell_surface()->GetWidget()->GetNativeWindow());
+      test_window_2.shell_surface->GetWidget()->GetNativeWindow());
 
   EXPECT_EQ(
       20U, fake_accessibility_helper_instance_->last_requested_tree_window_key()
@@ -192,7 +188,7 @@
                ->get_window_id());
 
   exo::SetShellClientAccessibilityId(
-      test_window_2.shell_surface()->GetWidget()->GetNativeWindow(), 21);
+      test_window_2.shell_surface->GetWidget()->GetNativeWindow(), 21);
 
   EXPECT_EQ(
       21U, fake_accessibility_helper_instance_->last_requested_tree_window_key()
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index a16a803..94131bd 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -143,6 +143,10 @@
   RunTestURL("foreground/js/file_transfer_controller_unittest_gen.html");
 }
 
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileTypeFiltersController) {
+  RunTestURL("foreground/js/file_type_filters_controller_unittest_gen.html");
+}
+
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileType) {
   RunTestURL("common/js/file_type_unittest_gen.html");
 }
diff --git a/chrome/browser/chromeos/input_method/emoji_suggester.cc b/chrome/browser/chromeos/input_method/emoji_suggester.cc
index 83a734cd..0d6b9e8 100644
--- a/chrome/browser/chromeos/input_method/emoji_suggester.cc
+++ b/chrome/browser/chromeos/input_method/emoji_suggester.cc
@@ -18,6 +18,7 @@
 #include "base/task/thread_pool.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
+#include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/services/ime/constants.h"
@@ -36,11 +37,6 @@
 constexpr char kEmojiMapFilePathTemplateName[] = "/emoji/emoji-map%s.csv";
 const int kMaxSuggestionIndex = 31;
 const int kMaxSuggestionSize = kMaxSuggestionIndex + 1;
-const char kShowEmojiSuggestionMessage[] =
-    "Emoji suggested. Press up or down to choose an emoji. Press enter to "
-    "insert.";
-const char kDismissEmojiSuggestionMessage[] = "Emoji suggestion dismissed.";
-const char kAnnounceCandidateTemplate[] = "%s. %zu of %zu";
 const int kNoneHighlighted = -1;
 
 std::string ReadEmojiDataFromFile() {
@@ -240,7 +236,8 @@
   candidates_ = emoji_map_.at(text);
   properties_.visible = true;
   properties_.candidates = candidates_;
-  properties_.announce_string = kShowEmojiSuggestionMessage;
+  properties_.announce_string =
+      l10n_util::GetStringUTF8(IDS_SUGGESTION_EMOJI_SUGGESTED);
   properties_.show_setting_link =
       GetPrefValue(kEmojiSuggesterShowSettingCount) <
       kEmojiSuggesterShowSettingMaxCount;
@@ -252,9 +249,9 @@
   buttons_.clear();
   for (size_t i = 0; i < candidates_.size(); i++) {
     suggestion_button_.index = i;
-    suggestion_button_.announce_string = base::StringPrintf(
-        kAnnounceCandidateTemplate, base::UTF16ToUTF8(candidates_[i]).c_str(),
-        i + 1, candidates_.size());
+    suggestion_button_.announce_string = l10n_util::GetStringFUTF8(
+        IDS_SUGGESTION_EMOJI_CHOSEN, candidates_[i], base::FormatNumber(i + 1),
+        base::FormatNumber(candidates_.size()));
     buttons_.push_back(suggestion_button_);
   }
   if (properties_.show_setting_link) {
@@ -294,7 +291,8 @@
 void EmojiSuggester::DismissSuggestion() {
   std::string error;
   properties_.visible = false;
-  properties_.announce_string = kDismissEmojiSuggestionMessage;
+  properties_.announce_string =
+      l10n_util::GetStringUTF8(IDS_SUGGESTION_DISMISSED);
   suggestion_handler_->SetAssistiveWindowProperties(context_id_, properties_,
                                                     &error);
   if (!error.empty()) {
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.cc b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
index 76cfe2c..cc1673d 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
@@ -25,7 +25,6 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/strings/grit/components_strings.h"
 #include "third_party/re2/src/re2/re2.h"
-#include "ui/base/l10n/l10n_util.h"
 
 namespace chromeos {
 
@@ -46,8 +45,22 @@
 const char kFirstNameRegex[] = "first name";
 const char kLastNameRegex[] = "last name";
 
-const char kAnnounceAnnotation[] =
-    "Press down to navigate and enter to insert.";
+const char kShowPersonalInfoSuggestionMessage[] =
+    "Personal info suggested. Press down arrow to access; escape to ignore.";
+const char kDismissPersonalInfoSuggestionMessage[] = "Suggestion dismissed.";
+const char kAcceptPersonalInfoSuggestionMessage[] = "Suggestion inserted.";
+
+// The current personal information would only provide one suggestion, so there
+// could be only two possible UI: 1. only one suggestion, 2. one suggestion and
+// one learn more button, and the suggestion is always before the learn more
+// button. So suggestion could be 1 of 1 or 1 of 2 depending on whether the
+// learn more button is displayed, but learn more button can only be 2 of 2.
+const char kSuggestionMessageTemplate[] =
+    "Suggestion %s. Button. Menu item 1 of %d. Press enter to insert; escape "
+    "to dismiss.";
+const char kLearnMoreMessage[] =
+    "Learn more about suggestions. Link. Menu item 2 of 2. Press enter to "
+    "activate; escape to dismiss.";
 const int kNoneHighlighted = -1;
 
 constexpr base::TimeDelta kTtsShowDelay =
@@ -172,7 +185,7 @@
       ui::ime::AssistiveWindowType::kPersonalInfoSuggestion;
   suggestion_button_.index = 0;
   settings_button_.id = ui::ime::ButtonId::kSmartInputsSettingLink;
-  settings_button_.announce_string = l10n_util::GetStringUTF8(IDS_LEARN_MORE);
+  settings_button_.announce_string = kLearnMoreMessage;
   settings_button_.window_type =
       ui::ime::AssistiveWindowType::kPersonalInfoSuggestion;
 }
@@ -335,7 +348,9 @@
     LOG(ERROR) << "Fail to show suggestion. " << error;
   }
 
-  suggestion_button_.announce_string = base::UTF16ToUTF8(text);
+  suggestion_button_.announce_string = base::StringPrintf(
+      kSuggestionMessageTemplate, base::UTF16ToUTF8(text).c_str(),
+      details.show_setting_link ? 2 : 1);
   buttons_.clear();
   buttons_.push_back(suggestion_button_);
   if (details.show_setting_link)
@@ -349,11 +364,9 @@
     IncrementPrefValueTilCapped(kPersonalInfoSuggesterShowSettingCount,
                                 kMaxShowSettingCount);
     tts_handler_->Announce(
-        // TODO(jiwan): Add translation to other languages when we support more
-        // than English.
-        base::StringPrintf("Suggestion %s. %s", base::UTF16ToUTF8(text).c_str(),
-                           show_annotation ? kAnnounceAnnotation : ""),
-        kTtsShowDelay);
+        // TODO(jiwan): Add translation to other languages when we support
+        // more than English.
+        kShowPersonalInfoSuggestionMessage, kTtsShowDelay);
   }
 
   suggestion_shown_ = true;
@@ -398,8 +411,7 @@
   IncrementPrefValueTilCapped(kPersonalInfoSuggesterAcceptanceCount,
                               kMaxAcceptanceCount);
   suggestion_shown_ = false;
-  tts_handler_->Announce(base::StringPrintf(
-      "Inserted suggestion %s.", base::UTF16ToUTF8(suggestion_).c_str()));
+  tts_handler_->Announce(kAcceptPersonalInfoSuggestionMessage);
 
   return true;
 }
@@ -413,6 +425,7 @@
   }
   suggestion_shown_ = false;
   RecordTimeToDismiss(base::TimeTicks::Now() - session_start_);
+  tts_handler_->Announce(kDismissPersonalInfoSuggestionMessage);
 }
 
 void PersonalInfoSuggester::SetButtonHighlighted(
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
index 4a0b6fa..20525528 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
@@ -464,15 +464,21 @@
   tts_handler_->VerifyAnnouncement("");
 
   task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
-  tts_handler_->VerifyAnnouncement(base::StringPrintf(
-      "Suggestion %s. Press down to navigate and enter to insert.",
-      base::UTF16ToUTF8(email_).c_str()));
+  tts_handler_->VerifyAnnouncement(
+      "Personal info suggested. Press down arrow to access; escape to ignore.");
 
   SendKeyboardEvent("Down");
   SendKeyboardEvent("Enter");
   task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(200));
-  tts_handler_->VerifyAnnouncement(base::StringPrintf(
-      "Inserted suggestion %s.", base::UTF16ToUTF8(email_).c_str()));
+  tts_handler_->VerifyAnnouncement("Suggestion inserted.");
+
+  suggester_->Suggest(base::UTF8ToUTF16("my email is "));
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1500));
+  tts_handler_->VerifyAnnouncement(
+      "Personal info suggested. Press down arrow to access; escape to ignore.");
+  SendKeyboardEvent("Esc");
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(200));
+  tts_handler_->VerifyAnnouncement("Suggestion dismissed.");
 }
 
 TEST_F(PersonalInfoSuggesterTest, DoNotShowAnnotationAfterMaxAcceptanceCount) {
@@ -486,24 +492,6 @@
   suggestion_handler_->VerifyShowAnnotation(false);
 }
 
-TEST_F(PersonalInfoSuggesterTest, DoNotAnnounceAnnotationWhenTabNotShown) {
-  profile_->set_profile_name(base::UTF16ToUTF8(email_));
-  profile_->GetPrefs()->SetBoolean(
-      ash::prefs::kAccessibilitySpokenFeedbackEnabled, true);
-  DictionaryPrefUpdate update(profile_->GetPrefs(),
-                              prefs::kAssistiveInputFeatureSettings);
-  update->SetIntKey(kPersonalInfoSuggesterAcceptanceCount, kMaxAcceptanceCount);
-
-  suggester_->Suggest(base::UTF8ToUTF16("my email is "));
-  suggestion_handler_->VerifyShowAnnotation(false);
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(500));
-  tts_handler_->VerifyAnnouncement("");
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
-  tts_handler_->VerifyAnnouncement(
-      base::StringPrintf("Suggestion %s. ", base::UTF16ToUTF8(email_).c_str()));
-}
-
 TEST_F(PersonalInfoSuggesterTest, ShowSettingLink) {
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
diff --git a/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc b/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc
index 506abae..d4126031 100644
--- a/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc
+++ b/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc
@@ -131,8 +131,9 @@
   for (const auto& result : results) {
     const int relevance =
         base::ClampToRange(result.relevance, 0, kMaxSearchResultScore);
-    const GURL icon_url =
-        result.icon_url ? GURL(*result.icon_url.get()) : GURL();
+
+    const std::string icon_type =
+        result.icon_type ? *result.icon_type.get() : std::string();
 
     // Calculate the relevance score by matching the query with the title.
     // Results with a match score of 0 are discarded. This will also be used to
@@ -146,7 +147,7 @@
       continue;
 
     auto search_result = std::make_unique<app_list::LauncherSearchResult>(
-        result.item_id, icon_url, relevance, profile_, extension,
+        result.item_id, icon_type, relevance, profile_, extension,
         error_reporter->Duplicate());
     search_result->UpdateFromMatch(tokenized_title, match);
     search_results.push_back(std::move(search_result));
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc
index cf1ea6a..81933c5c 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc
+++ b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc
@@ -21,6 +21,7 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/login/auth/user_context.h"
 #include "components/prefs/pref_service.h"
+#include "components/user_manager/known_user.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -409,6 +410,9 @@
   DismissExpiryNotification();
   PasswordChangeDialog::Dismiss();
   ConfirmPasswordChangeDialog::Dismiss();
+  // We request a new sync token. It will be updated locally and signal the fact
+  // of password change to other devices owned by the user.
+  CreateTokenAsync();
   RecordEvent(InSessionPasswordChangeEvent::kFinishPasswordChange);
 }
 
@@ -422,6 +426,34 @@
   }
 }
 
+void InSessionPasswordChangeManager::OnTokenCreated(
+    const std::string& sync_token) {
+  user_manager::known_user::SetPasswordSyncToken(primary_user_->GetAccountId(),
+                                                 sync_token);
+}
+
+void InSessionPasswordChangeManager::OnTokenFetched(
+    const std::string& sync_token) {
+  // Ignored.
+}
+
+void InSessionPasswordChangeManager::OnTokenVerified(bool is_valid) {
+  // Ignored.
+}
+
+void InSessionPasswordChangeManager::OnApiCallFailed(
+    PasswordSyncTokenFetcher::ErrorType error_type) {
+  // TODO(crbug.com/1112896): Error types will be tracked by UMA histograms.
+  // Going forward we should also consider re-trying token creation depending on
+  // the error_type.
+}
+
+void InSessionPasswordChangeManager::CreateTokenAsync() {
+  password_sync_token_fetcher_ = std::make_unique<PasswordSyncTokenFetcher>(
+      primary_profile_->GetURLLoaderFactory(), primary_profile_, this);
+  password_sync_token_fetcher_->StartTokenCreate();
+}
+
 // static
 InSessionPasswordChangeManager* InSessionPasswordChangeManager::GetNullable() {
   return g_test_instance ? g_test_instance
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h
index 68634f0..fba89ab 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h
+++ b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
 
 class Profile;
@@ -58,8 +59,10 @@
 // long as the primary user session exists  (but only if the primary user's
 // InSessionPasswordChange policy is enabled and the kInSessionPasswordChange
 // feature is enabled).
-class InSessionPasswordChangeManager : public AuthStatusConsumer,
-                                       public ash::SessionActivationObserver {
+class InSessionPasswordChangeManager
+    : public AuthStatusConsumer,
+      public ash::SessionActivationObserver,
+      public PasswordSyncTokenFetcher::Consumer {
  public:
   // Events in the in-session SAML password change flow.
   enum class Event {
@@ -154,16 +157,23 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // AuthStatusConsumer:
+  // AuthStatusConsumer
   void OnAuthFailure(const AuthFailure& error) override;
   void OnPasswordChangeDetected(const UserContext& user_context) override;
   void OnAuthSuccess(const UserContext& user_context) override;
 
-  // ash::SessionActivationObserver:
+  // ash::SessionActivationObserver
   void OnSessionActivated(bool activated) override;
   void OnLockStateChanged(bool locked) override;
 
+  // PasswordSyncTokenFetcher::Consumer
+  void OnTokenCreated(const std::string& sync_token) override;
+  void OnTokenFetched(const std::string& sync_token) override;
+  void OnTokenVerified(bool is_valid) override;
+  void OnApiCallFailed(PasswordSyncTokenFetcher::ErrorType error_type) override;
+
  private:
+  void CreateTokenAsync();
   static InSessionPasswordChangeManager* GetNullable();
 
   void NotifyObservers(Event event);
@@ -176,6 +186,7 @@
   int urgent_warning_days_;
   bool renotify_on_unlock_ = false;
   PasswordSource password_source_ = PasswordSource::PASSWORDS_SCRAPED;
+  std::unique_ptr<PasswordSyncTokenFetcher> password_sync_token_fetcher_;
 
   friend class InSessionPasswordChangeManagerTest;
 
diff --git a/chrome/browser/chromeos/remote_apps/DEPS b/chrome/browser/chromeos/remote_apps/DEPS
index 12a0b7b..5d92f21c 100644
--- a/chrome/browser/chromeos/remote_apps/DEPS
+++ b/chrome/browser/chromeos/remote_apps/DEPS
@@ -1,5 +1,5 @@
 specific_include_rules = {
-  "remote_apps_manager_browsertest\.cc": [
+  ".*_browsertest\.cc": [
     "+ash/app_list",
     "+ash/shell.h",
   ],
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_impl.cc b/chrome/browser/chromeos/remote_apps/remote_apps_impl.cc
new file mode 100644
index 0000000..e7b9b50
--- /dev/null
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_impl.cc
@@ -0,0 +1,121 @@
+// Copyright 2020 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/chromeos/remote_apps/remote_apps_impl.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/optional.h"
+#include "base/stl_util.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_manager.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_manager_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/render_frame_host.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/behavior_feature.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/features/feature_provider.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr char kErrNotReady[] = "Manager for remote apps is not ready";
+constexpr char kErrFolderIdDoesNotExist[] = "Folder ID provided does not exist";
+
+static bool g_bypass_checks_for_testing_ = false;
+
+}  // namespace
+
+// static
+bool RemoteAppsImpl::IsAllowed(content::RenderFrameHost* render_frame_host,
+                               const extensions::Extension* extension) {
+  if (!render_frame_host || !extension)
+    return false;
+
+  Profile* profile =
+      Profile::FromBrowserContext(render_frame_host->GetBrowserContext());
+  DCHECK(profile);
+  // RemoteApps are not available for non-managed guest sessions.
+  if (!RemoteAppsManagerFactory::GetForProfile(profile))
+    return false;
+
+  if (g_bypass_checks_for_testing_)
+    return true;
+
+  const extensions::Feature* feature =
+      extensions::FeatureProvider::GetBehaviorFeature(
+          extensions::behavior_feature::kKeyImprivataInSessionExtension);
+  DCHECK(feature);
+  return feature->IsAvailableToExtension(extension).is_available();
+}
+
+// static
+void RemoteAppsImpl::SetBypassChecksForTesting(bool bypass_checks_for_testing) {
+  g_bypass_checks_for_testing_ = bypass_checks_for_testing;
+}
+
+RemoteAppsImpl::RemoteAppsImpl(RemoteAppsManager* manager) : manager_(manager) {
+  DCHECK(manager);
+}
+
+RemoteAppsImpl::~RemoteAppsImpl() = default;
+
+void RemoteAppsImpl::Bind(
+    mojo::PendingReceiver<remote_apps::mojom::RemoteApps> pending_remote_apps,
+    mojo::PendingRemote<remote_apps::mojom::RemoteAppLaunchObserver>
+        pending_observer) {
+  receivers_.Add(this, std::move(pending_remote_apps));
+  app_launch_observers_.Add(
+      mojo::Remote<remote_apps::mojom::RemoteAppLaunchObserver>(
+          std::move(pending_observer)));
+}
+
+void RemoteAppsImpl::AddFolder(const std::string& name,
+                               AddFolderCallback callback) {
+  const std::string& folder_id = manager_->AddFolder(name);
+  std::move(callback).Run(folder_id, base::nullopt);
+}
+
+void RemoteAppsImpl::AddApp(const std::string& name,
+                            const std::string& folder_id,
+                            const GURL& icon_url,
+                            AddAppCallback callback) {
+  manager_->AddApp(
+      name, folder_id, icon_url,
+      base::BindOnce(&RemoteAppsImpl::OnAppAdded, weak_factory_.GetWeakPtr(),
+                     std::move(callback)));
+}
+
+void RemoteAppsImpl::OnAppLaunched(const std::string& id) {
+  if (!base::Contains(app_ids_, id))
+    return;
+  for (auto& observer : app_launch_observers_)
+    observer->OnRemoteAppLaunched(id);
+}
+
+void RemoteAppsImpl::OnAppAdded(AddAppCallback callback,
+                                const std::string& id,
+                                RemoteAppsError error) {
+  switch (error) {
+    case RemoteAppsError::kNotReady:
+      std::move(callback).Run(base::nullopt, kErrNotReady);
+      return;
+    case RemoteAppsError::kFolderIdDoesNotExist:
+      std::move(callback).Run(base::nullopt, kErrFolderIdDoesNotExist);
+      return;
+    case RemoteAppsError::kNone:
+      app_ids_.insert(id);
+      std::move(callback).Run(id, base::nullopt);
+      return;
+    case RemoteAppsError::kAppIdDoesNotExist:
+      // Only occurs when deleting an app, which is not yet implemented in the
+      // API.
+      DCHECK(false);
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_impl.h b/chrome/browser/chromeos/remote_apps/remote_apps_impl.h
new file mode 100644
index 0000000..3102800
--- /dev/null
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_impl.h
@@ -0,0 +1,76 @@
+// Copyright 2020 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_CHROMEOS_REMOTE_APPS_REMOTE_APPS_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_REMOTE_APPS_REMOTE_APPS_IMPL_H_
+
+#include <set>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_types.h"
+#include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+#include "url/gurl.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace extensions {
+class Extension;
+}
+
+namespace chromeos {
+
+class RemoteAppsManager;
+
+// Forwards calls to RemoteAppsManager via mojo. Also keeps track of apps added
+// by the extension for |OnAppLaunched()|.
+class RemoteAppsImpl : public remote_apps::mojom::RemoteApps {
+ public:
+  static bool IsAllowed(content::RenderFrameHost* render_frame_host,
+                        const extensions::Extension* extension);
+
+  static void SetBypassChecksForTesting(bool bypass_checks_for_testing);
+
+  explicit RemoteAppsImpl(RemoteAppsManager* manager);
+  RemoteAppsImpl(const RemoteAppsImpl&) = delete;
+  RemoteAppsImpl& operator=(const RemoteAppsImpl&) = delete;
+  ~RemoteAppsImpl() override;
+
+  void Bind(
+      mojo::PendingReceiver<remote_apps::mojom::RemoteApps> pending_remote_apps,
+      mojo::PendingRemote<remote_apps::mojom::RemoteAppLaunchObserver>
+          pending_observer);
+
+  // remote_apps::mojom::RemoteApps:
+  void AddFolder(const std::string& name, AddFolderCallback callback) override;
+  void AddApp(const std::string& name,
+              const std::string& folder_id,
+              const GURL& icon_url,
+              AddAppCallback callback) override;
+
+  void OnAppLaunched(const std::string& id);
+
+ private:
+  void OnAppAdded(AddAppCallback callback,
+                  const std::string& id,
+                  RemoteAppsError error);
+
+  RemoteAppsManager* manager_ = nullptr;
+  std::set<std::string> app_ids_;
+  mojo::ReceiverSet<remote_apps::mojom::RemoteApps> receivers_;
+  mojo::RemoteSet<remote_apps::mojom::RemoteAppLaunchObserver>
+      app_launch_observers_;
+  base::WeakPtrFactory<RemoteAppsImpl> weak_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_REMOTE_APPS_REMOTE_APPS_IMPL_H_
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_impl_browsertest.cc b/chrome/browser/chromeos/remote_apps/remote_apps_impl_browsertest.cc
new file mode 100644
index 0000000..8a79a6da
--- /dev/null
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_impl_browsertest.cc
@@ -0,0 +1,184 @@
+// Copyright 2020 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/chromeos/remote_apps/remote_apps_impl.h"
+
+#include <string>
+#include <vector>
+
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/model/app_list_item.h"
+#include "ash/app_list/model/app_list_model.h"
+#include "ash/shell.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h"
+#include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/remote_apps/id_generator.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_manager.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_manager_factory.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_model.h"
+#include "chrome/browser/extensions/chrome_test_extension_loader.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/common/chrome_paths.h"
+#include "chromeos/constants/chromeos_switches.h"
+#include "components/policy/proto/chrome_device_policy.pb.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+#include "content/public/test/browser_test.h"
+#include "extensions/browser/api/test/test_api.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/switches.h"
+#include "extensions/test/extension_test_message_listener.h"
+#include "extensions/test/result_catcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace {
+
+// ID of extension found at chrome/test/data/remote_apps.
+constexpr char kExtensionId[] = "ceddkihciiemhnpnhbndbinppokgoidh";
+
+constexpr char kId1[] = "Id 1";
+constexpr char kId2[] = "Id 2";
+constexpr char kId3[] = "Id 3";
+
+}  // namespace
+
+class RemoteAppsImplBrowsertest : public policy::DevicePolicyCrosBrowserTest {
+ public:
+  RemoteAppsImplBrowsertest() : policy::DevicePolicyCrosBrowserTest() {}
+
+  // DevicePolicyCrosBrowserTest:
+  void SetUp() override {
+    app_list::AppListSyncableServiceFactory::SetUseInTesting(true);
+    RemoteAppsImpl::SetBypassChecksForTesting(true);
+    DevicePolicyCrosBrowserTest::SetUp();
+  }
+
+  // DevicePolicyCrosBrowserTest:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(chromeos::switches::kLoginManager);
+    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
+    command_line->AppendSwitchASCII(
+        extensions::switches::kAllowlistedExtensionID, kExtensionId);
+  }
+
+  // DevicePolicyCrosBrowserTest:
+  void SetUpOnMainThread() override {
+    policy::DevicePolicyCrosBrowserTest::SetUpOnMainThread();
+
+    SetUpDeviceLocalAccountPolicy();
+    WizardController::SkipPostLoginScreensForTesting();
+    SessionStateWaiter(session_manager::SessionState::ACTIVE).Wait();
+  }
+
+  void SetUpDeviceLocalAccountPolicy() {
+    enterprise_management::DeviceLocalAccountsProto* const
+        device_local_accounts =
+            device_policy()->payload().mutable_device_local_accounts();
+    enterprise_management::DeviceLocalAccountInfoProto* const account =
+        device_local_accounts->add_account();
+    account->set_account_id("user@test");
+    account->set_type(enterprise_management::DeviceLocalAccountInfoProto::
+                          ACCOUNT_TYPE_PUBLIC_SESSION);
+    device_local_accounts->set_auto_login_id("user@test");
+    device_local_accounts->set_auto_login_delay(0);
+    RefreshDevicePolicy();
+  }
+
+  void LoadExtensionAndRunTest(const std::string& test_name) {
+    config_.SetKey("customArg", base::Value(test_name));
+    extensions::TestGetConfigFunction::set_test_config_state(&config_);
+
+    base::FilePath test_dir_path;
+    base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir_path);
+    base::FilePath extension_path =
+        test_dir_path.AppendASCII("extensions/remote_apps/extension");
+    base::FilePath pem_path =
+        test_dir_path.AppendASCII("extensions/remote_apps/remote_apps.pem");
+
+    user_manager::User* user =
+        user_manager::UserManager::Get()->GetActiveUser();
+    Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
+
+    std::unique_ptr<FakeIdGenerator> id_generator =
+        std::make_unique<FakeIdGenerator>(
+            std::vector<std::string>{kId1, kId2, kId3});
+    RemoteAppsManagerFactory::GetForProfile(profile)
+        ->GetModelForTesting()
+        ->SetIdGeneratorForTesting(std::move(id_generator));
+
+    extensions::ChromeTestExtensionLoader loader(profile);
+    loader.set_location(extensions::Manifest::EXTERNAL_POLICY);
+    loader.set_pack_extension(true);
+    loader.set_pem_path(pem_path);
+    ASSERT_TRUE(loader.LoadExtension(extension_path));
+  }
+
+  ash::AppListItem* GetAppListItem(const std::string& id) {
+    ash::AppListControllerImpl* controller =
+        ash::Shell::Get()->app_list_controller();
+    ash::AppListModel* model = controller->GetModel();
+    return model->FindItem(id);
+  }
+
+ private:
+  base::DictionaryValue config_;
+  chromeos::LocalPolicyTestServerMixin local_policy_mixin_{&mixin_host_};
+};
+
+IN_PROC_BROWSER_TEST_F(RemoteAppsImplBrowsertest, AddApp) {
+  extensions::ResultCatcher catcher;
+  LoadExtensionAndRunTest("AddApp");
+  ASSERT_TRUE(catcher.GetNextResult());
+
+  ash::AppListItem* app = GetAppListItem(kId1);
+  EXPECT_FALSE(app->is_folder());
+  EXPECT_EQ("App 1", app->name());
+}
+
+IN_PROC_BROWSER_TEST_F(RemoteAppsImplBrowsertest, AddFolderAndApps) {
+  extensions::ResultCatcher catcher;
+  LoadExtensionAndRunTest("AddFolderAndApps");
+  ASSERT_TRUE(catcher.GetNextResult());
+
+  ash::AppListItem* folder = GetAppListItem(kId1);
+  EXPECT_TRUE(folder->is_folder());
+  EXPECT_EQ("Folder 1", folder->name());
+  EXPECT_EQ(2u, folder->ChildItemCount());
+  EXPECT_TRUE(folder->FindChildItem(kId2));
+  EXPECT_TRUE(folder->FindChildItem(kId3));
+
+  ash::AppListItem* app1 = GetAppListItem(kId2);
+  EXPECT_EQ(kId1, app1->folder_id());
+
+  ash::AppListItem* app2 = GetAppListItem(kId3);
+  EXPECT_EQ(kId1, app2->folder_id());
+}
+
+IN_PROC_BROWSER_TEST_F(RemoteAppsImplBrowsertest, OnRemoteAppLaunched) {
+  extensions::ResultCatcher catcher;
+  ExtensionTestMessageListener listener("Remote app added",
+                                        /*will_reply=*/false);
+  listener.set_extension_id(kExtensionId);
+  LoadExtensionAndRunTest("OnRemoteAppLaunched");
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+  ChromeLauncherController::instance()->LaunchApp(
+      ash::ShelfID(kId1), ash::ShelfLaunchSource::LAUNCH_FROM_APP_LIST,
+      /*event_flags=*/0, /*display_id=*/0);
+  ASSERT_TRUE(catcher.GetNextResult());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_manager.cc b/chrome/browser/chromeos/remote_apps/remote_apps_manager.cc
index ceb25bb..4509fd4 100644
--- a/chrome/browser/chromeos/remote_apps/remote_apps_manager.cc
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_manager.cc
@@ -10,6 +10,7 @@
 #include "ash/public/cpp/image_downloader.h"
 #include "base/bind.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
@@ -73,12 +74,13 @@
                                const GURL& icon_url,
                                AddAppCallback callback) {
   if (!is_initialized_) {
-    std::move(callback).Run(std::string(), Error::kNotReady);
+    std::move(callback).Run(std::string(), RemoteAppsError::kNotReady);
     return;
   }
 
   if (!folder_id.empty() && !model_->HasFolder(folder_id)) {
-    std::move(callback).Run(std::string(), Error::kFolderIdDoesNotExist);
+    std::move(callback).Run(std::string(),
+                            RemoteAppsError::kFolderIdDoesNotExist);
     return;
   }
 
@@ -88,15 +90,15 @@
   remote_apps_->AddApp(info);
 }
 
-RemoteAppsManager::Error RemoteAppsManager::DeleteApp(const std::string& id) {
+RemoteAppsError RemoteAppsManager::DeleteApp(const std::string& id) {
   // Check if app was added but |HandleOnAppAdded| has not been called.
   if (!model_->HasApp(id) ||
       add_app_callback_map_.find(id) != add_app_callback_map_.end())
-    return Error::kAppIdDoesNotExist;
+    return RemoteAppsError::kAppIdDoesNotExist;
 
   model_->DeleteApp(id);
   remote_apps_->DeleteApp(id);
-  return Error::kNone;
+  return RemoteAppsError::kNone;
 }
 
 std::string RemoteAppsManager::AddFolder(const std::string& folder_name) {
@@ -105,17 +107,16 @@
   return folder_info.id;
 }
 
-RemoteAppsManager::Error RemoteAppsManager::DeleteFolder(
-    const std::string& folder_id) {
+RemoteAppsError RemoteAppsManager::DeleteFolder(const std::string& folder_id) {
   if (!model_->HasFolder(folder_id))
-    return Error::kFolderIdDoesNotExist;
+    return RemoteAppsError::kFolderIdDoesNotExist;
 
   // Move all items out of the folder. Empty folders are automatically deleted.
   RemoteAppsModel::FolderInfo& folder_info = model_->GetFolderInfo(folder_id);
   for (const auto& app : folder_info.items)
     model_updater_->MoveItemToFolder(app, std::string());
   model_->DeleteFolder(folder_id);
-  return Error::kNone;
+  return RemoteAppsError::kNone;
 }
 
 void RemoteAppsManager::AddObserver(Observer* observer) {
@@ -126,8 +127,22 @@
   observer_list_.RemoveObserver(observer);
 }
 
+void RemoteAppsManager::BindInterface(
+    mojo::PendingReceiver<remote_apps::mojom::RemoteAppsFactory>
+        pending_remote_apps_factory) {
+  receivers_.Add(this, std::move(pending_remote_apps_factory));
+}
+
 void RemoteAppsManager::Shutdown() {}
 
+void RemoteAppsManager::Create(
+    mojo::PendingReceiver<remote_apps::mojom::RemoteApps> pending_remote_apps,
+    mojo::PendingRemote<remote_apps::mojom::RemoteAppLaunchObserver>
+        pending_observer) {
+  remote_apps_impl_.Bind(std::move(pending_remote_apps),
+                         std::move(pending_observer));
+}
+
 const std::map<std::string, RemoteAppsModel::AppInfo>&
 RemoteAppsManager::GetApps() {
   return model_->GetAllAppInfo();
@@ -136,6 +151,7 @@
 void RemoteAppsManager::LaunchApp(const std::string& id) {
   for (Observer& observer : observer_list_)
     observer.OnAppLaunched(id);
+  remote_apps_impl_.OnAppLaunched(id);
 }
 
 gfx::ImageSkia RemoteAppsManager::GetIcon(const std::string& id) {
@@ -214,7 +230,7 @@
   auto it = add_app_callback_map_.find(id);
   DCHECK(it != add_app_callback_map_.end())
       << "Missing callback for id: " << id;
-  std::move(it->second).Run(id, Error::kNone);
+  std::move(it->second).Run(id, RemoteAppsError::kNone);
   add_app_callback_map_.erase(it);
 }
 
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_manager.h b/chrome/browser/chromeos/remote_apps/remote_apps_manager.h
index 0ca73492..78c7efe 100644
--- a/chrome/browser/chromeos/remote_apps/remote_apps_manager.h
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_manager.h
@@ -13,11 +13,16 @@
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/apps/app_service/remote_apps.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_impl.h"
 #include "chrome/browser/chromeos/remote_apps/remote_apps_model.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_types.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater_observer.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
+#include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 
 class AppListModelUpdater;
 class ChromeAppListItem;
@@ -33,6 +38,8 @@
 
 namespace chromeos {
 
+class RemoteAppsImpl;
+
 // KeyedService which manages the logic for |AppType::kRemote| in AppService.
 // This service is only created for Managed Guest Sessions.
 // The IDs of the added apps and folders are GUIDs generated using
@@ -40,16 +47,9 @@
 class RemoteAppsManager : public KeyedService,
                           public apps::RemoteApps::Delegate,
                           public app_list::AppListSyncableService::Observer,
-                          public AppListModelUpdaterObserver {
+                          public AppListModelUpdaterObserver,
+                          public remote_apps::mojom::RemoteAppsFactory {
  public:
-  enum class Error {
-    kNone = 0,
-    kAppIdDoesNotExist,
-    kFolderIdDoesNotExist,
-    // Manager has not been initialized.
-    kNotReady,
-  };
-
   class Observer : public base::CheckedObserver {
    public:
     ~Observer() override = default;
@@ -73,8 +73,12 @@
 
   bool is_initialized() const { return is_initialized_; }
 
+  void BindInterface(
+      mojo::PendingReceiver<remote_apps::mojom::RemoteAppsFactory>
+          pending_remote_apps_factory);
+
   using AddAppCallback =
-      base::OnceCallback<void(const std::string& id, Error error)>;
+      base::OnceCallback<void(const std::string& id, RemoteAppsError error)>;
 
   // Adds a app with the given |name|. If |folder_id| is non-empty, the app is
   // added to the folder with the given ID. The icon of the app is an image
@@ -92,7 +96,7 @@
 
   // Deletes the app with id |id|.
   // Deleting a non-existent app will result in an error.
-  Error DeleteApp(const std::string& id);
+  RemoteAppsError DeleteApp(const std::string& id);
 
   // Adds a folder with |folder_name|. Note that empty folders are not
   // shown in the launcher. Returns the ID for the added folder.
@@ -101,7 +105,7 @@
   // Deletes the folder with id |folder_id|. All items in the folder are moved
   // to the top-level in the launcher.
   // Deleting a non-existent folder will result in an error.
-  Error DeleteFolder(const std::string& folder_id);
+  RemoteAppsError DeleteFolder(const std::string& folder_id);
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
@@ -109,6 +113,12 @@
   // KeyedService:
   void Shutdown() override;
 
+  // remote_apps::mojom::RemoteAppsFactory:
+  void Create(
+      mojo::PendingReceiver<remote_apps::mojom::RemoteApps> pending_remote_apps,
+      mojo::PendingRemote<remote_apps::mojom::RemoteAppLaunchObserver>
+          pending_observer) override;
+
   // apps::RemoteApps::Delegate:
   const std::map<std::string, RemoteAppsModel::AppInfo>& GetApps() override;
   void LaunchApp(const std::string& id) override;
@@ -146,9 +156,11 @@
   app_list::AppListSyncableService* app_list_syncable_service_ = nullptr;
   AppListModelUpdater* model_updater_ = nullptr;
   std::unique_ptr<apps::RemoteApps> remote_apps_;
+  RemoteAppsImpl remote_apps_impl_{this};
   std::unique_ptr<RemoteAppsModel> model_;
   std::unique_ptr<ImageDownloader> image_downloader_;
   base::ObserverList<Observer> observer_list_;
+  mojo::ReceiverSet<remote_apps::mojom::RemoteAppsFactory> receivers_;
   // Map from id to callback. The callback is run after |OnAppUpdate| for the
   // app has been observed.
   std::map<std::string, AddAppCallback> add_app_callback_map_;
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_manager_browsertest.cc b/chrome/browser/chromeos/remote_apps/remote_apps_manager_browsertest.cc
index d374ae1..a7768cb 100644
--- a/chrome/browser/chromeos/remote_apps/remote_apps_manager_browsertest.cc
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_manager_browsertest.cc
@@ -213,35 +213,34 @@
                      const GURL& icon_url) {
     base::RunLoop run_loop;
     std::string id;
-    manager_->AddApp(
-        name, folder_id, icon_url,
-        base::BindOnce(
-            [](base::RepeatingClosure closure, std::string* id_arg,
-               const std::string& id, RemoteAppsManager::Error error) {
-              ASSERT_EQ(RemoteAppsManager::Error::kNone, error);
+    manager_->AddApp(name, folder_id, icon_url,
+                     base::BindOnce(
+                         [](base::RepeatingClosure closure, std::string* id_arg,
+                            const std::string& id, RemoteAppsError error) {
+                           ASSERT_EQ(RemoteAppsError::kNone, error);
 
-              ash::AppListControllerImpl* controller =
-                  ash::Shell::Get()->app_list_controller();
-              ash::AppListModel* model = controller->GetModel();
-              ASSERT_TRUE(model->FindItem(id));
-              *id_arg = id;
+                           ash::AppListControllerImpl* controller =
+                               ash::Shell::Get()->app_list_controller();
+                           ash::AppListModel* model = controller->GetModel();
+                           ASSERT_TRUE(model->FindItem(id));
+                           *id_arg = id;
 
-              closure.Run();
-            },
-            run_loop.QuitClosure(), &id));
+                           closure.Run();
+                         },
+                         run_loop.QuitClosure(), &id));
     run_loop.Run();
     return id;
   }
 
-  RemoteAppsManager::Error DeleteApp(const std::string& id) {
-    RemoteAppsManager::Error error = manager_->DeleteApp(id);
+  RemoteAppsError DeleteApp(const std::string& id) {
+    RemoteAppsError error = manager_->DeleteApp(id);
     // Allow updates to propagate to AppList.
     base::RunLoop().RunUntilIdle();
     return error;
   }
 
-  RemoteAppsManager::Error DeleteFolder(const std::string& id) {
-    RemoteAppsManager::Error error = manager_->DeleteFolder(id);
+  RemoteAppsError DeleteFolder(const std::string& id) {
+    RemoteAppsError error = manager_->DeleteFolder(id);
     // Allow updates to propagate to AppList.
     base::RunLoop().RunUntilIdle();
     return error;
@@ -258,7 +257,7 @@
     waiter.Wait();
   }
 
-  void AddAppAssertError(RemoteAppsManager::Error error,
+  void AddAppAssertError(RemoteAppsError error,
                          const std::string& name,
                          const std::string& folder_id,
                          const GURL& icon_url) {
@@ -266,9 +265,8 @@
     manager_->AddApp(
         name, folder_id, icon_url,
         base::BindOnce(
-            [](base::RepeatingClosure closure,
-               RemoteAppsManager::Error expected_error, const std::string& id,
-               RemoteAppsManager::Error error) {
+            [](base::RepeatingClosure closure, RemoteAppsError expected_error,
+               const std::string& id, RemoteAppsError error) {
               ASSERT_EQ(expected_error, error);
               closure.Run();
             },
@@ -308,8 +306,8 @@
   GURL icon_url("icon_url");
   gfx::ImageSkia icon = CreateTestIcon(32, SK_ColorRED);
 
-  AddAppAssertError(RemoteAppsManager::Error::kFolderIdDoesNotExist, name,
-                    kMissingId, icon_url);
+  AddAppAssertError(RemoteAppsError::kFolderIdDoesNotExist, name, kMissingId,
+                    icon_url);
 }
 
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, AddAppErrorNotReady) {
@@ -318,8 +316,7 @@
   gfx::ImageSkia icon = CreateTestIcon(32, SK_ColorRED);
 
   manager_->SetIsInitializedForTesting(false);
-  AddAppAssertError(RemoteAppsManager::Error::kNotReady, name, std::string(),
-                    icon_url);
+  AddAppAssertError(RemoteAppsError::kNotReady, name, std::string(), icon_url);
 }
 
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, DeleteApp) {
@@ -327,15 +324,14 @@
   AddAppAndWaitForIconChange(kId1, "name", std::string(), GURL("icon_url"),
                              CreateTestIcon(32, SK_ColorRED));
 
-  RemoteAppsManager::Error error = DeleteApp(kId1);
+  RemoteAppsError error = DeleteApp(kId1);
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(RemoteAppsManager::Error::kNone, error);
+  EXPECT_EQ(RemoteAppsError::kNone, error);
   EXPECT_FALSE(GetAppListItem(kId1));
 }
 
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, DeleteAppError) {
-  EXPECT_EQ(RemoteAppsManager::Error::kAppIdDoesNotExist,
-            DeleteApp(kMissingId));
+  EXPECT_EQ(RemoteAppsError::kAppIdDoesNotExist, DeleteApp(kMissingId));
 }
 
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, AddAndDeleteFolder) {
@@ -343,12 +339,11 @@
   // Empty folder has no AppListItem.
   EXPECT_FALSE(GetAppListItem(kId1));
 
-  EXPECT_EQ(RemoteAppsManager::Error::kNone, DeleteFolder(kId1));
+  EXPECT_EQ(RemoteAppsError::kNone, DeleteFolder(kId1));
 }
 
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, DeleteFolderError) {
-  EXPECT_EQ(RemoteAppsManager::Error::kFolderIdDoesNotExist,
-            DeleteFolder(kMissingId));
+  EXPECT_EQ(RemoteAppsError::kFolderIdDoesNotExist, DeleteFolder(kMissingId));
 }
 
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, AddFolderAndApp) {
diff --git a/chrome/browser/chromeos/remote_apps/remote_apps_types.h b/chrome/browser/chromeos/remote_apps/remote_apps_types.h
new file mode 100644
index 0000000..e3d9f00
--- /dev/null
+++ b/chrome/browser/chromeos/remote_apps/remote_apps_types.h
@@ -0,0 +1,20 @@
+// Copyright 2020 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_CHROMEOS_REMOTE_APPS_REMOTE_APPS_TYPES_H_
+#define CHROME_BROWSER_CHROMEOS_REMOTE_APPS_REMOTE_APPS_TYPES_H_
+
+namespace chromeos {
+
+enum class RemoteAppsError {
+  kNone = 0,
+  kAppIdDoesNotExist,
+  kFolderIdDoesNotExist,
+  // Manager has not been initialized.
+  kNotReady,
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_REMOTE_APPS_REMOTE_APPS_TYPES_H_
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 9c7f63d6..8beb72d 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -3663,15 +3663,15 @@
   static constexpr const wchar_t* kCrazyFilenames[] = {
       L"a_file_name.zip",
       L"\u89c6\u9891\u76f4\u64ad\u56fe\u7247.zip",  // chinese chars
-      L"\u0412\u043e "
-      L"\u0424\u043b\u043e\u0440\u0438\u0434\u0435\u043e\u0431\u044a"
-      L"\u044f\u0432\u043b\u0435\u043d\u0440\u0435\u0436\u0438\u043c \u0427"
-      L"\u041f \u0438\u0437-\u0437\u0430 \u0443\u0442\u0435\u0447\u043a\u0438 "
-      L"\u043d\u0435\u0444\u0442\u0438.zip",  // russian
+      (L"\u0412\u043e "
+       L"\u0424\u043b\u043e\u0440\u0438\u0434\u0435\u043e\u0431\u044a"
+       L"\u044f\u0432\u043b\u0435\u043d\u0440\u0435\u0436\u0438\u043c \u0427"
+       L"\u041f \u0438\u0437-\u0437\u0430 \u0443\u0442\u0435\u0447\u043a\u0438 "
+       L"\u043d\u0435\u0444\u0442\u0438.zip"),  // russian
       L"Desocupa\xe7\xe3o est\xe1vel.zip",
       // arabic:
-      L"\u0638\u2026\u0638\u02c6\u0637\xa7\u0638\u201a\u0637\xb9 \u0638\u201e"
-      L"\u0638\u201e\u0637\xb2\u0638\u0679\u0637\xa7\u0637\xb1\u0637\xa9.zip",
+      (L"\u0638\u2026\u0638\u02c6\u0637\xa7\u0638\u201a\u0637\xb9 \u0638\u201e"
+       L"\u0638\u201e\u0637\xb2\u0638\u0679\u0637\xa7\u0637\xb1\u0637\xa9.zip"),
       L"\u05d4\u05e2\u05d3\u05e4\u05d5\u05ea.zip",  // hebrew
       L"\u092d\u093e\u0930\u0924.zip",              // hindi
       L"d\xe9stabilis\xe9.zip",                     // french
@@ -3679,7 +3679,8 @@
       L"\u97d3-\u4e2d \uc815\uc0c1, \ucc9c\uc548\ud568 \uc758\uacac.zip",
       L"jiho....tiho...miho.zip",
       L"jiho!@#$tiho$%^&-()_+=miho copy.zip",  // special chars
-      L"Wohoo-to hoo+I.zip", L"Picture 1.zip",
+      L"Wohoo-to hoo+I.zip",
+      L"Picture 1.zip",
       L"This is a very very long english sentence with spaces and , and +.zip",
   };
 
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 814316e..240e561 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -1028,6 +1028,7 @@
       "//chromeos/components/camera_app_ui:mojo_bindings",
       "//chromeos/components/camera_app_ui/resources:chrome_camera_app",
       "//chromeos/components/proximity_auth",
+      "//chromeos/components/remote_apps/mojom",
       "//chromeos/constants",
       "//chromeos/cryptohome",
       "//chromeos/dbus",
diff --git a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
index b872063..a434c9d 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
@@ -18,10 +18,14 @@
 #include "extensions/common/permissions/permissions_data.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/remote_apps/remote_apps_impl.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_manager.h"
+#include "chrome/browser/chromeos/remote_apps/remote_apps_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/speech/extension_api/tts_engine_extension_observer.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/components/camera_app_ui/camera_app_ui.h"
+#include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
 #include "chromeos/services/cfm/public/buildflags/buildflags.h"
 #include "chromeos/services/media_perception/public/mojom/media_perception.mojom.h"
 #include "chromeos/services/tts/public/mojom/tts_service.mojom.h"
@@ -80,7 +84,20 @@
       ->BindTtsStream(std::move(receiver));
 }
 
-#endif
+void BindRemoteAppsFactory(
+    content::RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<chromeos::remote_apps::mojom::RemoteAppsFactory>
+        pending_receiver) {
+  // |remote_apps_manager| will be null in non-managed guest sessions, but this
+  // is already checked in |RemoteAppsImpl::IsAllowed()|.
+  chromeos::RemoteAppsManager* remote_apps_manager =
+      chromeos::RemoteAppsManagerFactory::GetForProfile(
+          Profile::FromBrowserContext(render_frame_host->GetBrowserContext()));
+  DCHECK(remote_apps_manager);
+  remote_apps_manager->BindInterface(std::move(pending_receiver));
+}
+
+#endif  // defined(OS_CHROMEOS)
 }  // namespace
 
 void PopulateChromeFrameBindersForExtension(
@@ -155,7 +172,12 @@
     binder_map->Add<chromeos::tts::mojom::TtsStream>(
         base::BindRepeating(&BindTtsStream));
   }
-#endif
+
+  if (chromeos::RemoteAppsImpl::IsAllowed(render_frame_host, extension)) {
+    binder_map->Add<chromeos::remote_apps::mojom::RemoteAppsFactory>(
+        base::BindRepeating(&BindRemoteAppsFactory));
+  }
+#endif  // defined(OS_CHROMEOS)
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 8a6f818..888a999c 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2114,11 +2114,6 @@
     "expiry_milestone": 86
   },
   {
-    "name": "enable-sync-trusted-vault",
-    "owners": [ "mastiz@chromium.org", "//components/sync/OWNERS" ],
-    "expiry_milestone": 85
-  },
-  {
     "name": "enable-system-webapps",
     "owners": [ "calamity" ],
     "expiry_milestone": 78
@@ -3628,12 +3623,12 @@
   },
   {
     "name": "pluginvm-show-camera-permissions",
-    "owners": [ "danielng" ],
+    "owners": [ "danielng@google.com", "lxj@google.com" ],
     "expiry_milestone": 87
   },
   {
     "name": "pluginvm-show-microphone-permissions",
-    "owners": [ "dtor" ],
+    "owners": [ "dtor", "lxj@google.com" ],
     "expiry_milestone": 87
   },
   {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 2d52ccb..ebd0cdd7 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -971,11 +971,6 @@
     "Enable using server-provided resource loading hints to provide a preview "
     "over slow network connections.";
 
-const char kEnableSyncTrustedVaultName[] =
-    "Enable trusted vault sync passphrase type";
-const char kEnableSyncTrustedVaultDescription[] =
-    "Enables the new, experimental passphrase type for sync data";
-
 #if BUILDFLAG(ENABLE_TAB_SEARCH)
 const char kEnableTabSearchName[] = "Enable Tab Search";
 const char kEnableTabSearchDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d17ce02..986f950 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -564,9 +564,6 @@
 extern const char kEnableSubresourceRedirectName[];
 extern const char kEnableSubresourceRedirectDescription[];
 
-extern const char kEnableSyncTrustedVaultName[];
-extern const char kEnableSyncTrustedVaultDescription[];
-
 #if BUILDFLAG(ENABLE_TAB_SEARCH)
 extern const char kEnableTabSearchName[];
 extern const char kEnableTabSearchDescription[];
diff --git a/chrome/browser/media/webrtc/media_stream_infobar_browsertest.cc b/chrome/browser/media/webrtc/media_stream_permission_browsertest.cc
similarity index 78%
rename from chrome/browser/media/webrtc/media_stream_infobar_browsertest.cc
rename to chrome/browser/media/webrtc/media_stream_permission_browsertest.cc
index 49d5e62..d2f3282 100644
--- a/chrome/browser/media/webrtc/media_stream_infobar_browsertest.cc
+++ b/chrome/browser/media/webrtc/media_stream_permission_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/media/webrtc/webrtc_browsertest_base.h"
@@ -65,7 +66,9 @@
 
  private:
   content::WebContents* LoadTestPageInBrowser(Browser* browser) {
-    EXPECT_TRUE(embedded_test_server()->Start());
+    if (!embedded_test_server()->Started()) {
+      EXPECT_TRUE(embedded_test_server()->Start());
+    }
 
     // Uses the default server.
     GURL url = test_page_url();
@@ -76,12 +79,6 @@
     return browser->tab_strip_model()->GetActiveWebContents();
   }
 
-  // Dummy callback for when we deny the current request directly.
-  static void OnMediaStreamResponse(
-      const blink::MediaStreamDevices& devices,
-      blink::mojom::MediaStreamRequestResult result,
-      std::unique_ptr<content::MediaStreamUI> ui) {}
-
   DISALLOW_COPY_AND_ASSIGN(MediaStreamPermissionTest);
 };
 
@@ -169,3 +166,50 @@
   EXPECT_TRUE(GetUserMediaWithSpecificConstraintsAndAccept(
       tab_contents, kAudioOnlyCallConstraints));
 }
+
+IN_PROC_BROWSER_TEST_F(MediaStreamPermissionTest,
+                       DenyingPermissionStopsStreamWhenRelevant) {
+  struct {
+    std::string constraints;
+    ContentSettingsType setting_to_clear;
+    bool should_video_stop;
+  } kTests[] = {
+      {kAudioVideoCallConstraints, ContentSettingsType::MEDIASTREAM_CAMERA,
+       true},
+      {kAudioVideoCallConstraints, ContentSettingsType::MEDIASTREAM_MIC, true},
+      {kVideoOnlyCallConstraints, ContentSettingsType::MEDIASTREAM_CAMERA,
+       true},
+      {kVideoOnlyCallConstraints, ContentSettingsType::MEDIASTREAM_MIC, false},
+  };
+
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+
+  for (const auto& kTest : kTests) {
+    content::WebContents* tab_contents = LoadTestPageInTab();
+
+    EXPECT_TRUE(GetUserMediaWithSpecificConstraintsAndAcceptIfPrompted(
+        tab_contents, kTest.constraints));
+
+    StartDetectingVideo(tab_contents, "local-view");
+    EXPECT_TRUE(WaitForVideoToPlay(tab_contents));
+
+    settings_map->ClearSettingsForOneType(kTest.setting_to_clear);
+
+    // Let all the cross-thread tasks do their work.
+    base::RunLoop().RunUntilIdle();
+
+    StartDetectingVideo(tab_contents, "local-view");
+
+    if (kTest.should_video_stop) {
+      EXPECT_TRUE(WaitForVideoToStop(tab_contents));
+    } else {
+      EXPECT_TRUE(WaitForVideoToPlay(tab_contents));
+    }
+
+    // Clean up settings for the following tests.
+    settings_map->ClearSettingsForOneType(ContentSettingsType::MEDIASTREAM_MIC);
+    settings_map->ClearSettingsForOneType(
+        ContentSettingsType::MEDIASTREAM_CAMERA);
+  }
+}
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index 806b591..27819d1 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -473,6 +473,14 @@
   return is_video_playing;
 }
 
+bool WebRtcTestBase::WaitForVideoToStop(
+    content::WebContents* tab_contents) const {
+  bool is_video_stopped =
+      test::PollingWaitUntil("isVideoStopped()", "video-stopped", tab_contents);
+  EXPECT_TRUE(is_video_stopped);
+  return is_video_stopped;
+}
+
 std::string WebRtcTestBase::GetStreamSize(
     content::WebContents* tab_contents,
     const std::string& video_element) const {
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.h b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
index e85f002..3c98df5 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.h
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
@@ -182,7 +182,11 @@
   // make that work). Looks at a 320x240 area of the target video tag.
   void StartDetectingVideo(content::WebContents* tab_contents,
                            const std::string& video_element) const;
+
+  // Wait for a video to start/stop playing. StartDetectingVideo must have
+  // been called already.
   bool WaitForVideoToPlay(content::WebContents* tab_contents) const;
+  bool WaitForVideoToStop(content::WebContents* tab_contents) const;
 
   // Returns the stream size as a string on the format <width>x<height>.
   std::string GetStreamSize(content::WebContents* tab_contents,
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index b275fd38..d19d141 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1275,8 +1275,10 @@
 
 // If there is a username and password with prefilled values, overwrite the
 // password if the username looks like a placeholder value
+
+// TODO(crbug.com/1116886) Renable this test
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
-                       PlaceholderPasswordOverwritten) {
+                       DISABLED_PlaceholderPasswordOverwritten) {
   // Save a credential to the password store.
   scoped_refptr<password_manager::TestPasswordStore> password_store =
       static_cast<password_manager::TestPasswordStore*>(
diff --git a/chrome/browser/payments/BUILD.gn b/chrome/browser/payments/BUILD.gn
index 210ab7e1..d7c0ffb 100644
--- a/chrome/browser/payments/BUILD.gn
+++ b/chrome/browser/payments/BUILD.gn
@@ -7,6 +7,7 @@
 
   sources = [
     "abort_payment_handler_browsertest.cc",
+    "android_payment_app_factory_browsertest.cc",
     "colocated_payment_manifests_browsertest.cc",
     "empty_parameters_browsertest.cc",
     "has_enrolled_instrument_browsertest.cc",
diff --git a/chrome/browser/payments/android_payment_app_factory_browsertest.cc b/chrome/browser/payments/android_payment_app_factory_browsertest.cc
new file mode 100644
index 0000000..76af1b1
--- /dev/null
+++ b/chrome/browser/payments/android_payment_app_factory_browsertest.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/test/payments/payment_request_platform_browsertest_base.h"
+#include "components/payments/core/features.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+class AndroidPaymentAppFactoryTest
+    : public PaymentRequestPlatformBrowserTestBase {
+ public:
+  AndroidPaymentAppFactoryTest() {
+    feature_list_.InitAndEnableFeature(features::kAppStoreBilling);
+  }
+
+  ~AndroidPaymentAppFactoryTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(AndroidPaymentAppFactoryTest, SmokeTest) {
+  NavigateTo("a.com", "/app_store_billing_tests/index.html");
+  ASSERT_EQ("success", content::EvalJs(GetActiveWebContents(),
+                                       content::JsReplace(
+                                           "addSupportedMethod($1)",
+                                           "https://play.google.com/billing")));
+  ASSERT_EQ("success",
+            content::EvalJs(GetActiveWebContents(), "createPaymentRequest()"));
+  ASSERT_EQ("false",
+            content::EvalJs(GetActiveWebContents(), "canMakePayment()"));
+}
+
+}  // namespace
+}  // namespace payments
diff --git a/chrome/browser/plugins/flash_download_interception_unittest.cc b/chrome/browser/plugins/flash_download_interception_unittest.cc
index 809c7385..e9d75556 100644
--- a/chrome/browser/plugins/flash_download_interception_unittest.cc
+++ b/chrome/browser/plugins/flash_download_interception_unittest.cc
@@ -58,8 +58,8 @@
       "http://adobe.com/go/CA-H-GET-FLASH",
       "http://adobe.com/go/DE_CH-H-M-A2",
       "http://adobe.com/go/gntray_dl_getflashplayer_jp",
-      "http://www.adobe.com/shockwave/download/download.cgi?"
-      "P1_Prod_Version=ShockwaveFlash",
+      ("http://www.adobe.com/shockwave/download/download.cgi?"
+       "P1_Prod_Version=ShockwaveFlash"),
   };
 
   for (auto* url : flash_intercept_urls) {
@@ -81,8 +81,8 @@
       // Don't match text within the query or fragment.
       "http://www.adobe.com/go/non-matching?foo=flashplayer",
       "http://www.adobe.com/go/non-matching#!foo=flashplayer",
-      "http://www.adobe.com/shockwave/download/download.cgi?"
-      "P1_Prod_Version=SomethingElse",
+      ("http://www.adobe.com/shockwave/download/download.cgi?"
+       "P1_Prod_Version=SomethingElse"),
   };
 
   for (auto* url : flash_no_intercept_urls) {
diff --git a/chrome/browser/resources/chromeos/edu_login/browser_proxy.js b/chrome/browser/resources/chromeos/edu_login/browser_proxy.js
index 04becb0f..c908d389 100644
--- a/chrome/browser/resources/chromeos/edu_login/browser_proxy.js
+++ b/chrome/browser/resources/chromeos/edu_login/browser_proxy.js
@@ -61,6 +61,13 @@
    */
   completeLogin(credentials, eduLoginParams) {}
 
+  /**
+   * Send 'getAccounts' message to the handler. The promise will be resolved
+   * with the list of emails of accounts in session.
+   * @return {Promise<Array<string>>}
+   */
+  getAccounts() {}
+
   /** Send 'dialogClose' message to close the login dialog. */
   dialogClose() {}
 }
@@ -110,6 +117,11 @@
   }
 
   /** @override */
+  getAccounts() {
+    return sendWithPromise('getAccounts');
+  }
+
+  /** @override */
   dialogClose() {
     chrome.send('dialogClose');
   }
diff --git a/chrome/browser/resources/chromeos/edu_login/edu_login_signin.js b/chrome/browser/resources/chromeos/edu_login/edu_login_signin.js
index 7de6352..823f8a5 100644
--- a/chrome/browser/resources/chromeos/edu_login/edu_login_signin.js
+++ b/chrome/browser/resources/chromeos/edu_login/edu_login_signin.js
@@ -85,6 +85,8 @@
     this.authExtHost_.addEventListener(
         'authCompleted', e => this.onAuthCompleted_(
             /** @type {!CustomEvent<!AuthCompletedCredentials>} */(e)));
+    this.authExtHost_.addEventListener(
+        'getAccounts', () => this.onGetAccounts_());
   },
 
   /**
@@ -129,6 +131,13 @@
     this.loading_ = true;
   },
 
+  /** @private */
+  onGetAccounts_() {
+    this.browserProxy_.getAccounts().then(result => {
+      this.authExtHost_.getAccountsResponse(result);
+    });
+  },
+
   /**
    * Loads auth extension.
    * @param {!AuthParams} data Parameters for auth extension.
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 0f0f457..85fa491 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -207,6 +207,9 @@
     'backButton'(msg) {
       this.dispatchEvent(new CustomEvent('backButton', {detail: msg.show}));
     },
+    'getAccounts'(msg) {
+      this.dispatchEvent(new Event('getAccounts'));
+    },
     'showView'(msg) {
       this.dispatchEvent(new Event('showView'));
     },
@@ -595,6 +598,14 @@
       this.isLoaded_ = true;
     }
 
+    /**
+     * Called in response to 'getAccounts' event.
+     * @param {Array<string>} accounts list of emails
+     */
+    getAccountsResponse(accounts) {
+      this.sendMessageToWebview('accountsListed', accounts);
+    }
+
     constructInitialFrameUrl_(data) {
       if (data.doSamlRedirect) {
         let url = this.idpOrigin_ + SAML_REDIRECTION_PATH;
@@ -860,11 +871,22 @@
     }
 
     /**
-     * Invoked to send a HTML5 message to the webview element.
-     * @param {*} payload Payload of the HTML5 message.
+     * Invoked to send a HTML5 message with attached data to the webview
+     * element.
+     * @param {string} messageType Type of the HTML5 message.
+     * @param {Object=} messageData Data to be attached to the message.
      */
-    sendMessageToWebview(payload) {
+    sendMessageToWebview(messageType, messageData = null) {
       const currentUrl = this.webview_.src;
+      let payload = undefined;
+      if (messageData) {
+        payload = {type: messageType, data: messageData};
+      } else {
+        // TODO(crbug.com/1116343): Use new message format when it will be
+        // available in production.
+        payload = messageType;
+      }
+
       this.webview_.contentWindow.postMessage(payload, currentUrl);
     }
 
diff --git a/chrome/browser/resources/inline_login/inline_login_app.js b/chrome/browser/resources/inline_login/inline_login_app.js
index 985b8b0..7b9d167 100644
--- a/chrome/browser/resources/inline_login/inline_login_app.js
+++ b/chrome/browser/resources/inline_login/inline_login_app.js
@@ -105,6 +105,8 @@
             /** @type {!CustomEvent<!AuthCompletedCredentials>} */ (e)));
     this.authExtHost_.addEventListener(
         'showIncognito', () => this.onShowIncognito_());
+    this.authExtHost_.addEventListener(
+        'getAccounts', () => this.onGetAccounts_());
   },
 
   /**
@@ -156,6 +158,13 @@
     this.browserProxy_.showIncognito();
   },
 
+  /** @private */
+  onGetAccounts_() {
+    this.browserProxy_.getAccounts().then(result => {
+      this.authExtHost_.getAccountsResponse(result);
+    });
+  },
+
   /**
    * Loads auth extension.
    * @param {!AuthParams} data Parameters for auth extension.
diff --git a/chrome/browser/resources/inline_login/inline_login_browser_proxy.js b/chrome/browser/resources/inline_login/inline_login_browser_proxy.js
index 144423f..91bb37dd 100644
--- a/chrome/browser/resources/inline_login/inline_login_browser_proxy.js
+++ b/chrome/browser/resources/inline_login/inline_login_browser_proxy.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
 
 import {AuthCompletedCredentials} from '../gaia_auth_host/authenticator.m.js';
 
@@ -46,6 +46,13 @@
   /** Send 'showIncognito' message to the handler */
   showIncognito() {}
 
+  /**
+   * Send 'getAccounts' message to the handler. The promise will be resolved
+   * with the list of emails of accounts in session.
+   * @return {Promise<Array<string>>}
+   */
+  getAccounts() {}
+
   /** Send 'dialogClose' message to close the login dialog. */
   dialogClose() {}
 }
@@ -88,6 +95,11 @@
   }
 
   /** @override */
+  getAccounts() {
+    return sendWithPromise('getAccounts');
+  }
+
+  /** @override */
   dialogClose() {
     chrome.send('dialogClose');
   }
diff --git a/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.html b/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.html
index 4995387..b26470c 100644
--- a/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.html
@@ -4,6 +4,7 @@
       --computer-icon-padding-bottom: 10px;
       --computer-icon-padding-sides: 8px;
       --hairline-border: 1px;
+      --hairline-color : var(--google-grey-200);
       --outer-icon-size: 48px;
    }
 
@@ -18,7 +19,7 @@
   }
 
   settings-avatar-icon {
-    border: var(--hairline-border) solid var(--google-grey-refresh-100);
+    border: var(--hairline-border) solid var(--hairline-color);
     border-radius: 50%;
     display: flex;
     flex-shrink: 0;
@@ -32,7 +33,7 @@
         - var(--computer-icon-padding-bottom));
     --iron-icon-width: calc(var(--outer-icon-size) - 2 * var(--hairline-border)
         - 2 * var(--computer-icon-padding-sides));
-    border: var(--hairline-border) solid var(--google-grey-refresh-100);
+    border: var(--hairline-border) solid var(--hairline-color);
     border-radius: 50%;
     flex-shrink: 0;
     padding-bottom: var(--computer-icon-padding-bottom);
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.html b/chrome/browser/resources/settings/autofill_page/passwords_section.html
index 61658d2..75ac76d 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.html
@@ -52,22 +52,27 @@
         width: 40px;
       }
 
+      #accountStorageOptInButtonsContainer {
+        padding-bottom: 16px;
+      }
+
       #devicePasswordsLink {
         cursor: pointer;
+        padding-top: 16px;
       }
 
       #devicePasswordsLinkIcon {
-        border-color: gray;
+        border-color: var(--google-grey-200);
         border-radius: 20px;
         border-style: solid;
         border-width: 1px;
-        height: 19px;
+        height: 17px;
         margin-inline-end: 16px;
         padding-bottom: 10px;
         padding-inline-end: 8px;
         padding-inline-start: 8px;
         padding-top: 11px;
-        width: 24px;
+        width: 22px;
       }
    </style>
     <settings-toggle-button id="passwordToggle"
@@ -166,7 +171,8 @@
       <div slot="body" class="list-frame">
         <div hidden$="[[!eligibleForAccountStorage_]]"
             id="accountStorageButtonsContainer">
-          <div class="cr-row first two-line list-item">
+          <div class="cr-row first two-line list-item"
+              id="accountStorageOptInButtonsContainer">
             <settings-avatar-icon id="profileIcon"></settings-avatar-icon>
             <div class="flex cr-padded-text">
               <div id="accountStorageOptInBody"
@@ -188,7 +194,7 @@
               $i18n{optOutAccountStorageLabel}
             </cr-button>
           </div>
-          <div id="devicePasswordsLink" class="cr-row first two-line list-item"
+          <div id="devicePasswordsLink" class="cr-row two-line list-item"
               hidden$="[[!shouldShowDevicePasswordsLink_]]"
               on-click="onDevicePasswordsLinkClicked_">
             <iron-icon id="devicePasswordsLinkIcon" icon="cr:computer">
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
index 7dd7dda..d182b48 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
@@ -1,7 +1,9 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="input_method_util.html">
 <link rel="import" href="languages_metrics_proxy.html">
 <link rel="import" href="../os_route.html">
@@ -18,6 +20,10 @@
         padding-inline-start: var(--cr-section-padding);
       }
 
+      .bottom-margin {
+        margin-bottom: var(--cr-section-vertical-margin);
+      }
+
       .icon-external {
         margin-inline-end: 0;
       }
@@ -39,6 +45,12 @@
       .external-wrapper {
         display: flex;
       }
+
+      #addInputMethod {
+        --iron-icon-fill-color: var(--cr-link-color);
+        margin-inline-end: 4px;
+        margin-top: 16px;
+      }
     </style>
 
     <div route-path="default">
@@ -49,7 +61,7 @@
           on-settings-boolean-control-change="onShowImeMenuChange_">
       </settings-toggle-button>
 
-      <div class="hr">
+      <div class="hr bottom-margin">
         <h2>$i18n{inputMethodListTitle}</h2>
         <div class="list-frame vertical-list" id="inputMethodsList">
           <template is="dom-repeat"
@@ -88,8 +100,21 @@
               </template>
             </div>
           </template>
+          <div class="list-item">
+            <cr-button id="addInputMethod" on-click="onAddInputMethodClick_">
+              <iron-icon icon="cr:add"></iron-icon>
+              $i18n{addInputMethodLabel}
+            </cr-button>
+          </div>
         </div>
       </div>
+      <settings-toggle-button id="enableSpellcheckingToggle" class="hr"
+          label="$i18n{spellCheckTitle}"
+          sub-label="[[getSpellCheckSubLabel_(spellCheckLanguages_)]]"
+          pref="{{prefs.browser.enable_spellchecking}}"
+          disabled="[[!spellCheckLanguages_.length]]"
+          on-settings-boolean-control-change="onSpellcheckToggleChange_">
+      </settings-toggle-button>
     </div>
   </template>
   <script src="input_page.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
index 9c58af17..bd3a273 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
@@ -34,6 +34,16 @@
 
     /** @type {!LanguageHelper} */
     languageHelper: Object,
+
+    /**
+     * @private {!Array<!LanguageState|!ForcedLanguageState>}
+     */
+    spellCheckLanguages_: {
+      type: Array,
+      value() {
+        return [];
+      },
+    },
   },
 
   /** @private {?settings.LanguagesMetricsProxy} */
@@ -159,4 +169,28 @@
   getOpenOptionsPageLabel_(inputMethodName) {
     return this.i18n('openOptionsPage', inputMethodName);
   },
+
+  /** @private */
+  onAddInputMethodClick_() {
+    this.languagesMetricsProxy_.recordAddInputMethod();
+    // TODO(crbug/1113439): Add input methods dialog.
+  },
+
+  /**
+   * @return {string|undefined}
+   * @private
+   */
+  getSpellCheckSubLabel_() {
+    return this.spellCheckLanguages_.length ?
+        undefined :  // equivalent to not setting the sublabel in the HTML.
+        this.i18n('spellCheckDisabledReason');
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onSpellcheckToggleChange_(e) {
+    this.languagesMetricsProxy_.recordToggleSpellCheck(e.target.checked);
+  },
 });
diff --git a/chrome/browser/ui/app_list/search/common/file_icon_util.cc b/chrome/browser/ui/app_list/search/common/file_icon_util.cc
index e55f001..cb9dc2c4 100644
--- a/chrome/browser/ui/app_list/search/common/file_icon_util.cc
+++ b/chrome/browser/ui/app_list/search/common/file_icon_util.cc
@@ -7,18 +7,35 @@
 #include <string>
 #include <utility>
 
+#include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
 #include "base/files/file_path.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
 #include "ui/file_manager/file_manager_resource_util.h"
 #include "ui/file_manager/grit/file_manager_resources.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/paint_vector_icon.h"
 
-#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader.h"
+namespace {
+
+// Hex color: #796EEE
+constexpr SkColor kFiletypeGsiteColor = SkColorSetRGB(121, 110, 238);
+
+// Hex color: #FF7537
+constexpr SkColor kFiletypePptColor = SkColorSetRGB(255, 117, 55);
+
+// Hex color: #796EEE
+constexpr SkColor kFiletypeSitesColor = SkColorSetRGB(121, 110, 238);
+
+constexpr int kIconDipSize = 20;
+
+}  // namespace
 
 namespace app_list {
 namespace internal {
@@ -129,47 +146,124 @@
   }
 }
 
-int GetResourceIdForIconType(IconType icon) {
+IconType GetIconTypeFromString(const std::string& icon_type_string) {
+  static const base::NoDestructor<std::map<std::string, IconType>>
+      type_string_to_icon_type({{"archive", IconType::ARCHIVE},
+                                {"audio", IconType::AUDIO},
+                                {"chart", IconType::CHART},
+                                {"excel", IconType::EXCEL},
+                                {"drive", IconType::DRIVE},
+                                {"folder", IconType::FOLDER},
+                                {"gdoc", IconType::GDOC},
+                                {"gdraw", IconType::GDRAW},
+                                {"generic", IconType::GENERIC},
+                                {"gform", IconType::GFORM},
+                                {"gmap", IconType::GMAP},
+                                {"gsheet", IconType::GSHEET},
+                                {"gsite", IconType::GSITE},
+                                {"gslides", IconType::GSLIDE},
+                                {"gtable", IconType::GTABLE},
+                                {"image", IconType::IMAGE},
+                                {"linux", IconType::LINUX},
+                                {"pdf", IconType::PDF},
+                                {"ppt", IconType::PPT},
+                                {"script", IconType::SCRIPT},
+                                {"shared", IconType::FOLDER_SHARED},
+                                {"sites", IconType::SITES},
+                                {"tini", IconType::TINI},
+                                {"video", IconType::VIDEO},
+                                {"word", IconType::WORD}});
+
+  const auto& icon_it = type_string_to_icon_type->find(icon_type_string);
+  if (icon_it != type_string_to_icon_type->end())
+    return icon_it->second;
+  return IconType::GENERIC;
+}
+
+gfx::ImageSkia GetVectorIconFromIconType(IconType icon) {
   // Changes to this map should be reflected in
   // ui/file_manager/file_manager/common/js/file_type.js.
-  static const base::NoDestructor<base::flat_map<IconType, int>>
-      icon_to_2x_resource_id({
-          {IconType::ARCHIVE,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_ARCHIVE},
-          {IconType::AUDIO, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_AUDIO},
-          {IconType::CHART, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_CHART},
-          // TODO(crbug.com/1088395):  we're missing a generic square drive
-          // file icon.
-          {IconType::DRIVE, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GENERIC},
-          {IconType::EXCEL, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_EXCEL},
-          {IconType::FOLDER, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_FOLDER},
-          // TODO(crbug.com/1088395): we're missing a square shared folder icon.
-          {IconType::FOLDER_SHARED,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_FOLDER},
-          {IconType::GDOC, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GDOC},
-          {IconType::GDRAW, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GDRAW},
-          {IconType::GENERIC,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GENERIC},
-          {IconType::GFORM, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GFORM},
-          {IconType::GMAP, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GMAP},
-          {IconType::GSHEET, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSHEET},
-          {IconType::GSITE, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSITE},
-          {IconType::GSLIDE, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSLIDES},
-          {IconType::GTABLE, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GTABLE},
-          {IconType::IMAGE, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_IMAGE},
-          {IconType::LINUX, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GENERIC},
-          {IconType::PDF, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PDF},
-          {IconType::PPT, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PPT},
-          {IconType::SCRIPT, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_SCRIPT},
-          {IconType::SITES, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_SITES},
-          {IconType::TINI, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_TINI},
-          {IconType::VIDEO, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_VIDEO},
-          {IconType::WORD, IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_WORD},
-      });
+  static const base::NoDestructor<std::map<IconType, gfx::IconDescription>>
+      icon_type_to_icon_description(
+          {{IconType::ARCHIVE,
+            gfx::IconDescription(ash::kFiletypeArchiveIcon, kIconDipSize,
+                                 gfx::kGoogleGrey700)},
+           {IconType::AUDIO,
+            gfx::IconDescription(ash::kFiletypeAudioIcon, kIconDipSize,
+                                 gfx::kGoogleRed500)},
+           {IconType::CHART,
+            gfx::IconDescription(ash::kFiletypeChartIcon, kIconDipSize,
+                                 gfx::kGoogleGreen500)},
+           {IconType::DRIVE,
+            gfx::IconDescription(ash::kFiletypeTeamDriveIcon, kIconDipSize,
+                                 gfx::kGoogleGrey700)},
+           {IconType::EXCEL,
+            gfx::IconDescription(ash::kFiletypeExcelIcon, kIconDipSize,
+                                 gfx::kGoogleGreen500)},
+           {IconType::FOLDER,
+            gfx::IconDescription(ash::kFiletypeFolderIcon, kIconDipSize,
+                                 gfx::kGoogleGrey700)},
+           {IconType::FOLDER_SHARED,
+            gfx::IconDescription(ash::kFiletypeSharedIcon, kIconDipSize,
+                                 gfx::kGoogleGrey700)},
+           {IconType::GDOC,
+            gfx::IconDescription(ash::kFiletypeGdocIcon, kIconDipSize,
+                                 gfx::kGoogleBlue500)},
+           {IconType::GDRAW,
+            gfx::IconDescription(ash::kFiletypeGdrawIcon, kIconDipSize,
+                                 gfx::kGoogleRed500)},
+           {IconType::GENERIC,
+            gfx::IconDescription(ash::kFiletypeGenericIcon, kIconDipSize,
+                                 gfx::kGoogleGrey700)},
+           {IconType::GFORM,
+            gfx::IconDescription(ash::kFiletypeGformIcon, kIconDipSize,
+                                 gfx::kGoogleGreen500)},
+           {IconType::GMAP,
+            gfx::IconDescription(ash::kFiletypeGmapIcon, kIconDipSize,
+                                 gfx::kGoogleRed500)},
+           {IconType::GSHEET,
+            gfx::IconDescription(ash::kFiletypeGsheetIcon, kIconDipSize,
+                                 gfx::kGoogleGreen500)},
+           {IconType::GSITE,
+            gfx::IconDescription(ash::kFiletypeGsiteIcon, kIconDipSize,
+                                 kFiletypeGsiteColor)},
+           {IconType::GSLIDE,
+            gfx::IconDescription(ash::kFiletypeGslidesIcon, kIconDipSize,
+                                 gfx::kGoogleYellow500)},
+           {IconType::GTABLE,
+            gfx::IconDescription(ash::kFiletypeGtableIcon, kIconDipSize,
+                                 gfx::kGoogleGreen500)},
+           {IconType::IMAGE,
+            gfx::IconDescription(ash::kFiletypeImageIcon, kIconDipSize,
+                                 gfx::kGoogleRed500)},
+           {IconType::LINUX,
+            gfx::IconDescription(ash::kFiletypeLinuxIcon, kIconDipSize,
+                                 gfx::kGoogleGrey700)},
+           {IconType::PDF,
+            gfx::IconDescription(ash::kFiletypePdfIcon, kIconDipSize,
+                                 gfx::kGoogleRed500)},
+           {IconType::PPT,
+            gfx::IconDescription(ash::kFiletypePptIcon, kIconDipSize,
+                                 kFiletypePptColor)},
+           {IconType::SCRIPT,
+            gfx::IconDescription(ash::kFiletypeScriptIcon, kIconDipSize,
+                                 gfx::kGoogleBlue500)},
+           {IconType::SITES,
+            gfx::IconDescription(ash::kFiletypeSitesIcon, kIconDipSize,
+                                 kFiletypeSitesColor)},
+           {IconType::TINI,
+            gfx::IconDescription(ash::kFiletypeTiniIcon, kIconDipSize,
+                                 gfx::kGoogleBlue500)},
+           {IconType::VIDEO,
+            gfx::IconDescription(ash::kFiletypeVideoIcon, kIconDipSize,
+                                 gfx::kGoogleRed500)},
+           {IconType::WORD,
+            gfx::IconDescription(ash::kFiletypeWordIcon, kIconDipSize,
+                                 gfx::kGoogleBlue500)}});
 
-  const auto& id_it = icon_to_2x_resource_id->find(icon);
-  DCHECK(id_it != icon_to_2x_resource_id->end());
-  return id_it->second;
+  const auto& id_it = icon_type_to_icon_description->find(icon);
+  DCHECK(id_it != icon_type_to_icon_description->end());
+  return gfx::CreateVectorIcon(id_it->second);
 }
 
 int GetChipResourceIdForIconType(IconType icon) {
@@ -210,9 +304,8 @@
 }  // namespace internal
 
 gfx::ImageSkia GetIconForPath(const base::FilePath& filepath) {
-  return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-      internal::GetResourceIdForIconType(
-          internal::GetIconTypeForPath(filepath)));
+  return internal::GetVectorIconFromIconType(
+      internal::GetIconTypeForPath(filepath));
 }
 
 gfx::ImageSkia GetChipIconForPath(const base::FilePath& filepath) {
@@ -221,4 +314,8 @@
           internal::GetIconTypeForPath(filepath)));
 }
 
+gfx::ImageSkia GetIconFromType(const std::string& icon_type) {
+  return GetVectorIconFromIconType(internal::GetIconTypeFromString(icon_type));
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/common/file_icon_util.h b/chrome/browser/ui/app_list/search/common/file_icon_util.h
index 8c4b4fe6..cb846343 100644
--- a/chrome/browser/ui/app_list/search/common/file_icon_util.h
+++ b/chrome/browser/ui/app_list/search/common/file_icon_util.h
@@ -40,13 +40,15 @@
   WORD,
 };
 
+IconType GetIconTypeFromString(const std::string& icon_type_string);
 IconType GetIconTypeForPath(const base::FilePath& filepath);
-int GetResourceIdForIconType(IconType icon);
+gfx::ImageSkia GetVectorIconFromIconType(IconType icon);
 int GetChipResourceIdForIconType(IconType icon);
 }  // namespace internal
 
 gfx::ImageSkia GetIconForPath(const base::FilePath& filepath);
 gfx::ImageSkia GetChipIconForPath(const base::FilePath& filepath);
+gfx::ImageSkia GetIconFromType(const std::string& icon_type);
 
 }  // namespace app_list
 
diff --git a/chrome/browser/ui/app_list/search/common/file_icon_util_unittest.cc b/chrome/browser/ui/app_list/search/common/file_icon_util_unittest.cc
index 93685f2..6aad620 100644
--- a/chrome/browser/ui/app_list/search/common/file_icon_util_unittest.cc
+++ b/chrome/browser/ui/app_list/search/common/file_icon_util_unittest.cc
@@ -36,26 +36,6 @@
   }
 }
 
-TEST(AppListFileIconUtilTest, GetResourceIdForIconType) {
-  const std::vector<std::pair<internal::IconType, int>>
-      icon_type_to_resource_id = {
-          {internal::IconType::PDF,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PDF},
-          {internal::IconType::PDF,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PDF},
-          {internal::IconType::ARCHIVE,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_ARCHIVE},
-          {internal::IconType::GSLIDE,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSLIDES},
-          {internal::IconType::GENERIC,
-           IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GENERIC}};
-
-  for (const auto& pair : icon_type_to_resource_id) {
-    EXPECT_EQ(::app_list::internal::GetResourceIdForIconType(pair.first),
-              pair.second);
-  }
-}
-
 TEST(AppListFileIconUtilTest, GetChipResourceIdForIconType) {
   const std::vector<std::pair<internal::IconType, int>>
       icon_type_to_resource_id = {
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc
index 95a42f6..d62854e 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc
@@ -11,7 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.h"
-#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_impl.h"
+#include "chrome/browser/ui/app_list/search/common/file_icon_util.h"
 
 using chromeos::launcher_search_provider::Service;
 
@@ -25,13 +25,14 @@
 
 LauncherSearchResult::LauncherSearchResult(
     const std::string& item_id,
-    const GURL& icon_url,
+    const std::string& icon_type,
     const int discrete_value_relevance,
     Profile* profile,
     const extensions::Extension* extension,
     std::unique_ptr<chromeos::launcher_search_provider::ErrorReporter>
         error_reporter)
     : item_id_(item_id),
+      icon_type_(icon_type),
       discrete_value_relevance_(discrete_value_relevance),
       profile_(profile),
       extension_(extension) {
@@ -39,23 +40,12 @@
   DCHECK_LE(discrete_value_relevance,
             chromeos::launcher_search_provider::kMaxSearchResultScore);
 
-  icon_image_loader_ = base::MakeRefCounted<LauncherSearchIconImageLoaderImpl>(
-      icon_url, profile, extension,
-      ash::AppListConfig::instance().GetPreferredIconDimension(display_type()),
-      std::move(error_reporter));
-  icon_image_loader_->LoadResources();
-
   Initialize();
 }
 
-LauncherSearchResult::~LauncherSearchResult() {
-  icon_image_loader_->RemoveObserver(this);
-}
-
 std::unique_ptr<LauncherSearchResult> LauncherSearchResult::Duplicate() const {
-  LauncherSearchResult* duplicated_result =
-      new LauncherSearchResult(item_id_, discrete_value_relevance_, profile_,
-                               extension_, icon_image_loader_);
+  LauncherSearchResult* duplicated_result = new LauncherSearchResult(
+      item_id_, icon_type_, discrete_value_relevance_, profile_, extension_);
   duplicated_result->set_model_updater(model_updater());
   duplicated_result->SetMetadata(CloneMetadata());
   return base::WrapUnique(duplicated_result);
@@ -70,30 +60,17 @@
   return ash::LAUNCHER_SEARCH_PROVIDER_RESULT;
 }
 
-void LauncherSearchResult::OnIconImageChanged(
-    LauncherSearchIconImageLoader* image_loader) {
-  DCHECK_EQ(image_loader, icon_image_loader_.get());
-  SetIcon(icon_image_loader_->GetIconImage());
-}
-
-void LauncherSearchResult::OnBadgeIconImageChanged(
-    LauncherSearchIconImageLoader* image_loader) {
-  DCHECK_EQ(image_loader, icon_image_loader_.get());
-  // No badging is required.
-}
-
 LauncherSearchResult::LauncherSearchResult(
     const std::string& item_id,
+    const std::string& icon_type,
     const int discrete_value_relevance,
     Profile* profile,
-    const extensions::Extension* extension,
-    const scoped_refptr<LauncherSearchIconImageLoader>& icon_image_loader)
+    const extensions::Extension* extension)
     : item_id_(item_id),
+      icon_type_(icon_type),
       discrete_value_relevance_(discrete_value_relevance),
       profile_(profile),
-      extension_(extension),
-      icon_image_loader_(icon_image_loader) {
-  DCHECK(icon_image_loader_);
+      extension_(extension) {
   Initialize();
 }
 
@@ -105,9 +82,7 @@
   SetDetails(base::UTF8ToUTF16(extension_->name()));
   SetResultType(ResultType::kLauncher);
 
-  icon_image_loader_->AddObserver(this);
-
-  SetIcon(icon_image_loader_->GetIconImage());
+  SetIcon(GetIconFromType(icon_type_));
 }
 
 std::string LauncherSearchResult::GetSearchResultId() {
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.h b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.h
index 792bb9c5..77397e9 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.h
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.h
@@ -11,44 +11,36 @@
 #include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "chrome/browser/chromeos/launcher_search_provider/error_reporter.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
-#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader.h"
 #include "extensions/common/extension.h"
-#include "url/gurl.h"
 
 namespace app_list {
 
-class LauncherSearchResult : public ChromeSearchResult,
-                             public LauncherSearchIconImageLoader::Observer {
+class LauncherSearchResult : public ChromeSearchResult {
  public:
   LauncherSearchResult(
       const std::string& item_id,
-      const GURL& icon_url,
+      const std::string& icon_type,
       const int discrete_value_relevance,
       Profile* profile,
       const extensions::Extension* extension,
       std::unique_ptr<chromeos::launcher_search_provider::ErrorReporter>
           error_reporter);
-  ~LauncherSearchResult() override;
   std::unique_ptr<LauncherSearchResult> Duplicate() const;
 
   // ChromeSearchResult overrides:
   void Open(int event_flags) override;
   ash::SearchResultType GetSearchResultType() const override;
 
-  void OnIconImageChanged(LauncherSearchIconImageLoader* image_loader) override;
-  void OnBadgeIconImageChanged(
-      LauncherSearchIconImageLoader* image_loader) override;
-
  private:
   // Constructor for duplicating a result.
-  LauncherSearchResult(
-      const std::string& item_id,
-      const int discrete_value_relevance,
-      Profile* profile,
-      const extensions::Extension* extension,
-      const scoped_refptr<LauncherSearchIconImageLoader>& icon_image_loader);
+  LauncherSearchResult(const std::string& item_id,
+                       const std::string& icon_type,
+                       const int discrete_value_relevance,
+                       Profile* profile,
+                       const extensions::Extension* extension);
   void Initialize();
 
   // Returns search result ID. The search result ID is comprised of the
@@ -57,11 +49,11 @@
   std::string GetSearchResultId();
 
   const std::string item_id_;
+  const std::string icon_type_;
   // Must be between 0 and kMaxSearchResultScore.
   const int discrete_value_relevance_;
   Profile* profile_;
   const extensions::Extension* extension_;
-  scoped_refptr<LauncherSearchIconImageLoader> icon_image_loader_;
 
   DISALLOW_COPY_AND_ASSIGN(LauncherSearchResult);
 };
diff --git a/chrome/browser/ui/app_list/search/mixer.cc b/chrome/browser/ui/app_list/search/mixer.cc
index eb2c390..8ff427b 100644
--- a/chrome/browser/ui/app_list/search/mixer.cc
+++ b/chrome/browser/ui/app_list/search/mixer.cc
@@ -45,8 +45,8 @@
 // Used to group relevant providers together for mixing their results.
 class Mixer::Group {
  public:
-  Group(size_t max_results, double multiplier, double boost)
-      : max_results_(max_results), multiplier_(multiplier), boost_(boost) {}
+  Group(size_t max_results, double boost)
+      : max_results_(max_results), boost_(boost) {}
   ~Group() {}
 
   void AddProvider(SearchProvider* provider) {
@@ -64,8 +64,7 @@
         // [0.0, 1.0]. Clamp to that range.
         const double relevance =
             base::ClampToRange(result->relevance(), 0.0, 1.0);
-        double boost = boost_;
-        results_.emplace_back(result.get(), relevance * multiplier_ + boost);
+        results_.emplace_back(result.get(), relevance + boost_);
       }
     }
 
@@ -81,7 +80,6 @@
  private:
   typedef std::vector<SearchProvider*> Providers;
   const size_t max_results_;
-  const double multiplier_;
   const double boost_;
 
   Providers providers_;  // Not owned.
@@ -104,8 +102,8 @@
   }
 }
 
-size_t Mixer::AddGroup(size_t max_results, double multiplier, double boost) {
-  groups_.push_back(std::make_unique<Group>(max_results, multiplier, boost));
+size_t Mixer::AddGroup(size_t max_results, double boost) {
+  groups_.push_back(std::make_unique<Group>(max_results, boost));
   return groups_.size() - 1;
 }
 
diff --git a/chrome/browser/ui/app_list/search/mixer.h b/chrome/browser/ui/app_list/search/mixer.h
index 25d91b5..296cee7f 100644
--- a/chrome/browser/ui/app_list/search/mixer.h
+++ b/chrome/browser/ui/app_list/search/mixer.h
@@ -34,8 +34,7 @@
 
 // Mixer collects results from providers, sorts them and publishes them to the
 // SearchResults UI model. The targeted results have 6 slots to hold the
-// result. The search controller can specify any number of groups, each with a
-// different number of results and priority boost.
+// result.
 class Mixer {
  public:
   explicit Mixer(AppListModelUpdater* model_updater);
@@ -45,9 +44,8 @@
   // chosen from this group (if 0, will allow unlimited results from this
   // group). If there aren't enough results from all groups, more than
   // |max_results| may be chosen from this group. Each result in the group will
-  // have its score multiplied by |multiplier| and added by |boost|. Returns the
-  // group's group_id.
-  size_t AddGroup(size_t max_results, double multiplier, double boost);
+  // have its score increased by |boost|. Returns the group's group_id.
+  size_t AddGroup(size_t max_results, double boost);
 
   // Associates a provider with a mixer group.
   void AddProviderToGroup(size_t group_id, SearchProvider* provider);
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index 4cc10da..eafe9bf 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -133,10 +133,8 @@
   result->InvokeAction(action_index, event_flags);
 }
 
-size_t SearchController::AddGroup(size_t max_results,
-                                  double multiplier,
-                                  double boost) {
-  return mixer_->AddGroup(max_results, multiplier, boost);
+size_t SearchController::AddGroup(size_t max_results, double boost) {
+  return mixer_->AddGroup(max_results, boost);
 }
 
 void SearchController::AddProvider(size_t group_id,
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h
index 97bea42..cc7770e 100644
--- a/chrome/browser/ui/app_list/search/search_controller.h
+++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -59,7 +59,7 @@
                           int event_flags);
 
   // Adds a new mixer group. See Mixer::AddGroup.
-  size_t AddGroup(size_t max_results, double multiplier, double boost);
+  size_t AddGroup(size_t max_results, double boost = 0.0f);
 
   // Takes ownership of |provider| and associates it with given mixer group.
   void AddProvider(size_t group_id, std::unique_ptr<SearchProvider> provider);
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 2b4ca05..a0ea622c 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -80,9 +80,7 @@
 // TODO(wutao): Need UX spec.
 constexpr size_t kMaxSettingsShortcutResults = 6;
 
-constexpr float kBoostOfSettingsShortcut = 10.0f;
-// Keep in sync with value in search_result_ranker.cc.
-constexpr float kBoostOfApps = 8.0f;
+constexpr double kAppBoost = 8.0;
 
 }  // namespace
 
@@ -103,33 +101,34 @@
   // a query turns up very few results, the mixer may take more than this
   // maximum from a particular group.
 
-  // For fullscreen app list, Settings shortcuts will show on the very top and
-  // apps and answer card in the middle and other search results in the bottom.
-  // So set boost 10.0, 8.0, 5.0, 0.0 respectively.
-  size_t answer_card_group_id = controller->AddGroup(1, 1.0, 5.0);
-  size_t apps_group_id =
-      controller->AddGroup(kMaxAppsGroupResults, 1.0, kBoostOfApps);
+  // For the fullscreen app list, apps appear above the answer card, which
+  // appears above other results. Set boosts to |kAppBoost| for apps of all
+  // kinds, 5.0 for answer card, and otherwise 0.0.
+  size_t apps_group_id = controller->AddGroup(kMaxAppsGroupResults, kAppBoost);
+  size_t answer_card_group_id = controller->AddGroup(1, 5.0);
+
   size_t omnibox_group_id = controller->AddGroup(
-      ash::AppListConfig::instance().max_search_result_list_items(), 1.0, 0.0);
+      ash::AppListConfig::instance().max_search_result_list_items());
 
   // Add search providers.
   controller->AddProvider(
       apps_group_id, std::make_unique<AppSearchProvider>(
                          profile, list_controller,
                          base::DefaultClock::GetInstance(), model_updater));
-  controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>(
-                                                profile, list_controller));
   if (app_list_features::IsAnswerCardEnabled()) {
     controller->AddProvider(answer_card_group_id,
                             std::make_unique<AnswerCardSearchProvider>(
                                 profile, model_updater, list_controller));
   }
 
+  controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>(
+                                                profile, list_controller));
+
   // The Assistant search provider currently only contributes search results
   // when launcher chip integration is enabled.
   if (chromeos::assistant::features::IsLauncherChipIntegrationEnabled()) {
-    size_t assistant_group_id = controller->AddGroup(
-        kMaxAssistantResults, /*multiplier=*/1.0, kBoostOfApps);
+    size_t assistant_group_id =
+        controller->AddGroup(kMaxAssistantResults, kAppBoost);
     controller->AddProvider(assistant_group_id,
                             std::make_unique<AssistantSearchProvider>());
   }
@@ -138,7 +137,7 @@
   // session and running on Chrome OS.
   if (!profile->IsGuestSession()) {
     size_t search_api_group_id =
-        controller->AddGroup(kMaxLauncherSearchResults, 1.0, 0.0);
+        controller->AddGroup(kMaxLauncherSearchResults);
     controller->AddProvider(search_api_group_id,
                             std::make_unique<LauncherSearchProvider>(profile));
   }
@@ -147,7 +146,7 @@
   if (app_list_features::IsAppReinstallZeroStateEnabled() &&
       arc::IsArcAllowedForProfile(profile)) {
     size_t recommended_app_group_id =
-        controller->AddGroup(kMaxAppReinstallSearchResults, 1.0, kBoostOfApps);
+        controller->AddGroup(kMaxAppReinstallSearchResults, kAppBoost);
     controller->AddProvider(recommended_app_group_id,
                             std::make_unique<ArcAppReinstallSearchProvider>(
                                 profile, kMaxAppReinstallSearchResults));
@@ -157,7 +156,7 @@
     // Set same boost as apps group since Play store results are placed
     // with apps.
     size_t playstore_api_group_id =
-        controller->AddGroup(kMaxPlayStoreResults, 1.0, kBoostOfApps);
+        controller->AddGroup(kMaxPlayStoreResults, kAppBoost);
     controller->AddProvider(
         playstore_api_group_id,
         std::make_unique<ArcPlayStoreSearchProvider>(kMaxPlayStoreResults,
@@ -166,15 +165,17 @@
 
   if (app_list_features::IsAppDataSearchEnabled()) {
     size_t app_data_api_group_id =
-        controller->AddGroup(kMaxAppDataResults, 1.0, kBoostOfApps);
+        controller->AddGroup(kMaxAppDataResults, kAppBoost);
     controller->AddProvider(app_data_api_group_id,
                             std::make_unique<ArcAppDataSearchProvider>(
                                 kMaxAppDataResults, list_controller));
   }
 
+  // TODO(crbug.com/1028447): Remove the settings shortcut provider, superseded
+  // by OsSettingsProvider.
   if (app_list_features::IsSettingsShortcutSearchEnabled()) {
-    size_t settings_shortcut_group_id = controller->AddGroup(
-        kMaxSettingsShortcutResults, 1.0, kBoostOfSettingsShortcut);
+    size_t settings_shortcut_group_id =
+        controller->AddGroup(kMaxSettingsShortcutResults);
     controller->AddProvider(
         settings_shortcut_group_id,
         std::make_unique<SettingsShortcutProvider>(profile));
@@ -182,7 +183,7 @@
 
   if (arc::IsArcAllowedForProfile(profile)) {
     size_t app_shortcut_group_id =
-        controller->AddGroup(kMaxAppShortcutResults, 1.0, kBoostOfApps);
+        controller->AddGroup(kMaxAppShortcutResults, kAppBoost);
     controller->AddProvider(
         app_shortcut_group_id,
         std::make_unique<ArcAppShortcutsSearchProvider>(
@@ -194,11 +195,11 @@
   // scores changed to fit with these providers.
   if (app_list_features::IsZeroStateMixedTypesRankerEnabled()) {
     size_t zero_state_files_group_id =
-        controller->AddGroup(kMaxZeroStateFileResults, 1.0, 0.0);
+        controller->AddGroup(kMaxZeroStateFileResults);
     controller->AddProvider(zero_state_files_group_id,
                             std::make_unique<ZeroStateFileProvider>(profile));
     size_t drive_quick_access_group_id =
-        controller->AddGroup(kMaxDriveQuickAccessResults, 1.0, 0.0);
+        controller->AddGroup(kMaxDriveQuickAccessResults);
     controller->AddProvider(
         drive_quick_access_group_id,
         std::make_unique<DriveQuickAccessProvider>(profile, controller.get()));
@@ -206,7 +207,7 @@
 
   if (app_list_features::IsLauncherSettingsSearchEnabled()) {
     size_t os_settings_search_group_id =
-        controller->AddGroup(kGenericMaxResults, 1.0, 0.0);
+        controller->AddGroup(kGenericMaxResults);
     controller->AddProvider(os_settings_search_group_id,
                             std::make_unique<OsSettingsProvider>(profile));
   }
diff --git a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
index 841ef30..e297ac5 100644
--- a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
+++ b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
@@ -157,10 +157,9 @@
 
     // TODO(warx): when fullscreen app list is default enabled, modify this test
     // to test answer card/apps group having relevance boost.
-    size_t apps_group_id = mixer_->AddGroup(kMaxAppsGroupResults, 1.0, 0.0);
-    size_t omnibox_group_id = mixer_->AddGroup(kMaxOmniboxResults, 1.0, 0.0);
-    size_t playstore_group_id =
-        mixer_->AddGroup(kMaxPlaystoreResults, 0.5, 0.0);
+    size_t apps_group_id = mixer_->AddGroup(kMaxAppsGroupResults, 0.0);
+    size_t omnibox_group_id = mixer_->AddGroup(kMaxOmniboxResults, 0.0);
+    size_t playstore_group_id = mixer_->AddGroup(kMaxPlaystoreResults, 0.0);
 
     mixer_->AddProviderToGroup(apps_group_id, providers_[0].get());
     mixer_->AddProviderToGroup(omnibox_group_id, providers_[1].get());
@@ -210,58 +209,6 @@
   DISALLOW_COPY_AND_ASSIGN(MixerTest);
 };
 
-TEST_F(MixerTest, Basic) {
-  CreateMixer();
-
-  // Note: Some cases in |expected| have vastly more results than others, due to
-  // the "at least 6" mechanism. If it gets at least 6 results from all
-  // providers, it stops at 6. If not, it fetches potentially many more results
-  // from all providers. Not ideal, but currently by design.
-  struct TestCase {
-    const size_t app_results;
-    const size_t omnibox_results;
-    const size_t playstore_results;
-    const char* expected;
-  } kTestCases[] = {
-      {0, 0, 0, ""},
-      {10, 0, 0, "app0,app1,app2,app3,app4,app5,app6,app7,app8,app9"},
-      {0, 0, 10,
-       "playstore0,playstore1,playstore2,playstore3,playstore4,playstore5,"
-       "playstore6,playstore7,playstore8,playstore9"},
-      {4, 6, 0, "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3"},
-      {4, 6, 2,
-       "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,playstore0,"
-       "playstore1"},
-      {10, 10, 10,
-       "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,playstore0,"
-       "playstore1"},
-      {0, 10, 0,
-       "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5,omnibox6,"
-       "omnibox7,omnibox8,omnibox9"},
-      {0, 10, 1,
-       "omnibox0,omnibox1,omnibox2,omnibox3,playstore0,omnibox4,omnibox5,"
-       "omnibox6,omnibox7,omnibox8,omnibox9"},
-      {0, 10, 2, "omnibox0,omnibox1,omnibox2,omnibox3,playstore0,playstore1"},
-      {1, 10, 0,
-       "app0,omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5,omnibox6,"
-       "omnibox7,omnibox8,omnibox9"},
-      {2, 10, 0, "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3"},
-      {2, 10, 1, "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,playstore0"},
-      {2, 10, 2,
-       "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,playstore0,playstore1"},
-      {2, 0, 2, "app0,app1,playstore0,playstore1"},
-      {0, 0, 0, ""}};
-
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    app_provider()->set_count(kTestCases[i].app_results);
-    omnibox_provider()->set_count(kTestCases[i].omnibox_results);
-    playstore_provider()->set_count(kTestCases[i].playstore_results);
-    RunQuery();
-
-    EXPECT_EQ(kTestCases[i].expected, GetResults()) << "Case " << i;
-  }
-}
-
 // Tests that results with display index defined, will be shown in the final
 // results.
 TEST_F(MixerTest, ResultsWithDisplayIndex) {
@@ -275,8 +222,8 @@
   RunQuery();
 
   EXPECT_EQ(
-      "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,playstore0,"
-      "playstore1",
+      "app0,omnibox0,playstore0,app1,omnibox1,playstore1,app2,omnibox2,app3,"
+      "omnibox3",
       GetResults());
 
   // If the last result has display index defined, it will be in the final
@@ -285,8 +232,8 @@
   RunQuery();
 
   EXPECT_EQ(
-      "app5,app0,omnibox0,app1,omnibox1,app2,omnibox2,omnibox3,playstore0,"
-      "playstore1",
+      "app5,app0,omnibox0,playstore0,app1,omnibox1,playstore1,app2,omnibox2,"
+      "omnibox3",
       GetResults());
 }
 
diff --git a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc
index 2566437..8a43ce8 100644
--- a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc
+++ b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "chrome/browser/password_manager/change_password_url_service_factory.h"
 #include "components/password_manager/core/browser/change_password_url_service.h"
+#include "components/password_manager/core/browser/well_known_change_password_state.h"
 #include "components/password_manager/core/browser/well_known_change_password_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "content/public/browser/browser_context.h"
@@ -116,44 +117,12 @@
 
 void WellKnownChangePasswordNavigationThrottle::FetchNonExistingResource(
     NavigationHandle* handle) {
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url =
-      CreateWellKnownNonExistingResourceURL(handle->GetURL());
-  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-  resource_request->load_flags = net::LOAD_DISABLE_CACHE;
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation(
-          "well_known_path_that_should_not_exist",
-          R"(
-        semantics {
-          sender: "Password Manager"
-          description:
-            "Check whether the site supports .well-known 'special' URLs."
-            "If the website does not support the spec we navigate to the "
-            "fallback url. See also "
-"https://wicg.github.io/change-password-url/response-code-reliability.html#iana"
-          trigger:
-            "When the user clicks 'Change password' on "
-            "chrome://settings/passwords, or when they visit the "
-            "[ORIGIN]/.well-known/change-password special URL, Chrome makes "
-            "this additional request. Chrome Password manager shows a button "
-            "with the link in the password checkup for compromised passwords "
-            "view (chrome://settings/passwords/check) and in a dialog when the "
-            "user signs in using compromised credentials."
-          data:
-            "The request body is empty. No user data is included."
-          destination: WEBSITE
-        }
-        policy {
-          cookies_allowed: NO
-          setting: "This feature cannot be disabled."
-          policy_exception_justification: "Essential for navigation."
-        })");
   auto url_loader_factory = content::BrowserContext::GetDefaultStoragePartition(
                                 handle->GetWebContents()->GetBrowserContext())
                                 ->GetURLLoaderFactoryForBrowserProcess();
-  url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
-                                                 traffic_annotation);
+  url_loader_ =
+      password_manager::CreateResourceRequestToWellKnownNonExistingResourceFor(
+          handle->GetURL());
   // Binding the callback to |this| is safe, because the navigationthrottle
   // defers if the request is not received yet. Thereby the throttle still exist
   // when the response arrives.
diff --git a/chrome/browser/ui/popup_browsertest.cc b/chrome/browser/ui/popup_browsertest.cc
index 414f23e..ae3aac4 100644
--- a/chrome/browser/ui/popup_browsertest.cc
+++ b/chrome/browser/ui/popup_browsertest.cc
@@ -165,8 +165,8 @@
       "moveTo(screen.availLeft - 50, screen.availTop);",
       "moveTo(screen.availLeft, screen.availTop + screen.availHeight + 50);",
       "moveTo(screen.availLeft, screen.availTop - 50);",
-      "moveTo(screen.availLeft + screen.availWidth + 50, "
-      "screen.availTop + screen.availHeight + 50);",
+      ("moveTo(screen.availLeft + screen.availWidth + 50, "
+       "screen.availTop + screen.availHeight + 50);"),
       "moveTo(screen.availLeft - 50, screen.availTop - 50);",
   };
   for (auto* const script : kMoveScripts) {
diff --git a/chrome/browser/ui/views/accessibility/caret_browsing_dialog_delegate.cc b/chrome/browser/ui/views/accessibility/caret_browsing_dialog_delegate.cc
index d3f7039..b1acbd3 100644
--- a/chrome/browser/ui/views/accessibility/caret_browsing_dialog_delegate.cc
+++ b/chrome/browser/ui/views/accessibility/caret_browsing_dialog_delegate.cc
@@ -48,6 +48,7 @@
 
   auto* message_label = AddChildView(std::make_unique<views::Label>(
       message_text, views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT));
+  message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   message_label->SetMultiLine(true);
 
   do_not_ask_checkbox_ = AddChildView(std::make_unique<views::Checkbox>(
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
index 7b8cd9c..d984c46b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
+++ b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
@@ -170,6 +170,8 @@
   kShowEmojiSuggestions = 1203,
   kChangeSystemLanguage = 1204,
   kOfferTranslation = 1205,
+  kAddInputMethod = 1206,
+  kSpellCheck = 1207,
 
   // Files section.
   kGoogleDriveConnection = 1300,
diff --git a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
index 3ed74f9c4..49c7f91 100644
--- a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
@@ -103,6 +103,18 @@
        {.setting = mojom::Setting::kShowInputOptionsInShelf},
        {IDS_OS_SETTINGS_TAG_LANGUAGES_INPUT_INPUT_OPTIONS_SHELF_ALT1,
         SearchConcept::kAltTagEnd}},
+      {IDS_OS_SETTINGS_TAG_LANGUAGES_ADD_INPUT_METHOD,
+       mojom::kInputSubpagePath,
+       mojom::SearchResultIcon::kGlobe,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kAddInputMethod}},
+      {IDS_OS_SETTINGS_TAG_LANGUAGES_SPELL_CHECK,
+       mojom::kInputSubpagePath,
+       mojom::SearchResultIcon::kGlobe,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kSpellCheck}},
   });
   return *tags;
 }
@@ -264,6 +276,10 @@
       {"inputMethodListTitle",
        IDS_OS_SETTINGS_LANGUAGES_INPUT_METHOD_LIST_TITLE},
       {"openOptionsPage", IDS_OS_SETTINGS_LANGUAGES_OPEN_OPTIONS_PAGE_LABEL},
+      {"addInputMethodLabel", IDS_OS_SETTINGS_LANGUAGES_ADD_INPUT_METHOD_LABEL},
+      {"spellCheckTitle", IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_TITLE},
+      {"spellCheckDisabledReason",
+       IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_DISABLED_REASON},
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 }
@@ -389,6 +405,12 @@
       IDS_OS_SETTINGS_LANGUAGES_INPUT_PAGE_TITLE, mojom::Subpage::kInput,
       mojom::SearchResultIcon::kGlobe, mojom::SearchResultDefaultRank::kMedium,
       mojom::kInputSubpagePath);
+  static constexpr mojom::Setting kInputPageSettings[] = {
+      mojom::Setting::kAddInputMethod,
+      mojom::Setting::kSpellCheck,
+  };
+  RegisterNestedSettingBulk(mojom::Subpage::kInput, kInputPageSettings,
+                            generator);
 
   // Languages and input details.
   generator->RegisterTopLevelSubpage(
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
index b373cb9..38da9c6 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler.h"
-#include "chromeos/components/account_manager/account_manager.h"
 #include "chromeos/components/account_manager/account_manager_factory.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -38,6 +37,12 @@
 constexpr char kCrosAddAccountFlow[] = "crosAddAccount";
 constexpr char kCrosAddAccountEduFlow[] = "crosAddAccountEdu";
 
+std::string AnonymizeAccountEmail(const std::string& email) {
+  std::string result;
+  base::Base64Encode(crypto::SHA256HashString(email), &result);
+  return result + "@example.com";
+}
+
 bool GaiaActionButtonsEnabled() {
   return base::FeatureList::IsEnabled(chromeos::features::kGaiaActionButtons);
 }
@@ -252,6 +257,10 @@
       base::BindRepeating(
           &InlineLoginHandlerChromeOS::ShowIncognitoAndCloseDialog,
           base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getAccounts",
+      base::BindRepeating(&InlineLoginHandlerChromeOS::GetAccountsInSession,
+                          base::Unretained(this)));
 }
 
 void InlineLoginHandlerChromeOS::SetExtraInitParams(
@@ -347,4 +356,36 @@
   close_dialog_closure_.Run();
 }
 
+void InlineLoginHandlerChromeOS::GetAccountsInSession(
+    const base::ListValue* args) {
+  const std::string& callback_id = args->GetList()[0].GetString();
+  const Profile* profile = Profile::FromWebUI(web_ui());
+  chromeos::AccountManager* account_manager =
+      g_browser_process->platform_part()
+          ->GetAccountManagerFactory()
+          ->GetAccountManager(profile->GetPath().value());
+
+  account_manager->GetAccounts(
+      base::BindOnce(&InlineLoginHandlerChromeOS::OnGetAccounts,
+                     weak_factory_.GetWeakPtr(), callback_id));
+}
+
+void InlineLoginHandlerChromeOS::OnGetAccounts(
+    const std::string& callback_id,
+    const std::vector<AccountManager::Account>& accounts) {
+  base::ListValue account_emails;
+  for (const auto& account : accounts) {
+    if (account.key.account_type ==
+        account_manager::AccountType::ACCOUNT_TYPE_ACTIVE_DIRECTORY) {
+      // Don't send Active Directory account email to Gaia.
+      account_emails.Append(AnonymizeAccountEmail(account.raw_email));
+    } else {
+      account_emails.Append(account.raw_email);
+    }
+  }
+
+  ResolveJavascriptCallback(base::Value(callback_id),
+                            std::move(account_emails));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.h b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.h
index 727ffe1..1c8fc0d 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler.h"
+#include "chromeos/components/account_manager/account_manager.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 
@@ -36,8 +37,12 @@
 
  private:
   void ShowIncognitoAndCloseDialog(const base::ListValue* args);
+  void GetAccountsInSession(const base::ListValue* args);
+  void OnGetAccounts(const std::string& callback_id,
+                     const std::vector<AccountManager::Account>& accounts);
 
   base::RepeatingClosure close_dialog_closure_;
+  base::WeakPtrFactory<InlineLoginHandlerChromeOS> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(InlineLoginHandlerChromeOS);
 };
 
diff --git a/chrome/browser/web_applications/components/app_icon_manager.h b/chrome/browser/web_applications/components/app_icon_manager.h
index ff65c92..d345409 100644
--- a/chrome/browser/web_applications/components/app_icon_manager.h
+++ b/chrome/browser/web_applications/components/app_icon_manager.h
@@ -11,6 +11,7 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
 #include "chrome/common/web_application_info.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -47,11 +48,21 @@
       const AppId& app_id,
       IconPurpose purpose,
       const std::vector<SquareSizePx>& icon_sizes_in_px) const = 0;
-  // Returns whether there is a downloaded icon matching |icon_size_in_px| for
-  // any of the given |purposes|.
+  struct IconSizeAndPurpose {
+    SquareSizePx size_px = 0;
+    IconPurpose purpose = IconPurpose::ANY;
+  };
+  // For each of |purposes|, in the given order, looks for an icon with size at
+  // least |min_icon_size|. Returns information on the first icon found.
+  virtual base::Optional<IconSizeAndPurpose> FindIconMatchBigger(
+      const AppId& app_id,
+      const std::vector<IconPurpose>& purposes,
+      SquareSizePx min_size) const = 0;
+  // Returns whether there is a downloaded icon of at least |min_size| for any
+  // of the given |purposes|.
   virtual bool HasSmallestIcon(const AppId& app_id,
                                const std::vector<IconPurpose>& purposes,
-                               SquareSizePx min_icon_size) const = 0;
+                               SquareSizePx min_size) const = 0;
 
   using ReadIconsCallback =
       base::OnceCallback<void(std::map<SquareSizePx, SkBitmap> icon_bitmaps)>;
@@ -83,9 +94,9 @@
 
   using ReadIconWithPurposeCallback =
       base::OnceCallback<void(IconPurpose, const SkBitmap&)>;
-  // For each of |purposes|, in the given order, finds the smallest icon with
-  // size at least |icon_size_in_px|. Returns the first icon found, as a bitmap.
-  // Returns empty SkBitmap in |callback| if IO error.
+  // For each of |purposes|, in the given order, looks for an icon with size at
+  // least |min_icon_size|. Returns the first icon found, as a bitmap. Returns
+  // an empty SkBitmap in |callback| if IO error.
   virtual void ReadSmallestIcon(const AppId& app_id,
                                 const std::vector<IconPurpose>& purposes,
                                 SquareSizePx min_icon_size,
@@ -99,9 +110,9 @@
 
   using ReadCompressedIconWithPurposeCallback =
       base::OnceCallback<void(IconPurpose, std::vector<uint8_t> data)>;
-  // For each of |purposes|, in the given order, finds the smallest icon with
-  // size at least |icon_size_in_px|. Returns the first icon found, compressed
-  // as PNG. Returns empty |data| in |callback| if IO error.
+  // For each of |purposes|, in the given order, looks for an icon with size at
+  // least |min_icon_size|. Returns the first icon found, compressed as PNG.
+  // Returns empty |data| in |callback| if IO error.
   virtual void ReadSmallestCompressedIcon(
       const AppId& app_id,
       const std::vector<IconPurpose>& purposes,
diff --git a/chrome/browser/web_applications/components/web_app_install_utils.cc b/chrome/browser/web_applications/components/web_app_install_utils.cc
index f9b063d..62dd216 100644
--- a/chrome/browser/web_applications/components/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/components/web_app_install_utils.cc
@@ -77,7 +77,7 @@
 // Populate |web_app_info|'s shortcuts_menu_item_infos vector using the
 // blink::Manifest's shortcuts vector.
 std::vector<WebApplicationShortcutsMenuItemInfo>
-UpdateShortcutInfosFromManifest(
+UpdateShortcutsMenuItemInfosFromManifest(
     const std::vector<blink::Manifest::ShortcutItem>& shortcuts) {
   std::vector<WebApplicationShortcutsMenuItemInfo> web_app_shortcut_infos;
   int num_shortcut_icons = 0;
@@ -216,7 +216,7 @@
       base::FeatureList::IsEnabled(
           features::kDesktopPWAsAppIconShortcutsMenu)) {
     web_app_info->shortcuts_menu_item_infos =
-        UpdateShortcutInfosFromManifest(manifest.shortcuts);
+        UpdateShortcutsMenuItemInfosFromManifest(manifest.shortcuts);
   }
 }
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc
index 67f82f91..d1fece74 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc
@@ -16,7 +16,6 @@
 #include "base/task/thread_pool.h"
 #include "chrome/browser/extensions/menu_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/image_loader.h"
@@ -202,23 +201,34 @@
   return true;
 }
 
+base::Optional<web_app::AppIconManager::IconSizeAndPurpose>
+BookmarkAppIconManager::FindIconMatchBigger(
+    const web_app::AppId& app_id,
+    const std::vector<IconPurpose>& purposes,
+    SquareSizePx min_size) const {
+  const Extension* app = GetBookmarkApp(profile_, app_id);
+  if (!app)
+    return base::nullopt;
+  // Legacy bookmark apps handle IconPurpose::ANY icons only.
+  if (!base::Contains(purposes, IconPurpose::ANY))
+    return base::nullopt;
+
+  const ExtensionIconSet& icons = IconsInfo::GetIcons(app);
+  const std::string& path = icons.Get(min_size, ExtensionIconSet::MATCH_BIGGER);
+  // Returns 0 if path is empty or not found.
+  int found_icon_size = icons.GetIconSizeFromPath(path);
+
+  if (found_icon_size == 0)
+    return base::nullopt;
+
+  return IconSizeAndPurpose{found_icon_size, IconPurpose::ANY};
+}
+
 bool BookmarkAppIconManager::HasSmallestIcon(
     const web_app::AppId& app_id,
     const std::vector<IconPurpose>& purposes,
-    SquareSizePx icon_size_in_px) const {
-  const Extension* app = GetBookmarkApp(profile_, app_id);
-  if (!app)
-    return false;
-  // Legacy bookmark apps handle IconPurpose::ANY icons only.
-  if (!base::Contains(purposes, IconPurpose::ANY))
-    return false;
-
-  const ExtensionIconSet& icons = IconsInfo::GetIcons(app);
-
-  const std::string& path =
-      icons.Get(icon_size_in_px, ExtensionIconSet::MATCH_BIGGER);
-
-  return !path.empty();
+    SquareSizePx min_size) const {
+  return FindIconMatchBigger(app_id, purposes, min_size).has_value();
 }
 
 void BookmarkAppIconManager::ReadIcons(
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h
index b6bc5ec8..c63741f94 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h
@@ -28,9 +28,13 @@
       const web_app::AppId& app_id,
       IconPurpose purpose,
       const std::vector<SquareSizePx>& icon_sizes_in_px) const override;
+  base::Optional<IconSizeAndPurpose> FindIconMatchBigger(
+      const web_app::AppId& app_id,
+      const std::vector<IconPurpose>& purposes,
+      SquareSizePx min_size) const override;
   bool HasSmallestIcon(const web_app::AppId& app_id,
                        const std::vector<IconPurpose>& purposes,
-                       SquareSizePx icon_size_in_px) const override;
+                       SquareSizePx min_size) const override;
   void ReadIcons(const web_app::AppId& app_id,
                  IconPurpose purpose,
                  const std::vector<SquareSizePx>& icon_sizes_in_px,
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc
index 9bb4f64e..1409ec9 100644
--- a/chrome/browser/web_applications/web_app_database_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -116,9 +116,8 @@
     return protocol_handlers;
   }
 
-  static std::vector<WebApplicationShortcutsMenuItemInfo> CreateShortcutInfos(
-      const std::string& base_url,
-      uint32_t suffix) {
+  static std::vector<WebApplicationShortcutsMenuItemInfo>
+  CreateShortcutsMenuItemInfos(const std::string& base_url, uint32_t suffix) {
     std::vector<WebApplicationShortcutsMenuItemInfo> shortcuts_menu_item_infos;
     for (unsigned int i = 0; i < 3; ++i) {
       std::string suffix_str =
@@ -261,7 +260,7 @@
     app->SetAdditionalSearchTerms(std::move(additional_search_terms));
 
     app->SetShortcutsMenuItemInfos(
-        CreateShortcutInfos(base_url, random.next_uint()));
+        CreateShortcutsMenuItemInfos(base_url, random.next_uint()));
     app->SetDownloadedShortcutsMenuIconsSizes(
         CreateDownloadedShortcutsMenuIconsSizes());
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager.cc b/chrome/browser/web_applications/web_app_icon_manager.cc
index 86c98c7..210e825 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager.cc
@@ -569,12 +569,34 @@
                            icon_sizes_in_px);
 }
 
+base::Optional<AppIconManager::IconSizeAndPurpose>
+WebAppIconManager::FindIconMatchBigger(const AppId& app_id,
+                                       const std::vector<IconPurpose>& purposes,
+                                       SquareSizePx min_size) const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  const WebApp* web_app = registrar_.GetAppById(app_id);
+  if (!web_app)
+    return base::nullopt;
+
+  // Must iterate through purposes in order given.
+  for (IconPurpose purpose : purposes) {
+    const std::vector<SquareSizePx>& sizes =
+        web_app->downloaded_icon_sizes(purpose);
+    DCHECK(base::STLIsSorted(sizes));
+    for (SquareSizePx size : sizes) {
+      if (size >= min_size)
+        return IconSizeAndPurpose{size, purpose};
+    }
+  }
+
+  return base::nullopt;
+}
+
 bool WebAppIconManager::HasSmallestIcon(
     const AppId& app_id,
     const std::vector<IconPurpose>& purposes,
-    SquareSizePx min_size_in_px) const {
-  return FindDownloadedIconMatchBigger(app_id, purposes, min_size_in_px)
-      .has_value();
+    SquareSizePx min_size) const {
+  return FindIconMatchBigger(app_id, purposes, min_size).has_value();
 }
 
 void WebAppIconManager::ReadIcons(const AppId& app_id,
@@ -638,8 +660,8 @@
     ReadIconWithPurposeCallback callback) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  base::Optional<WebAppIconManager::SizeAndPurpose> best_icon =
-      FindDownloadedIconMatchBigger(app_id, purposes, min_size_in_px);
+  base::Optional<IconSizeAndPurpose> best_icon =
+      FindIconMatchBigger(app_id, purposes, min_size_in_px);
   DCHECK(best_icon.has_value());
   IconId icon_id(app_id, best_icon->purpose, best_icon->size_px);
   ReadIconCallback wrapped = base::BindOnce(
@@ -659,8 +681,8 @@
     ReadCompressedIconWithPurposeCallback callback) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  base::Optional<WebAppIconManager::SizeAndPurpose> best_icon =
-      FindDownloadedIconMatchBigger(app_id, purposes, min_size_in_px);
+  base::Optional<IconSizeAndPurpose> best_icon =
+      FindIconMatchBigger(app_id, purposes, min_size_in_px);
   DCHECK(best_icon.has_value());
   IconId icon_id(app_id, best_icon->purpose, best_icon->size_px);
   ReadCompressedIconCallback wrapped =
@@ -693,11 +715,10 @@
                                           IconPurpose purpose,
                                           SquareSizePx desired_icon_size,
                                           ReadIconsCallback callback) const {
-  base::Optional<SizeAndPurpose> best_icon =
-      FindDownloadedIconMatchBigger(app_id, {purpose}, desired_icon_size);
+  base::Optional<IconSizeAndPurpose> best_icon =
+      FindIconMatchBigger(app_id, {purpose}, desired_icon_size);
   if (!best_icon) {
-    best_icon =
-        FindDownloadedIconMatchSmaller(app_id, {purpose}, desired_icon_size);
+    best_icon = FindIconMatchSmaller(app_id, {purpose}, desired_icon_size);
   }
 
   if (!best_icon) {
@@ -719,35 +740,11 @@
   favicon_read_callback_ = std::move(callback);
 }
 
-base::Optional<WebAppIconManager::SizeAndPurpose>
-WebAppIconManager::FindDownloadedIconMatchBigger(
+base::Optional<AppIconManager::IconSizeAndPurpose>
+WebAppIconManager::FindIconMatchSmaller(
     const AppId& app_id,
     const std::vector<IconPurpose>& purposes,
-    SquareSizePx desired_size) const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  const WebApp* web_app = registrar_.GetAppById(app_id);
-  if (!web_app)
-    return base::nullopt;
-
-  // Must iterate through purposes in order given.
-  for (IconPurpose purpose : purposes) {
-    const std::vector<SquareSizePx>& sizes =
-        web_app->downloaded_icon_sizes(purpose);
-    DCHECK(base::STLIsSorted(sizes));
-    for (SquareSizePx size : sizes) {
-      if (size >= desired_size)
-        return WebAppIconManager::SizeAndPurpose{size, purpose};
-    }
-  }
-
-  return base::nullopt;
-}
-
-base::Optional<WebAppIconManager::SizeAndPurpose>
-WebAppIconManager::FindDownloadedIconMatchSmaller(
-    const AppId& app_id,
-    const std::vector<IconPurpose>& purposes,
-    SquareSizePx desired_size) const {
+    SquareSizePx max_size) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   const WebApp* web_app = registrar_.GetAppById(app_id);
   if (!web_app)
@@ -759,8 +756,8 @@
         web_app->downloaded_icon_sizes(purpose);
     DCHECK(base::STLIsSorted(sizes));
     for (SquareSizePx size : base::Reversed(sizes)) {
-      if (size <= desired_size)
-        return WebAppIconManager::SizeAndPurpose{size, purpose};
+      if (size <= max_size)
+        return IconSizeAndPurpose{size, purpose};
     }
   }
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager.h b/chrome/browser/web_applications/web_app_icon_manager.h
index d41824c..e9b1854 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.h
+++ b/chrome/browser/web_applications/web_app_icon_manager.h
@@ -57,9 +57,13 @@
       const AppId& app_id,
       IconPurpose purpose,
       const std::vector<SquareSizePx>& icon_sizes_in_px) const override;
+  base::Optional<IconSizeAndPurpose> FindIconMatchBigger(
+      const AppId& app_id,
+      const std::vector<IconPurpose>& purposes,
+      SquareSizePx min_size) const override;
   bool HasSmallestIcon(const AppId& app_id,
                        const std::vector<IconPurpose>& purposes,
-                       SquareSizePx min_size_in_px) const override;
+                       SquareSizePx min_size) const override;
   void ReadIcons(const AppId& app_id,
                  IconPurpose purpose,
                  const std::vector<SquareSizePx>& icon_sizes,
@@ -96,18 +100,10 @@
   void SetFaviconReadCallbackForTesting(FaviconReadCallback callback);
 
  private:
-  struct SizeAndPurpose {
-    SquareSizePx size_px = 0;
-    IconPurpose purpose = IconPurpose::ANY;
-  };
-  base::Optional<WebAppIconManager::SizeAndPurpose>
-  FindDownloadedIconMatchBigger(const AppId& app_id,
-                                const std::vector<IconPurpose>& purposes,
-                                SquareSizePx desired_size) const;
-  base::Optional<SizeAndPurpose> FindDownloadedIconMatchSmaller(
+  base::Optional<IconSizeAndPurpose> FindIconMatchSmaller(
       const AppId& app_id,
       const std::vector<IconPurpose>& purposes,
-      SquareSizePx desired_size) const;
+      SquareSizePx max_size) const;
 
   void ReadFavicon(const AppId& app_id);
   void OnReadFavicon(const AppId& app_id, const SkBitmap&);
diff --git a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
index b483598..c429aec 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
@@ -36,6 +36,12 @@
 
 namespace web_app {
 
+namespace {
+
+using IconSizeAndPurpose = AppIconManager::IconSizeAndPurpose;
+
+}  // namespace
+
 class WebAppIconManagerTest : public WebAppTest {
   void SetUp() override {
     WebAppTest::SetUp();
@@ -131,6 +137,41 @@
     return downloaded_shortcuts_menu_icons_sizes;
   }
 
+  struct PurposeAndBitmap {
+    IconPurpose purpose;
+    SkBitmap bitmap;
+  };
+  PurposeAndBitmap ReadSmallestIcon(const AppId& app_id,
+                                    const std::vector<IconPurpose>& purposes,
+                                    SquareSizePx min_icon_size) {
+    PurposeAndBitmap result;
+    base::RunLoop run_loop;
+    icon_manager().ReadSmallestIcon(
+        app_id, purposes, min_icon_size,
+        base::BindLambdaForTesting(
+            [&](IconPurpose purpose, const SkBitmap& bitmap) {
+              result.purpose = purpose;
+              result.bitmap = bitmap;
+              run_loop.Quit();
+            }));
+    run_loop.Run();
+    return result;
+  }
+
+  SkBitmap ReadSmallestIconAny(const AppId& app_id,
+                               SquareSizePx min_icon_size) {
+    SkBitmap result;
+    base::RunLoop run_loop;
+    icon_manager().ReadSmallestIconAny(
+        app_id, min_icon_size,
+        base::BindLambdaForTesting([&](const SkBitmap& bitmap) {
+          result = bitmap;
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+    return result;
+  }
+
   struct PurposeAndData {
     IconPurpose purpose;
     std::vector<uint8_t> data;
@@ -658,6 +699,11 @@
   }
 }
 
+// Simple struct doesn't have an operator==.
+bool operator==(const IconSizeAndPurpose& a, const IconSizeAndPurpose& b) {
+  return a.size_px == b.size_px && a.purpose == b.purpose;
+}
+
 TEST_F(WebAppIconManagerTest, FindSmallest) {
   auto web_app = CreateWebApp();
   const AppId app_id = web_app->app_id();
@@ -665,49 +711,79 @@
   const std::vector<int> sizes_px{10, 60, 50, 20, 30};
   const std::vector<SkColor> colors{SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN,
                                     SK_ColorBLUE, SK_ColorMAGENTA};
-  WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
+  WriteIcons(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, sizes_px,
+             colors);
 
   web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
+  // Pretend we only have one size of maskable icon.
+  web_app->SetDownloadedIconSizes(IconPurpose::MASKABLE, {20});
 
   controller().RegisterApp(std::move(web_app));
 
   EXPECT_FALSE(icon_manager().HasSmallestIcon(app_id, {IconPurpose::ANY}, 70));
+  EXPECT_EQ(base::nullopt,
+            icon_manager().FindIconMatchBigger(app_id, {IconPurpose::ANY}, 70));
+
   EXPECT_FALSE(icon_manager().HasSmallestIcon(
       app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, 70));
+  EXPECT_EQ(base::nullopt,
+            icon_manager().FindIconMatchBigger(
+                app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, 70));
+
   EXPECT_FALSE(
       icon_manager().HasSmallestIcon(app_id, {IconPurpose::MASKABLE}, 40));
+  EXPECT_EQ(base::nullopt, icon_manager().FindIconMatchBigger(
+                               app_id, {IconPurpose::MASKABLE}, 40));
 
   EXPECT_TRUE(icon_manager().HasSmallestIcon(
       app_id, {IconPurpose::MASKABLE, IconPurpose::ANY}, 40));
+  EXPECT_EQ((IconSizeAndPurpose{50, IconPurpose::ANY}),
+            icon_manager()
+                .FindIconMatchBigger(
+                    app_id, {IconPurpose::MASKABLE, IconPurpose::ANY}, 40)
+                .value());
+
   EXPECT_TRUE(icon_manager().HasSmallestIcon(
       app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, 20));
+  EXPECT_EQ((IconSizeAndPurpose{20, IconPurpose::ANY}),
+            icon_manager()
+                .FindIconMatchBigger(
+                    app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, 20)
+                .value());
+
+  EXPECT_TRUE(icon_manager().HasSmallestIcon(
+      app_id, {IconPurpose::MASKABLE, IconPurpose::ANY}, 10));
+  EXPECT_EQ((IconSizeAndPurpose{20, IconPurpose::MASKABLE}),
+            icon_manager()
+                .FindIconMatchBigger(
+                    app_id, {IconPurpose::MASKABLE, IconPurpose::ANY}, 10)
+                .value());
 
   {
-    base::RunLoop run_loop;
-
     EXPECT_TRUE(icon_manager().HasSmallestIcon(app_id, {IconPurpose::ANY}, 40));
-    icon_manager().ReadSmallestIconAny(
-        app_id, 40, base::BindLambdaForTesting([&](const SkBitmap& bitmap) {
-          EXPECT_FALSE(bitmap.empty());
-          EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(0, 0));
-          run_loop.Quit();
-        }));
-
-    run_loop.Run();
+    SkBitmap bitmap = ReadSmallestIconAny(app_id, 40);
+    EXPECT_FALSE(bitmap.empty());
+    EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(0, 0));
   }
-
   {
-    base::RunLoop run_loop;
-
     EXPECT_TRUE(icon_manager().HasSmallestIcon(app_id, {IconPurpose::ANY}, 20));
-    icon_manager().ReadSmallestIconAny(
-        app_id, 20, base::BindLambdaForTesting([&](const SkBitmap& bitmap) {
-          EXPECT_FALSE(bitmap.empty());
-          EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(0, 0));
-          run_loop.Quit();
-        }));
-
-    run_loop.Run();
+    SkBitmap bitmap = ReadSmallestIconAny(app_id, 20);
+    EXPECT_FALSE(bitmap.empty());
+    EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(0, 0));
+  }
+  {
+    PurposeAndBitmap result =
+        ReadSmallestIcon(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, 20);
+    EXPECT_FALSE(result.bitmap.empty());
+    EXPECT_EQ(IconPurpose::ANY, result.purpose);
+    EXPECT_EQ(SK_ColorBLUE, result.bitmap.getColor(0, 0));
+  }
+  {
+    PurposeAndBitmap result =
+        ReadSmallestIcon(app_id, {IconPurpose::MASKABLE, IconPurpose::ANY}, 20);
+    EXPECT_FALSE(result.bitmap.empty());
+    EXPECT_EQ(IconPurpose::MASKABLE, result.purpose);
+    EXPECT_EQ(SK_ColorBLUE, result.bitmap.getColor(0, 0));
   }
 }
 
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.cc b/chrome/browser/web_applications/web_app_shortcut_manager.cc
index 8004ff7..17879460 100644
--- a/chrome/browser/web_applications/web_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.cc
@@ -54,6 +54,9 @@
       app->downloaded_icon_sizes(IconPurpose::ANY),
       GetDesiredIconSizesForShortcut());
 
+  // Optimistic check to help debug low-frequency crash.
+  // TODO(crbug.com/1113276): Make this a DCHECK before hitting stable.
+  CHECK(icon_manager_);
   if (!icon_sizes_in_px.empty()) {
     icon_manager_->ReadIcons(app_id, IconPurpose::ANY, icon_sizes_in_px,
                              base::BindOnce(&WebAppShortcutManager::OnIconsRead,
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index af0f2a7..92243517 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1597514130-fe0a8d516b962baead2578c487739528f5924993.profdata
+chrome-mac-master-1597574780-11032f77f0853e1d71f33728c0242d630bf5af1f.profdata
diff --git a/chrome/common/extensions/api/launcher_search_provider.idl b/chrome/common/extensions/api/launcher_search_provider.idl
index 5f59f72..2521a83 100644
--- a/chrome/common/extensions/api/launcher_search_provider.idl
+++ b/chrome/common/extensions/api/launcher_search_provider.idl
@@ -11,8 +11,8 @@
   dictionary SearchResult {
     DOMString itemId;
     DOMString title;
-    // If iconUrl is not provided, app/extension icon is used automatically.
-    DOMString? iconUrl;
+    // If iconType is not provided, a generic icon is used automatically.
+    DOMString? iconType;
     // Relevance ranges from 0 to 4. 0 is the lowest relevance, 4 is highest.
     long relevance;
   };
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index acd11f1..cbf9a60c3 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -38,6 +38,7 @@
   ]
   if (is_chromeos) {
     deps += [
+      "//chromeos/components/remote_apps/mojom:mojom_js",
       "//chromeos/services/ime/public/mojom:mojom_js",
       "//chromeos/services/tts/public/mojom:mojom_js",
     ]
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 8515cff..4f5a719 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -178,6 +178,14 @@
   source_map->RegisterSource("chromeos.tts.mojom.tts_stream.mojom",
                              IDR_TTS_STREAM_MOJOM_JS);
   source_map->RegisterSource("chromeos.tts.stream", IDR_TTS_STREAM_BINDINGS_JS);
+
+  // Imprivata API.
+  source_map->RegisterSource("chromeos.remote_apps.mojom-lite",
+                             IDR_REMOTE_APPS_MOJOM_LITE_JS);
+  source_map->RegisterSource("chromeos.remote_apps",
+                             IDR_REMOTE_APPS_BINDINGS_JS);
+  source_map->RegisterSource("url/mojom/url.mojom-lite",
+                             IDR_MOJO_URL_MOJOM_LITE_JS);
 #endif  // defined(OS_CHROMEOS)
 
   source_map->RegisterSource(
diff --git a/chrome/renderer/resources/extensions/remote_apps/OWNERS b/chrome/renderer/resources/extensions/remote_apps/OWNERS
new file mode 100644
index 0000000..fc0c3ac
--- /dev/null
+++ b/chrome/renderer/resources/extensions/remote_apps/OWNERS
@@ -0,0 +1,2 @@
+hendrich@chromium.org
+jityao@google.com
diff --git a/chrome/renderer/resources/extensions/remote_apps/remote_apps_bindings.js b/chrome/renderer/resources/extensions/remote_apps/remote_apps_bindings.js
new file mode 100644
index 0000000..4c5ee06
--- /dev/null
+++ b/chrome/renderer/resources/extensions/remote_apps/remote_apps_bindings.js
@@ -0,0 +1,61 @@
+// Copyright 2020 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.
+
+'use strict';
+
+if ((typeof mojo === 'undefined') || !mojo.bindingsLibraryInitialized) {
+  loadScript('mojo_bindings_lite');
+}
+
+loadScript('url/mojom/url.mojom-lite');
+loadScript('chromeos.remote_apps.mojom-lite');
+
+class RemoteAppsAdapter {
+  constructor() {
+    const factory = chromeos.remoteApps.mojom.RemoteAppsFactory.getRemote();
+
+    this.remoteApps_ = new chromeos.remoteApps.mojom.RemoteAppsRemote();
+    this.callbackRouter_ =
+        new chromeos.remoteApps.mojom.RemoteAppLaunchObserverCallbackRouter();
+    factory.create(
+        this.remoteApps_.$.bindNewPipeAndPassReceiver(),
+        this.callbackRouter_.$.bindNewPipeAndPassRemote());
+  }
+
+  /**
+   * Adds a folder to the launcher. Note that empty folders are not shown in
+   * the launcher.
+   * @param {string} name name of the added folder
+   * @return {!Promise<!{folderId: string, error: string}>} ID for the added
+   *     folder
+   */
+  addFolder(name) {
+    return this.remoteApps_.addFolder(name);
+  }
+
+  /**
+   * Adds an app to the launcher.
+   * @param {string} name name of the added app
+   * @param {string} folderId Id of the parent folder. An empty string
+   *     indicates the app does not have a parent folder.
+   * @param {string} iconUrl URL to an image representing the app's icon
+   * @return {!Promise<!{appId: string, error: string}>} ID for the
+   *     added app.
+   */
+  addApp(name, folderId, iconUrl) {
+    return this.remoteApps_.addApp(name, folderId, {url: iconUrl});
+  }
+
+  /**
+   * Adds a callback for remote app launch events.
+   * @param {function(string)} callback called when a remote app is launched
+   *     with the app ID as argument.
+   * @return {!Promise<void>}
+   */
+  addRemoteAppLaunchObserver(callback) {
+    return this.callbackRouter_.onRemoteAppLaunched.addListener(callback);
+  }
+}
+
+exports.$set('returnValue', new RemoteAppsAdapter());
diff --git a/chrome/renderer/resources/renderer_resources.grd b/chrome/renderer/resources/renderer_resources.grd
index cadb90c..a0574ab 100644
--- a/chrome/renderer/resources/renderer_resources.grd
+++ b/chrome/renderer/resources/renderer_resources.grd
@@ -63,10 +63,15 @@
 
           <!-- ChromeOS IME Mojo service and bindings. -->
           <include name="IDR_IME_SERVICE_BINDINGS_JS" file="extensions\chromeos_ime_service_bindings.js" type="BINDATA" />
-          <include name="IDR_IME_SERVICE_MOJOM_JS" file="${mojom_root}\chromeos/services/ime/public/mojom/input_engine.mojom.js" use_base_dir="false" type="BINDATA" />
+          <include name="IDR_IME_SERVICE_MOJOM_JS" file="${mojom_root}\chromeos\services\ime\public\mojom\input_engine.mojom.js" use_base_dir="false" type="BINDATA" />
+
+          <!-- Remote Apps bindings. -->
+          <include name="IDR_REMOTE_APPS_BINDINGS_JS" file="extensions\remote_apps\remote_apps_bindings.js" type="BINDATA" />
+          <include name="IDR_REMOTE_APPS_MOJOM_LITE_JS" file="${mojom_root}\chromeos\components\remote_apps\mojom\remote_apps.mojom-lite.js" use_base_dir="false" type="BINDATA" />
+          <include name="IDR_MOJO_URL_MOJOM_LITE_JS" file="${mojom_root}\url\mojom\url.mojom-lite.js" use_base_dir="false" type="BINDATA" />
 
           <include name="IDR_TTS_STREAM_BINDINGS_JS" file="extensions\chromeos_tts_stream_bindings.js" type="BINDATA" />
-          <include name="IDR_TTS_STREAM_MOJOM_JS" file="${mojom_root}\chromeos/services/tts/public/mojom/tts_service.mojom.js" use_base_dir="false" type="BINDATA" />
+          <include name="IDR_TTS_STREAM_MOJOM_JS" file="${mojom_root}\chromeos\services\tts\public\mojom\tts_service.mojom.js" use_base_dir="false" type="BINDATA" />
         </if>
         <!-- Media Router Mojo service and bindings. -->
         <include name="IDR_MEDIA_CONTROLLER_MOJOM_JS" file="${mojom_root}\chrome\common\media_router\mojom\media_controller.mojom.js" use_base_dir="false" type="BINDATA" />
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4eba90e..dbb58d7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -970,7 +970,7 @@
       "../browser/media/test_license_server_config.h",
       "../browser/media/unified_autoplay_browsertest.cc",
       "../browser/media/webrtc/media_stream_devices_controller_browsertest.cc",
-      "../browser/media/webrtc/media_stream_infobar_browsertest.cc",
+      "../browser/media/webrtc/media_stream_permission_browsertest.cc",
       "../browser/media/webrtc/test_stats_dictionary.cc",
       "../browser/media/webrtc/test_stats_dictionary.h",
       "../browser/media/webrtc/test_stats_dictionary_unittest.cc",
@@ -2490,6 +2490,7 @@
         "../browser/chromeos/printing/test_printer_configurer.cc",
         "../browser/chromeos/printing/test_printer_configurer.h",
         "../browser/chromeos/profiles/profile_helper_browsertest.cc",
+        "../browser/chromeos/remote_apps/remote_apps_impl_browsertest.cc",
         "../browser/chromeos/remote_apps/remote_apps_manager_browsertest.cc",
         "../browser/chromeos/shutdown_policy_browsertest.cc",
         "../browser/chromeos/startup_settings_cache_browsertest.cc",
diff --git a/chrome/test/data/extensions/remote_apps/extension/manifest.json b/chrome/test/data/extensions/remote_apps/extension/manifest.json
new file mode 100644
index 0000000..e73a462
--- /dev/null
+++ b/chrome/test/data/extensions/remote_apps/extension/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Remote Apps",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "Browser test for Remote Apps Mojo Private API",
+  "background": {
+    "scripts": ["test.js"]
+  }
+}
diff --git a/chrome/test/data/extensions/remote_apps/extension/test.js b/chrome/test/data/extensions/remote_apps/extension/test.js
new file mode 100644
index 0000000..ef350b7
--- /dev/null
+++ b/chrome/test/data/extensions/remote_apps/extension/test.js
@@ -0,0 +1,66 @@
+// Copyright 2020 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.
+
+let api;
+
+const testCases = [
+  async function AddApp() {
+    const result1 = await api.addApp('App 1', '', '');
+    chrome.test.assertFalse(!!result1.error);
+    chrome.test.assertEq('Id 1', result1.appId);
+
+    const result2 = await api.addApp('App 2', 'missing', '');
+    chrome.test.assertEq('Folder ID provided does not exist', result2.error);
+
+    chrome.test.succeed();
+  },
+  async function AddFolderAndApps() {
+    const result1 = await api.addFolder('Folder 1');
+    const folderId = result1.folderId;
+    chrome.test.assertFalse(!!result1.error);
+    chrome.test.assertEq('Id 1', folderId);
+
+    const result2 = await api.addApp('App 1', folderId, '');
+    chrome.test.assertFalse(!!result2.error);
+    chrome.test.assertEq('Id 2', result2.appId);
+
+    const result3 = await api.addApp('App 2', folderId, '');
+    chrome.test.assertFalse(!!result3.error);
+    chrome.test.assertEq('Id 3', result3.appId);
+
+    chrome.test.succeed();
+  },
+  async function OnRemoteAppLaunched() {
+    let actualId = '';
+    await new Promise(async (resolve) => {
+      await api.addRemoteAppLaunchObserver(id => {
+        actualId = id;
+        resolve();
+      });
+      await api.addApp('App 1', '', '');
+      chrome.test.sendMessage('Remote app added');
+    });
+
+    chrome.test.assertEq('Id 1', actualId);
+    chrome.test.succeed();
+  },
+];
+
+chrome.test.getConfig(async (config) => {
+  try {
+    api = await chrome.mojoPrivate.requireAsync('chromeos.remote_apps');
+  } catch (e) {
+    chrome.test.notifyFail('Could not get mojoPrivate bindings: ' + e.message);
+    return;
+  }
+
+  const testName = config.customArg;
+  const testCase = testCases.find((f) => f.name === testName);
+  if (!testCase) {
+    chrome.test.notifyFail('Test case \'' + testName + '\' not found');
+    return;
+  }
+
+  chrome.test.runTests([testCase]);
+});
diff --git a/chrome/test/data/extensions/remote_apps/remote_apps.pem b/chrome/test/data/extensions/remote_apps/remote_apps.pem
new file mode 100644
index 0000000..2285fbc7
--- /dev/null
+++ b/chrome/test/data/extensions/remote_apps/remote_apps.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDrhtzVny69zwz3
+F0n517RrPaeuiXF9f7TXf+K+xrL3p0NDTrP6pj5A9tV2rbhCrMqEd6ub5WRhl7Y8
+JlnWcAs6UikeJaQU7uSSVXxw2/ZJdEgTrcjL6DvfyyGpWf33TQn8yHVHpqiRxXr5
+NV2ciA0Vv8abNgbi5EUQrM+yKXi3FrCGBewXNoffA8tUV3jYEdHEJirE3y1s65r9
+xD9RMfPlGt6lV63EOGy+Ti88YldKPB6HiRHD9GmIH3BPkan9YGlmb4RBWLfoUNZS
+jrrUAlQzkUaWLyqTYHZqtpNHaKClCAX6DNAodgchzd+YNWW/Ysev6et6IkAO5dbl
+v4gxEkAPAgMBAAECggEAKiKv6kW2mn1qr9/KO7jDzbWzhG2RUKbipvT5jzDD/rs9
+NNLlLu/DzmJ6UOeGQeNgva8dE+BHg5AdKYig5NSZpZ7iPUL1pksQuD8z6orndj+n
+z2F1PUl4QLK5/G6dmTr+kOsZ1C40FRQTynaqHyFV2fC7qrPRKpE06+VGqPRzZKmC
+HjeLUTevBgOYmVB/bRn1uc7yZN2YpuDoJ9BtU1HopyqVFVxTvJorsCAYD+94hS6I
++lKzW+X1U0JDGjTRaRZqHaOc7kgKJswD1B6xVKv58ZO4mRhmKbKtaKRF3IVLz9vb
+RyoClY2Qrn57hOMSgKyh+jxN8jpiW76bTHOi2GofVQKBgQD6PhSHzqpDAVVg+ivR
+JykRjfVtG5mOAYPB4PAZX+8KuKXxtFuh9xN98zJiB/EaqJNP0Kcnd09enkqHN4Cm
+D8WEBzjokIxJQf55+DzeVtC1DkCAzuWdfXeJDjOQ/e447L9xeo0ms9ivjsWpl2T+
+p6jfx7nk1N1cPZUGyIso0m1oVQKBgQDw8huFWKEM4K5TXMF9Z/keoS/q6uVoeSkB
+335S/iZMEmnv8eG46y4ID30Mg4E4gye9U4Jc6wauorQYm1lOpfVlYxsVh7TaMFLk
+mQ+jUWttIeURye3qn3t9YCSsIdKydNUrkkJd4nCCr31rPSQhRWa5PQUVjtOqI4B/
+siafBDo60wKBgQCpC6by1zlNamkyyc0vzTSBF1TkD/D7bSqEnl+TxKrGo1X2odAE
+6dPREajHcHX/fEGHeXxxvLdxQ501GtldVOoo9ngLIxqhomM2Iet8h0kWBjqsyRdz
+/H3zqBRNrjxvV/87uX4A1x1Z+yisGAmxvbDm+xUo8GNZHIC/xFm9iek+wQKBgDQj
+0DzM7x0ASfkUK3Ld2xT7wIjPiBFRlsQm/wkqolL38SDRcQ05J17rKx5YHtCB4Umh
+FqbQ3UNRRjPE+lCArVfhWG0STtqgdm+th6rJ5btaCF4PGoMZO/nnokf1kci4a6Dg
+J6h1Ze+B1lwsgPMKN66CO+VsYPWCdT4s6RqkKY2tAoGBAOiyRyW3RfpdGO36mv7p
+r7qZ++tH+ZnTZ6CAp/+MTcx0XpCUnmSOGt0fU83TI9ujBeVJSoafg2MB/Th5UX11
+RkN67zkTqeyej5scAzoTB+FD4+/zcrCfLze30dLCvtGp/IdwyLv9X+Yd4uxPIugm
+CGqT0AcAo852wwzRPS/7eB6J
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/webrtc/video_detector.js b/chrome/test/data/webrtc/video_detector.js
index 4c96610..cab940ad 100644
--- a/chrome/test/data/webrtc/video_detector.js
+++ b/chrome/test/data/webrtc/video_detector.js
@@ -79,6 +79,25 @@
 }
 
 /**
+ * Checks if the video has stopped
+ *
+ * @return {string} video-stopped or video-not-stopped.
+ */
+function isVideoStopped() {
+  // Video is considered to be stopped if the last 5 fingerprints are the same.
+  // We only check for rough equality though to account for rounding errors.
+  if (gFingerprints.length < 5)
+    returnToTest('video-not-stopped');
+
+  if (allElementsRoughlyEqualTo_(gFingerprints.slice(-5),
+                                 gFingerprints[gFingerprints.length - 1])) {
+    returnToTest('video-stopped');
+  }
+
+  returnToTest('video-not-stopped');
+}
+
+/**
  * Queries for the stream size (not necessarily the size at which the video tag
  * is rendered).
  *
diff --git a/chrome/test/data/webui/chromeos/edu_login/edu_login_signin_test.js b/chrome/test/data/webui/chromeos/edu_login/edu_login_signin_test.js
index 03e56aa..8a6911d 100644
--- a/chrome/test/data/webui/chromeos/edu_login/edu_login_signin_test.js
+++ b/chrome/test/data/webui/chromeos/edu_login/edu_login_signin_test.js
@@ -11,7 +11,7 @@
 import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {TestEduAccountLoginBrowserProxy} from './edu_login_test_util.js';
+import {getFakeAccountsList, TestEduAccountLoginBrowserProxy} from './edu_login_test_util.js';
 
 window.edu_login_signin_tests = {};
 edu_login_signin_tests.suiteName = 'EduLoginSigninTest';
@@ -45,6 +45,10 @@
       this.loadCalls = 0;
       /** @type {Number} */
       this.resetStatesCalls = 0;
+      /** @type {number} */
+      this.getAccountsResponseCalls = 0;
+      /** @type {Array<string>} */
+      this.getAccountsResponseResult = null;
     }
 
     /**
@@ -60,6 +64,14 @@
     resetStates() {
       this.resetStatesCalls++;
     }
+
+    /**
+     * @param {Array<string>} accounts list of emails.
+     */
+    getAccountsResponse(accounts) {
+      this.getAccountsResponseCalls++;
+      this.getAccountsResponseResult = accounts;
+    }
   }
 
   setup(function() {
@@ -119,6 +131,15 @@
           assertEquals(fakeCredentials, result[0]);
           assertDeepEquals(fakeLoginParams, result[1]);
         });
+
+        testAuthenticator.dispatchEvent(new Event('getAccounts'));
+        assertEquals(1, testBrowserProxy.getCallCount('getAccounts'));
+        testBrowserProxy.whenCalled('getAccounts').then(function() {
+          assertEquals(1, testAuthenticator.getAccountsResponseCalls);
+          assertDeepEquals(
+              getFakeAccountsList(),
+              testAuthenticator.getAccountsResponseResult);
+        });
       });
 
   test(assert(edu_login_signin_tests.TestNames.GoBackInWebview), function() {
diff --git a/chrome/test/data/webui/chromeos/edu_login/edu_login_test_util.js b/chrome/test/data/webui/chromeos/edu_login/edu_login_test_util.js
index 0e14524..cb43dd4d 100644
--- a/chrome/test/data/webui/chromeos/edu_login/edu_login_test_util.js
+++ b/chrome/test/data/webui/chromeos/edu_login/edu_login_test_util.js
@@ -29,6 +29,11 @@
   ];
 }
 
+/** @return {!Array<string>} */
+export function getFakeAccountsList() {
+  return ['test@gmail.com', 'test2@gmail.com', 'test3@gmail.com'];
+}
+
 /** @implements {EduAccountLoginBrowserProxy} */
 export class TestEduAccountLoginBrowserProxy extends TestBrowserProxy {
   constructor() {
@@ -40,6 +45,7 @@
       'authExtensionReady',
       'switchToFullTab',
       'completeLogin',
+      'getAccounts',
       'dialogClose',
     ]);
 
@@ -107,6 +113,12 @@
   }
 
   /** @override */
+  getAccounts() {
+    this.methodCalled('getAccounts');
+    return Promise.resolve(getFakeAccountsList());
+  }
+
+  /** @override */
   dialogClose() {
     this.methodCalled('dialogClose');
   }
diff --git a/chrome/test/data/webui/inline_login/inline_login_test.js b/chrome/test/data/webui/inline_login/inline_login_test.js
index 63fc5177..11aa9b50 100644
--- a/chrome/test/data/webui/inline_login/inline_login_test.js
+++ b/chrome/test/data/webui/inline_login/inline_login_test.js
@@ -10,8 +10,9 @@
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
-import {TestAuthenticator, TestInlineLoginBrowserProxy} from './inline_login_test_util.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
+
+import {getFakeAccountsList, TestAuthenticator, TestInlineLoginBrowserProxy} from './inline_login_test_util.js';
 
 window.inline_login_test = {};
 inline_login_test.suiteName = 'InlineLoginTest';
@@ -97,6 +98,14 @@
 
     testAuthenticator.dispatchEvent(new Event('showIncognito'));
     assertEquals(1, testBrowserProxy.getCallCount('showIncognito'));
+
+    testAuthenticator.dispatchEvent(new Event('getAccounts'));
+    assertEquals(1, testBrowserProxy.getCallCount('getAccounts'));
+    testBrowserProxy.whenCalled('getAccounts').then(function() {
+      assertEquals(1, testAuthenticator.getAccountsResponseCalls);
+      assertDeepEquals(
+          getFakeAccountsList(), testAuthenticator.getAccountsResponseResult);
+    });
   });
 
   test(assert(inline_login_test.TestNames.BackButton), () => {
diff --git a/chrome/test/data/webui/inline_login/inline_login_test_util.js b/chrome/test/data/webui/inline_login/inline_login_test_util.js
index caaa3ab..3691ea1 100644
--- a/chrome/test/data/webui/inline_login/inline_login_test_util.js
+++ b/chrome/test/data/webui/inline_login/inline_login_test_util.js
@@ -8,6 +8,11 @@
 
 import {TestBrowserProxy} from '../test_browser_proxy.m.js';
 
+/** @return {!Array<string>} */
+export function getFakeAccountsList() {
+  return ['test@gmail.com', 'test2@gmail.com', 'test3@gmail.com'];
+}
+
 export class TestAuthenticator extends EventTarget {
   constructor() {
     super();
@@ -17,6 +22,10 @@
     this.data = null;
     /** @type {number} */
     this.loadCalls = 0;
+    /** @type {number} */
+    this.getAccountsResponseCalls = 0;
+    /** @type {Array<string>} */
+    this.getAccountsResponseResult = null;
   }
 
   /**
@@ -28,6 +37,14 @@
     this.authMode = authMode;
     this.data = data;
   }
+
+  /**
+   * @param {Array<string>} accounts list of emails.
+   */
+  getAccountsResponse(accounts) {
+    this.getAccountsResponseCalls++;
+    this.getAccountsResponseResult = accounts;
+  }
 }
 
 /** @implements {InlineLoginBrowserProxy} */
@@ -41,6 +58,7 @@
       'lstFetchResults',
       'metricsHandler:recordAction',
       'showIncognito',
+      'getAccounts',
       'dialogClose',
     ]);
   }
@@ -81,6 +99,12 @@
   }
 
   /** @override */
+  getAccounts() {
+    this.methodCalled('getAccounts');
+    return Promise.resolve(getFakeAccountsList());
+  }
+
+  /** @override */
   dialogClose() {
     this.methodCalled('dialogClose');
   }
diff --git a/chrome/test/data/webui/settings/chromeos/input_page_test.js b/chrome/test/data/webui/settings/chromeos/input_page_test.js
index 4ddbcc0..7bae917 100644
--- a/chrome/test/data/webui/settings/chromeos/input_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/input_page_test.js
@@ -71,7 +71,8 @@
 
       // The test input methods should appear.
       const items = inputMethodsList.querySelectorAll('.list-item');
-      assertEquals(2, items.length);  // Two items for input methods
+      // Two items for input methods and one item for add input methods.
+      assertEquals(3, items.length);
       assertEquals(
           'US keyboard',
           items[0].querySelector('.display-name').textContent.trim());
@@ -116,5 +117,12 @@
       assertTrue(
           await metricsProxy.whenCalled('recordToggleShowInputOptionsOnShelf'));
     });
+
+    test('when adding input methods', async () => {
+      inputPage.$$('#addInputMethod').click();
+      Polymer.dom.flush();
+
+      await metricsProxy.whenCalled('recordAddInputMethod');
+    });
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js b/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js
index 74c48c16..2c943c6d 100644
--- a/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js
@@ -20,6 +20,7 @@
         'recordManageInputMethods',
         'recordToggleShowInputOptionsOnShelf',
         'recordToggleTranslate',
+        'recordAddInputMethod',
       ]);
     }
 
@@ -47,6 +48,11 @@
     recordToggleTranslate(value) {
       this.methodCalled('recordToggleTranslate', value);
     }
+
+    /** @override */
+    recordAddInputMethod(value) {
+      this.methodCalled('recordAddInputMethod', value);
+    }
   }
   // #cr_define_end
   return {
diff --git a/chromecast/base/metrics/cast_metrics_helper.cc b/chromecast/base/metrics/cast_metrics_helper.cc
index fb51287..54c3ae1 100644
--- a/chromecast/base/metrics/cast_metrics_helper.cc
+++ b/chromecast/base/metrics/cast_metrics_helper.cc
@@ -294,7 +294,7 @@
 base::Value CastMetricsHelper::CreateEventBase(const std::string& name) {
   base::Value cast_event(base::Value::Type::DICTIONARY);
   cast_event.SetKey("name", base::Value(name));
-  const double time = (Now() - base::TimeTicks()).InMicroseconds();
+  const double time = (Now() - base::TimeTicks()).InMicrosecondsF();
   cast_event.SetKey("time", base::Value(time));
   return cast_event;
 }
diff --git a/chromecast/graphics/accessibility/accessibility_focus_ring_controller.cc b/chromecast/graphics/accessibility/accessibility_focus_ring_controller.cc
index 8ccbee7..e465ee2f 100644
--- a/chromecast/graphics/accessibility/accessibility_focus_ring_controller.cc
+++ b/chromecast/graphics/accessibility/accessibility_focus_ring_controller.cc
@@ -435,10 +435,8 @@
       return;
     }
 
-    double fraction = delta / transition_time;
-
     // Ease-in effect.
-    fraction = pow(fraction, 0.3);
+    const double fraction = pow(delta / transition_time, 0.3);
 
     // Handle corner case where we're animating but we don't have previous
     // rings.
@@ -480,9 +478,7 @@
     opacity = 1.0 - (change_delta / (fade_in_time + fade_out_time));
 
   // Layer::SetOpacity will throw an error if we're not within 0...1.
-  opacity = base::ClampToRange(opacity, 0.0f, 1.0f);
-
-  animation_info->opacity = opacity;
+  animation_info->opacity = base::ClampToRange(opacity, 0.0f, 1.0f);
 }
 
 void AccessibilityFocusRingController::AnimateCaretRing(
diff --git a/chromeos/components/media_app_ui/media_app_ui.cc b/chromeos/components/media_app_ui/media_app_ui.cc
index 00e8781..4f246db 100644
--- a/chromeos/components/media_app_ui/media_app_ui.cc
+++ b/chromeos/components/media_app_ui/media_app_ui.cc
@@ -82,10 +82,15 @@
   auto* allowlist = WebUIAllowlist::GetOrCreate(browser_context);
   const url::Origin host_origin =
       url::Origin::Create(GURL(kChromeUIMediaAppURL));
-  allowlist->RegisterAutoGrantedPermission(
-      host_origin, ContentSettingsType::FILE_SYSTEM_READ_GUARD);
-  allowlist->RegisterAutoGrantedPermission(
-      host_origin, ContentSettingsType::FILE_SYSTEM_WRITE_GUARD);
+  allowlist->RegisterAutoGrantedPermissions(
+      host_origin, {
+                       ContentSettingsType::COOKIES,
+                       ContentSettingsType::FILE_SYSTEM_READ_GUARD,
+                       ContentSettingsType::FILE_SYSTEM_WRITE_GUARD,
+                       ContentSettingsType::IMAGES,
+                       ContentSettingsType::JAVASCRIPT,
+                       ContentSettingsType::SOUND,
+                   });
 
   content::WebUIDataSource* untrusted_source =
       CreateMediaAppUntrustedDataSource(delegate_.get());
diff --git a/chromeos/components/remote_apps/mojom/BUILD.gn b/chromeos/components/remote_apps/mojom/BUILD.gn
new file mode 100644
index 0000000..f91de8a
--- /dev/null
+++ b/chromeos/components/remote_apps/mojom/BUILD.gn
@@ -0,0 +1,10 @@
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  sources = [ "remote_apps.mojom" ]
+
+  public_deps = [
+    "//mojo/public/mojom/base",
+    "//url/mojom:url_mojom_gurl",
+  ]
+}
diff --git a/chromeos/components/remote_apps/mojom/OWNERS b/chromeos/components/remote_apps/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/chromeos/components/remote_apps/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromeos/components/remote_apps/mojom/remote_apps.mojom b/chromeos/components/remote_apps/mojom/remote_apps.mojom
new file mode 100644
index 0000000..594fffe
--- /dev/null
+++ b/chromeos/components/remote_apps/mojom/remote_apps.mojom
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module chromeos.remote_apps.mojom;
+
+import "url/mojom/url.mojom";
+
+// Interface for communication between an extension and the Remote Apps
+// Manager.
+interface RemoteApps {
+  // Adds a Remote Apps folder to the launcher. Empty folders are not shown in
+  // the launcher.
+  //
+  // Input parameters:
+  // - |name|: the name of the folder.
+  //
+  // Output parameters:
+  // - |folder_id|: the ID of the newly added folder.
+  // - |error|: A string describing the error if any.
+  AddFolder(string name) => (string? folder_id, string? error);
+
+  // Adds a Remote Apps app to the launcher.
+  //
+  // Input parameters:
+  // - |name|: the name of the app.
+  // - |folder_id|: the ID of the parent folder. An empty string indicates the
+  //                app has no parent folder.
+  // - |icon_url|: a URL pointing to an image which represents the app's icon.
+  //
+  // Output parameters:
+  // - |app_id|: the ID of the newly added app.
+  // - |error|: A string describing the error if any.
+  AddApp(string name, string folder_id, url.mojom.Url icon_url) =>
+      (string? app_id, string? error);
+};
+
+// Factory for creating an instance of RemoteApps.
+interface RemoteAppsFactory {
+  // Creates an instance of RemoteApps.
+  Create(pending_receiver<RemoteApps> remote_apps,
+         pending_remote<RemoteAppLaunchObserver> observer);
+};
+
+// A RemoteAppLaunchObserver gets notifications when a remote app is launched.
+interface RemoteAppLaunchObserver {
+  // Invoked when a remote app is launched. |app_id| is the ID of the app which
+  // was launched.
+  OnRemoteAppLaunched(string app_id);
+};
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 833b0de..36fbbf8 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -8622,6 +8622,72 @@
   EXPECT_EQ(0, personal_data_.num_times_save_upi_id_called());
 }
 
+// Tests the vote generation for the address enhancement types.
+TEST_F(AutofillManagerTest, PossibleFieldTypesForEnhancementVotes) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      features::kAutofillAddressEnhancementVotes);
+
+  std::vector<AutofillProfile> profiles = {AutofillProfile()};
+  profiles[0].SetRawInfo(ADDRESS_HOME_STREET_NAME,
+                         base::ASCIIToUTF16("StreetName"));
+  profiles[0].SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER,
+                         base::ASCIIToUTF16("HouseNumber"));
+  profiles[0].SetRawInfo(ADDRESS_HOME_PREMISE_NAME,
+                         base::ASCIIToUTF16("Premise"));
+  profiles[0].SetRawInfo(ADDRESS_HOME_SUBPREMISE,
+                         base::ASCIIToUTF16("Subpremise"));
+
+  FormData form;
+  FormFieldData field1;
+  test::CreateTestFormField("somelabel", "someid", "StreetName", "text",
+                            &field1);
+  form.fields.push_back(field1);
+  test::CreateTestFormField("somelabel", "someid", "HouseNumber", "text",
+                            &field1);
+  form.fields.push_back(field1);
+  test::CreateTestFormField("somelabel", "someid", "Premise", "text", &field1);
+  form.fields.push_back(field1);
+  test::CreateTestFormField("somelabel", "someid", "Subpremise", "text",
+                            &field1);
+  form.fields.push_back(field1);
+
+  FormStructure form_structure(form);
+
+  AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
+      profiles, {}, base::string16(), "en-us", &form_structure);
+
+  ASSERT_EQ(4U, form_structure.field_count());
+
+  EXPECT_EQ(form_structure.field(0)->possible_types(),
+            ServerFieldTypeSet({ADDRESS_HOME_STREET_NAME}));
+  EXPECT_EQ(form_structure.field(1)->possible_types(),
+            ServerFieldTypeSet({ADDRESS_HOME_HOUSE_NUMBER}));
+  EXPECT_EQ(form_structure.field(2)->possible_types(),
+            ServerFieldTypeSet({ADDRESS_HOME_PREMISE_NAME}));
+  EXPECT_EQ(form_structure.field(3)->possible_types(),
+            ServerFieldTypeSet({ADDRESS_HOME_SUBPREMISE}));
+
+  // Disable the feature and verify that no possible types are detected.
+  scoped_feature_list.Reset();
+  scoped_feature_list.InitAndDisableFeature(
+      features::kAutofillAddressEnhancementVotes);
+
+  AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
+      profiles, {}, base::string16(), "en-us", &form_structure);
+
+  ASSERT_EQ(4U, form_structure.field_count());
+
+  EXPECT_EQ(form_structure.field(0)->possible_types(),
+            ServerFieldTypeSet({UNKNOWN_TYPE}));
+  EXPECT_EQ(form_structure.field(1)->possible_types(),
+            ServerFieldTypeSet({UNKNOWN_TYPE}));
+  EXPECT_EQ(form_structure.field(2)->possible_types(),
+            ServerFieldTypeSet({UNKNOWN_TYPE}));
+  EXPECT_EQ(form_structure.field(3)->possible_types(),
+            ServerFieldTypeSet({UNKNOWN_TYPE}));
+}
+
 // AutofillManagerTest with kAutofillDisabledMixedForms feature enabled.
 class AutofillManagerTestWithMixedForms : public AutofillManagerTest {
  protected:
diff --git a/components/autofill/core/browser/data_model/address.cc b/components/autofill/core/browser/data_model/address.cc
index 3b471eb..113a69c3 100644
--- a/components/autofill/core/browser/data_model/address.cc
+++ b/components/autofill/core/browser/data_model/address.cc
@@ -30,36 +30,29 @@
 
 using structured_address::VerificationStatus;
 
-Address::Address() {}
+Address::Address() = default;
 
-Address::Address(const Address& address) {
-  *this = address;
-}
+Address::Address(const Address& address) = default;
 
-Address::~Address() {}
+Address::~Address() = default;
 
-Address& Address::operator=(const Address& address) {
-  if (this == &address)
-    return *this;
-
-  street_address_ = address.street_address_;
-  dependent_locality_ = address.dependent_locality_;
-  city_ = address.city_;
-  state_ = address.state_;
-  country_code_ = address.country_code_;
-  zip_code_ = address.zip_code_;
-  sorting_code_ = address.sorting_code_;
-  return *this;
-}
+Address& Address::operator=(const Address& address) = default;
 
 bool Address::operator==(const Address& other) const {
   if (this == &other)
     return true;
+  // Note that the structured address tokens are not evaluated for profile
+  // comparison.
   return street_address_ == other.street_address_ &&
          dependent_locality_ == other.dependent_locality_ &&
          city_ == other.city_ && state_ == other.state_ &&
          zip_code_ == other.zip_code_ && sorting_code_ == other.sorting_code_ &&
-         country_code_ == other.country_code_;
+         country_code_ == other.country_code_ &&
+         street_name_ == other.street_name_ &&
+         dependent_street_name_ == other.dependent_street_name_ &&
+         house_number_ == other.house_number_ &&
+         premise_name_ == other.premise_name_ &&
+         subpremise_ == other.subpremise_;
 }
 
 base::string16 Address::GetRawInfo(ServerFieldType type) const {
diff --git a/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
index 9d025eec9..292152d 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
@@ -188,6 +188,25 @@
   return iter_.get();
 }
 
+// Copies the address line information and structured tokens from |source| to
+// |target|.
+void CopyAddressLineInformationFromProfile(const AutofillProfile& source,
+                                           Address* target) {
+  ServerFieldTypeSet types_to_copy;
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillAddressEnhancementVotes)) {
+    types_to_copy = {
+        ADDRESS_HOME_STREET_ADDRESS,        ADDRESS_HOME_STREET_NAME,
+        ADDRESS_HOME_DEPENDENT_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER,
+        ADDRESS_HOME_PREMISE_NAME,          ADDRESS_HOME_SUBPREMISE};
+  } else {
+    types_to_copy = {ADDRESS_HOME_STREET_ADDRESS};
+  }
+
+  for (const auto& type : types_to_copy)
+    target->SetRawInfo(type, source.GetRawInfo(type));
+}
+
 }  // namespace
 
 AutofillProfileComparator::AutofillProfileComparator(
@@ -791,17 +810,17 @@
   const base::string16& address2 = p2.GetInfo(kStreetAddress, app_locale_);
   // If one of the addresses is empty then use the other.
   if (address1.empty()) {
-    address->SetInfo(kStreetAddress, address2, app_locale_);
+    CopyAddressLineInformationFromProfile(p2, address);
   } else if (address2.empty()) {
-    address->SetInfo(kStreetAddress, address1, app_locale_);
+    CopyAddressLineInformationFromProfile(p1, address);
   } else {
     // Prefer the multi-line address if one is multi-line and the other isn't.
     bool address1_multiline = ContainsNewline(address1);
     bool address2_multiline = ContainsNewline(address2);
     if (address1_multiline && !address2_multiline) {
-      address->SetInfo(kStreetAddress, address1, app_locale_);
+      CopyAddressLineInformationFromProfile(p1, address);
     } else if (address2_multiline && !address1_multiline) {
-      address->SetInfo(kStreetAddress, address2, app_locale_);
+      CopyAddressLineInformationFromProfile(p2, address);
     } else {
       // Prefer the one with more tokens if they're both single-line or both
       // multi-line addresses, making sure to apply address normalization and
@@ -812,19 +831,20 @@
       switch (result) {
         case SAME_TOKENS:
           // They have the same set of unique tokens. Let's pick the one that's
-          // longer.
-          address->SetInfo(
-              kStreetAddress,
-              (p2.use_date() > p1.use_date() ? address2 : address1),
-              app_locale_);
+          // newer.
+          if (p2.use_date() > p1.use_date()) {
+            CopyAddressLineInformationFromProfile(p2, address);
+          } else {
+            CopyAddressLineInformationFromProfile(p1, address);
+          }
           break;
         case S1_CONTAINS_S2:
           // address1 has more unique tokens than address2.
-          address->SetInfo(kStreetAddress, address1, app_locale_);
+          CopyAddressLineInformationFromProfile(p1, address);
           break;
         case S2_CONTAINS_S1:
           // address2 has more unique tokens than address1.
-          address->SetInfo(kStreetAddress, address2, app_locale_);
+          CopyAddressLineInformationFromProfile(p2, address);
           break;
         case DIFFERENT_TOKENS:
         default:
diff --git a/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc b/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
index 88cc560..02c6844 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
@@ -59,8 +59,9 @@
 
 const char kLocale[] = "en-US";
 
-class AutofillProfileComparatorTest : public testing::Test,
-                                      public testing::WithParamInterface<bool> {
+class AutofillProfileComparatorTest
+    : public testing::Test,
+      public testing::WithParamInterface<std::tuple<bool, bool>> {
  public:
   // Expose the protected methods of autofill::AutofillProfileComparator for
   // testing.
@@ -288,6 +289,29 @@
               actual.GetInfo(AutofillType(ADDRESS_HOME_ZIP), kLocale));
     EXPECT_EQ(expected.GetInfo(AutofillType(ADDRESS_HOME_COUNTRY), kLocale),
               actual.GetInfo(AutofillType(ADDRESS_HOME_COUNTRY), kLocale));
+
+    EXPECT_EQ(expected.GetInfo(AutofillType(autofill::ADDRESS_HOME_STREET_NAME),
+                               kLocale),
+              actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_STREET_NAME),
+                             kLocale));
+    EXPECT_EQ(expected.GetInfo(
+                  AutofillType(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME),
+                  kLocale),
+              actual.GetInfo(
+                  AutofillType(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME),
+                  kLocale));
+    EXPECT_EQ(expected.GetInfo(
+                  AutofillType(autofill::ADDRESS_HOME_HOUSE_NUMBER), kLocale),
+              actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_HOUSE_NUMBER),
+                             kLocale));
+    EXPECT_EQ(expected.GetInfo(
+                  AutofillType(autofill::ADDRESS_HOME_PREMISE_NAME), kLocale),
+              actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_PREMISE_NAME),
+                             kLocale));
+    EXPECT_EQ(expected.GetInfo(AutofillType(autofill::ADDRESS_HOME_SUBPREMISE),
+                               kLocale),
+              actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_SUBPREMISE),
+                             kLocale));
   }
 
   AutofillProfileComparator comparator_{kLocale};
@@ -296,17 +320,36 @@
   void SetUp() override { InitializeFeatures(); }
 
   void InitializeFeatures() {
-    structured_names_enabled_ = GetParam();
+    structured_names_enabled_ = std::get<0>(GetParam());
+    address_enhancement_votes_enabled_ = std::get<1>(GetParam());
+
+    std::vector<base::Feature> enabled_features;
+    std::vector<base::Feature> disabled_features;
+
     if (structured_names_enabled_) {
-      scoped_features_.InitAndEnableFeature(
+      enabled_features.push_back(
           autofill::features::kAutofillEnableSupportForMoreStructureInNames);
     } else {
-      scoped_features_.InitAndDisableFeature(
+      disabled_features.push_back(
           autofill::features::kAutofillEnableSupportForMoreStructureInNames);
     }
+
+    if (address_enhancement_votes_enabled_) {
+      enabled_features.push_back(
+          autofill::features::kAutofillAddressEnhancementVotes);
+    } else {
+      disabled_features.push_back(
+          autofill::features::kAutofillAddressEnhancementVotes);
+    }
+    scoped_features_.InitWithFeatures(enabled_features, disabled_features);
   }
 
   bool StructuredNames() const { return structured_names_enabled_; }
+  bool AddressEnhancementVotes() const {
+    return address_enhancement_votes_enabled_;
+  }
+
+  bool address_enhancement_votes_enabled_;
   bool structured_names_enabled_;
   base::test::ScopedFeatureList scoped_features_;
 
@@ -1167,9 +1210,33 @@
 TEST_P(AutofillProfileComparatorTest, MergeAddressesMostUniqueTokens) {
   AutofillProfile p1 = CreateProfileWithAddress(
       "1 Some Street", "Unit 3", "Carver", "CA - California", "90210", "US");
+
+  p1.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                base::UTF8ToUTF16("StreetName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                base::UTF8ToUTF16("DependentStreetName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                base::UTF8ToUTF16("HouseNumber"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                base::UTF8ToUTF16("PremiseName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                base::UTF8ToUTF16("Subpremise"));
+
   AutofillProfile p2 = CreateProfileWithAddress(
       "1 Some Other Street", "Unit 3", "Carver City", "ca", "90210-1234", "us");
 
+  p2.set_use_date(p1.use_date() + base::TimeDelta::FromMinutes(1));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                base::UTF8ToUTF16("StreetName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                base::UTF8ToUTF16("DependentStreetName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                base::UTF8ToUTF16("HouseNumber2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                base::UTF8ToUTF16("PremiseName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                base::UTF8ToUTF16("Subpremise2"));
+
   Address expected;
   expected.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("1 Some Other Street"));
   expected.SetRawInfo(ADDRESS_HOME_LINE2, UTF8ToUTF16("Unit 3"));
@@ -1178,6 +1245,78 @@
   expected.SetRawInfo(ADDRESS_HOME_ZIP, UTF8ToUTF16("90210-1234"));
   expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("US"));
 
+  // If address enhancement votes are enabled, it is expecfted that the
+  // substructure from p2 since it is a superset of p1.
+  // Otherwise the fields are expected to be empty after the merge process.
+  if (AddressEnhancementVotes()) {
+    expected.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                        base::UTF8ToUTF16("StreetName2"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                        base::UTF8ToUTF16("DependentStreetName2"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                        base::UTF8ToUTF16("HouseNumber2"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                        base::UTF8ToUTF16("PremiseName2"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                        base::UTF8ToUTF16("Subpremise2"));
+  }
+  MergeAddressesAndExpect(p1, p2, expected);
+  MergeAddressesAndExpect(p2, p1, expected);
+}
+
+TEST_P(AutofillProfileComparatorTest, MergeAddressesWithStructure) {
+  AutofillProfile p1 = CreateProfileWithAddress(
+      "6543 CH BACON", "APP 3", "MONTRÉAL", "QUÉBEC", "HHH999", "ca");
+
+  p1.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                base::UTF8ToUTF16("StreetName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                base::UTF8ToUTF16("DependentStreetName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                base::UTF8ToUTF16("HouseNumber"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                base::UTF8ToUTF16("PremiseName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                base::UTF8ToUTF16("Subpremise"));
+
+  AutofillProfile p2 = CreateProfileWithAddress(
+      "6543, Bacon Rd", "", "Montreal", "QC", "hhh 999", "CA");
+  p2.set_use_date(p1.use_date() + base::TimeDelta::FromMinutes(1));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                base::UTF8ToUTF16("StreetName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                base::UTF8ToUTF16("DependentStreetName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                base::UTF8ToUTF16("HouseNumber2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                base::UTF8ToUTF16("PremiseName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                base::UTF8ToUTF16("Subpremise2"));
+
+  Address expected;
+  expected.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("6543 CH BACON"));
+  expected.SetRawInfo(ADDRESS_HOME_LINE2, UTF8ToUTF16("APP 3"));
+  expected.SetRawInfo(ADDRESS_HOME_CITY, UTF8ToUTF16("Montreal"));
+  expected.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16("QC"));
+  expected.SetRawInfo(ADDRESS_HOME_ZIP, UTF8ToUTF16("hhh 999"));
+  expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("CA"));
+
+  // If address enhancement votes are enabled, it is expecfted that the
+  // substructure from p1 is used since it is most recent.
+  // Otherwise the fields are expected to be empty after the merge process.
+  if (AddressEnhancementVotes()) {
+    expected.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                        base::UTF8ToUTF16("StreetName"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                        base::UTF8ToUTF16("DependentStreetName"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                        base::UTF8ToUTF16("HouseNumber"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                        base::UTF8ToUTF16("PremiseName"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                        base::UTF8ToUTF16("Subpremise"));
+  }
+
   MergeAddressesAndExpect(p1, p2, expected);
   MergeAddressesAndExpect(p2, p1, expected);
 }
@@ -1185,8 +1324,31 @@
 TEST_P(AutofillProfileComparatorTest, MergeAddressesWithRewrite) {
   AutofillProfile p1 = CreateProfileWithAddress(
       "6543 CH BACON", "APP 3", "MONTRÉAL", "QUÉBEC", "HHH999", "ca");
+
+  p1.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                base::UTF8ToUTF16("StreetName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                base::UTF8ToUTF16("DependentStreetName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                base::UTF8ToUTF16("HouseNumber"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                base::UTF8ToUTF16("PremiseName"));
+  p1.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                base::UTF8ToUTF16("Subpremise"));
+
   AutofillProfile p2 = CreateProfileWithAddress(
       "6543, Bacon Rd", "", "Montreal", "QC", "hhh 999", "CA");
+  p2.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                base::UTF8ToUTF16("StreetName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                base::UTF8ToUTF16("DependentStreetName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                base::UTF8ToUTF16("HouseNumber2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                base::UTF8ToUTF16("PremiseName2"));
+  p2.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                base::UTF8ToUTF16("Subpremise2"));
+
   p2.set_use_date(p1.use_date() + base::TimeDelta::FromMinutes(1));
 
   Address expected;
@@ -1197,6 +1359,21 @@
   expected.SetRawInfo(ADDRESS_HOME_ZIP, UTF8ToUTF16("hhh 999"));
   expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("CA"));
 
+  // If address enhancement votes are enabled, it is expecfted that the
+  // substructure from p1 is used since it has more tokens.
+  if (AddressEnhancementVotes()) {
+    expected.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
+                        base::UTF8ToUTF16("StreetName"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
+                        base::UTF8ToUTF16("DependentStreetName"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
+                        base::UTF8ToUTF16("HouseNumber"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
+                        base::UTF8ToUTF16("PremiseName"));
+    expected.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
+                        base::UTF8ToUTF16("Subpremise"));
+  }
+
   MergeAddressesAndExpect(p1, p2, expected);
   MergeAddressesAndExpect(p2, p1, expected);
 }
@@ -1233,4 +1410,6 @@
 INSTANTIATE_TEST_SUITE_P(
     All,
     AutofillProfileComparatorTest,
-    testing::Bool());  // Test with and without structured names.
+    testing::Combine(testing::Bool(),
+                     testing::Bool()));  // Test with and without structured
+                                         // names and address enhancement votes.
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 85760cd..b35ae47e 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -903,6 +903,7 @@
     form->UpdateAutofillCount();
     form->RationalizeRepeatedFields(form_interactions_ukm_logger);
     form->RationalizeFieldTypePredictions();
+    form->OverrideServerPredictionsWithHeuristics();
     form->IdentifySections(false);
   }
 
@@ -1860,6 +1861,25 @@
   }
 }
 
+void FormStructure::OverrideServerPredictionsWithHeuristics() {
+  if (!base::FeatureList::IsEnabled(
+          features::kAutofillEnableSupportForMoreStructureInNames)) {
+    return;
+  }
+  for (const auto& field : fields_) {
+    // If the heuristic type is |LAST_NAME_SECOND| or |LAST_NAME_FIRST|
+    // unconditionally use this prediction.
+    switch (field->heuristic_type()) {
+      case NAME_LAST_SECOND:
+      case NAME_LAST_FIRST:
+        field->SetTypeTo(AutofillType(field->heuristic_type()));
+        break;
+      default: {
+      };
+    }
+  }
+}
+
 void FormStructure::RationalizeRepeatedFields(
     AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
   // The type of every field whose index is in
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index a0f583e..db20768 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -211,6 +211,10 @@
   // the fields that are considered composing a first complete phone number.
   void RationalizePhoneNumbersInSection(std::string section);
 
+  // Overrides server predictions with specific heuristic predictions:
+  // * NAME_LAST_SECOND heuristic predictions are unconditionally used.
+  void OverrideServerPredictionsWithHeuristics();
+
   const AutofillField* field(size_t index) const;
   AutofillField* field(size_t index);
   size_t field_count() const;
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index f5e7a3ae..de7e79d1 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -5197,6 +5197,88 @@
   EXPECT_EQ(0U, form_structure2.PossibleValues(ADDRESS_BILLING_COUNTRY).size());
 }
 
+// Test the heuristic predictions the NAME_LAST_SECOND override server
+// predictions.
+TEST_F(FormStructureTest,
+       ParseQueryResponse_HeuristicsOverrideSpanishLastNameTypes) {
+  base::test::ScopedFeatureList scoped_feature;
+  scoped_feature.InitAndEnableFeature(
+      features::kAutofillEnableSupportForMoreStructureInNames);
+
+  FormData form_data;
+  FormFieldData field;
+  form_data.url = GURL("http://foo.com");
+  field.form_control_type = "text";
+
+  // First name field.
+  field.label = ASCIIToUTF16("Nombre");
+  field.name = ASCIIToUTF16("Nombre");
+  form_data.fields.push_back(field);
+
+  // First last name field.
+  // Should be identified by local heuristics.
+  field.label = ASCIIToUTF16("Apellido Paterno");
+  field.name = ASCIIToUTF16("apellido_paterno");
+  form_data.fields.push_back(field);
+
+  // Second last name field.
+  // Should be identified by local heuristics.
+  field.label = ASCIIToUTF16("Apellido Materno");
+  field.name = ASCIIToUTF16("apellido materno");
+  form_data.fields.push_back(field);
+
+  FormStructure form(form_data);
+  form.DetermineHeuristicTypes();
+
+  // Setup the query response.
+  AutofillQueryResponseContents response;
+  std::string response_string;
+  response.add_field()->set_overall_type_prediction(NAME_FIRST);
+  // Simulate a NAME_LAST classification for the two last name fields.
+  response.add_field()->set_overall_type_prediction(NAME_LAST);
+  response.add_field()->set_overall_type_prediction(NAME_LAST);
+  ASSERT_TRUE(response.SerializeToString(&response_string));
+
+  // Parse the response and update the field type predictions.
+  std::vector<FormStructure*> forms{&form};
+  FormStructure::ParseQueryResponse(response_string, forms,
+                                    test::GetEncodedSignatures(forms), nullptr);
+  ASSERT_EQ(form.field_count(), 3U);
+
+  // Validate the heuristic and server predictions.
+  EXPECT_EQ(NAME_LAST_FIRST, form.field(1)->heuristic_type());
+  EXPECT_EQ(NAME_LAST_SECOND, form.field(2)->heuristic_type());
+  EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
+  EXPECT_EQ(NAME_LAST, form.field(2)->server_type());
+
+  // Validate that the heuristic prediction wins for the two last name fields.
+  EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
+  EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_LAST_FIRST);
+  EXPECT_EQ(form.field(2)->Type().GetStorableType(), NAME_LAST_SECOND);
+
+  // Now disable the feature and process the query again.
+  scoped_feature.Reset();
+  scoped_feature.InitAndDisableFeature(
+      features::kAutofillEnableSupportForMoreStructureInNames);
+
+  std::vector<FormStructure*> forms2{&form};
+  FormStructure::ParseQueryResponse(
+      response_string, forms2, test::GetEncodedSignatures(forms2), nullptr);
+  ASSERT_EQ(form.field_count(), 3U);
+
+  // Validate the heuristic and server predictions.
+  EXPECT_EQ(NAME_LAST_FIRST, form.field(1)->heuristic_type());
+  EXPECT_EQ(NAME_LAST_SECOND, form.field(2)->heuristic_type());
+  EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
+  EXPECT_EQ(NAME_LAST, form.field(2)->server_type());
+
+  // Validate that the heuristic prediction does not win for the two last name
+  // fields.
+  EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
+  EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_LAST);
+  EXPECT_EQ(form.field(2)->Type().GetStorableType(), NAME_LAST);
+}
+
 // Tests proper resolution heuristic, server and html field types when the
 // server returns NO_SERVER_DATA, UNKNOWN_TYPE, and a valid type.
 TEST_F(FormStructureTest, ParseQueryResponse_TooManyTypes) {
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 7d24dc6..01203468 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -42,15 +42,6 @@
 // message.
 static constexpr int kAutostartInitialProgress = 5;
 
-// Parameter that allows setting the color of the overlay.
-const char kOverlayColorParameterName[] = "OVERLAY_COLORS";
-
-// Parameter that contains the current session username. Should be synced with
-// |SESSION_USERNAME_PARAMETER| from
-// .../password_manager/PasswordChangeLauncher.java
-// TODO(b/151401974): Eliminate duplicate parameter definitions.
-const char kPasswordChangeUsernameParameterName[] = "PASSWORD_CHANGE_USERNAME";
-
 // Experiment for toggling the new progress bar.
 const char kProgressBarExperiment[] = "4400697";
 
@@ -1027,7 +1018,7 @@
     SetDetails(std::move(details));
 
   const base::Optional<std::string> overlay_color =
-      trigger_context_->GetParameter(kOverlayColorParameterName);
+      trigger_context_->GetOverlayColors();
   if (overlay_color) {
     std::unique_ptr<OverlayColors> colors = std::make_unique<OverlayColors>();
     std::vector<std::string> color_strings =
@@ -1045,7 +1036,7 @@
     SetOverlayColors(std::move(colors));
   }
   const base::Optional<std::string> password_change_username =
-      trigger_context_->GetParameter(kPasswordChangeUsernameParameterName);
+      trigger_context_->GetPasswordChangeUsername();
   if (password_change_username) {
     DCHECK(
         GetCurrentURL().is_valid());  // At least |deeplink_url_| must be set.
diff --git a/components/autofill_assistant/browser/trigger_context.cc b/components/autofill_assistant/browser/trigger_context.cc
index ae904963..83c3a03 100644
--- a/components/autofill_assistant/browser/trigger_context.cc
+++ b/components/autofill_assistant/browser/trigger_context.cc
@@ -7,6 +7,15 @@
 
 namespace autofill_assistant {
 
+// Parameter that allows setting the color of the overlay.
+const char kOverlayColorParameterName[] = "OVERLAY_COLORS";
+
+// Parameter that contains the current session username. Should be synced with
+// |SESSION_USERNAME_PARAMETER| from
+// .../password_manager/PasswordChangeLauncher.java
+// TODO(b/151401974): Eliminate duplicate parameter definitions.
+const char kPasswordChangeUsernameParameterName[] = "PASSWORD_CHANGE_USERNAME";
+
 // static
 std::unique_ptr<TriggerContext> TriggerContext::CreateEmpty() {
   return std::make_unique<TriggerContextImpl>();
@@ -28,6 +37,14 @@
 TriggerContext::TriggerContext() {}
 TriggerContext::~TriggerContext() {}
 
+base::Optional<std::string> TriggerContext::GetOverlayColors() const {
+  return GetParameter(kOverlayColorParameterName);
+}
+
+base::Optional<std::string> TriggerContext::GetPasswordChangeUsername() const {
+  return GetParameter(kPasswordChangeUsernameParameterName);
+}
+
 TriggerContextImpl::TriggerContextImpl() {}
 
 TriggerContextImpl::TriggerContextImpl(
diff --git a/components/autofill_assistant/browser/trigger_context.h b/components/autofill_assistant/browser/trigger_context.h
index 5c6695f..cb201d3 100644
--- a/components/autofill_assistant/browser/trigger_context.h
+++ b/components/autofill_assistant/browser/trigger_context.h
@@ -44,6 +44,10 @@
   virtual base::Optional<std::string> GetParameter(
       const std::string& name) const = 0;
 
+  // Getters for specific parameters.
+  base::Optional<std::string> GetOverlayColors() const;
+  base::Optional<std::string> GetPasswordChangeUsername() const;
+
   // Returns a comma-separated set of experiment ids.
   virtual std::string experiment_ids() const = 0;
 
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 0a235698..0f401cba 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -1028,6 +1028,9 @@
 
 void ClientControlledShellSurface::InitializeWindowState(
     ash::WindowState* window_state) {
+  // Set the relevant window properties for Arc apps.
+  SetArcAppType(window_state->window());
+
   // Allow the client to request bounds that do not fill the entire work area
   // when maximized, or the entire display when fullscreen.
   window_state->set_allow_set_bounds_direct(true);
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 3f02840d..1a71e2bf 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -962,7 +962,6 @@
   SetShellApplicationId(window, application_id_);
   SetShellStartupId(window, startup_id_);
   SetShellMainSurface(window, root_surface());
-  SetArcAppType(window);
 
   // Start tracking changes to window bounds and window state.
   window->AddObserver(this);
diff --git a/components/feed/core/common/user_classifier.cc b/components/feed/core/common/user_classifier.cc
index e286833..e6ec9ff9 100644
--- a/components/feed/core/common/user_classifier.cc
+++ b/components/feed/core/common/user_classifier.cc
@@ -285,7 +285,7 @@
 
   base::TimeDelta since_last_time =
       clock_->Now() - pref_service_->GetTime(GetLastTimeKey(event));
-  return since_last_time.InSecondsF() / 3600;
+  return since_last_time / base::TimeDelta::FromHours(1);
 }
 
 bool UserClassifier::HasLastTime(Event event) const {
diff --git a/components/media_message_center/media_controls_progress_view.cc b/components/media_message_center/media_controls_progress_view.cc
index ebc6769e..f180c19e 100644
--- a/components/media_message_center/media_controls_progress_view.cc
+++ b/components/media_message_center/media_controls_progress_view.cc
@@ -91,7 +91,7 @@
   base::TimeDelta current_position = media_position.GetPosition();
   base::TimeDelta duration = media_position.duration();
 
-  double progress = current_position.InSecondsF() / duration.InSecondsF();
+  double progress = current_position / duration;
   SetBarProgress(progress);
 
   // Time formatting can't yet represent durations greater than 24 hours in
diff --git a/components/ntp_snippets/user_classifier.cc b/components/ntp_snippets/user_classifier.cc
index d9f4ea23..e38e8b56 100644
--- a/components/ntp_snippets/user_classifier.cc
+++ b/components/ntp_snippets/user_classifier.cc
@@ -361,7 +361,7 @@
   base::TimeDelta since_last_time =
       clock_->Now() - DeserializeTime(pref_service_->GetInt64(
                           kLastTimeKeys[static_cast<int>(metric)]));
-  return since_last_time.InSecondsF() / 3600;
+  return since_last_time / base::TimeDelta::FromHours(1);
 }
 
 bool UserClassifier::HasLastTime(Metric metric) const {
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index 7657098..09918a0c 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -48,7 +48,8 @@
 }
 
 bool OmniboxPopupModel::Selection::IsChangeToKeyword(Selection from) const {
-  return state == KEYWORD_MODE && from.state != KEYWORD_MODE;
+  return (state == KEYWORD_MODE || state == FOCUSED_BUTTON_KEYWORD) &&
+         !(from.state == KEYWORD_MODE || from.state == FOCUSED_BUTTON_KEYWORD);
 }
 
 bool OmniboxPopupModel::Selection::IsButtonFocused() const {
diff --git a/components/omnibox/browser/shortcuts_provider.cc b/components/omnibox/browser/shortcuts_provider.cc
index 68051c1..c246dfff 100644
--- a/components/omnibox/browser/shortcuts_provider.cc
+++ b/components/omnibox/browser/shortcuts_provider.cc
@@ -386,8 +386,7 @@
   base::TimeDelta time_passed = base::Time::Now() - shortcut.last_access_time;
   // Clamp to 0 in case time jumps backwards (e.g. due to DST).
   double decay_exponent =
-      std::max(0.0, kLn2 * static_cast<double>(time_passed.InMicroseconds()) /
-                        base::Time::kMicrosecondsPerWeek);
+      std::max(0.0, kLn2 * time_passed / base::TimeDelta::FromDays(7));
 
   // We modulate the decay factor based on how many times the shortcut has been
   // used. Newly created shortcuts decay at full speed; otherwise, decaying by
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 67004b9..0a652d1c 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -243,6 +243,8 @@
     "ui/saved_passwords_presenter.h",
     "votes_uploader.cc",
     "votes_uploader.h",
+    "well_known_change_password_state.cc",
+    "well_known_change_password_state.h",
     "well_known_change_password_util.cc",
     "well_known_change_password_util.h",
   ]
@@ -631,6 +633,7 @@
     "ui/saved_passwords_presenter_unittest.cc",
     "vote_uploads_test_matchers.h",
     "votes_uploader_unittest.cc",
+    "well_known_change_password_state_unittest.cc",
     "well_known_change_password_util_unittest.cc",
   ]
   if (is_android) {
diff --git a/components/password_manager/core/browser/well_known_change_password_state.cc b/components/password_manager/core/browser/well_known_change_password_state.cc
new file mode 100644
index 0000000..4151c8a
--- /dev/null
+++ b/components/password_manager/core/browser/well_known_change_password_state.cc
@@ -0,0 +1,109 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/well_known_change_password_state.h"
+
+#include "components/password_manager/core/browser/well_known_change_password_util.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+using password_manager::WellKnownChangePasswordState;
+using password_manager::WellKnownChangePasswordStateDelegate;
+
+namespace password_manager {
+
+std::unique_ptr<network::SimpleURLLoader>
+CreateResourceRequestToWellKnownNonExistingResourceFor(const GURL& url) {
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = CreateWellKnownNonExistingResourceURL(url);
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+  resource_request->load_flags = net::LOAD_DISABLE_CACHE;
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation(
+          "well_known_path_that_should_not_exist",
+          R"(
+        semantics {
+          sender: "Password Manager"
+          description:
+            "Check whether the site supports .well-known 'special' URLs."
+            "If the website does not support the spec we navigate to the "
+            "fallback url. See also "
+"https://wicg.github.io/change-password-url/response-code-reliability.html#iana"
+          trigger:
+            "When the user clicks 'Change password' on "
+            "chrome://settings/passwords, or when they visit the "
+            "[ORIGIN]/.well-known/change-password special URL, Chrome makes "
+            "this additional request. Chrome Password manager shows a button "
+            "with the link in the password checkup for compromised passwords "
+            "view (chrome://settings/passwords/check) and in a dialog when the "
+            "user signs in using compromised credentials."
+          data:
+            "The request body is empty. No user data is included."
+          destination: WEBSITE
+        }
+        policy {
+          cookies_allowed: NO
+          setting: "This feature cannot be disabled."
+          policy_exception_justification: "Essential for navigation."
+        })");
+  return network::SimpleURLLoader::Create(std::move(resource_request),
+                                          traffic_annotation);
+}
+
+WellKnownChangePasswordState::WellKnownChangePasswordState(
+    WellKnownChangePasswordStateDelegate* delegate)
+    : delegate_(delegate) {}
+
+WellKnownChangePasswordState::~WellKnownChangePasswordState() = default;
+
+void WellKnownChangePasswordState::FetchNonExistingResource(
+    network::SharedURLLoaderFactory* url_loader_factory,
+    const GURL& url) {
+  url_loader_ = CreateResourceRequestToWellKnownNonExistingResourceFor(url);
+  // Binding the callback to |this| is safe, because the State exists until
+  // OnProcessingFinished is called which can only be called after the response
+  // arrives.
+  url_loader_->DownloadHeadersOnly(
+      url_loader_factory,
+      base::BindOnce(
+          &WellKnownChangePasswordState::FetchNonExistingResourceCallback,
+          base::Unretained(this)));
+}
+
+void WellKnownChangePasswordState::SetChangePasswordResponseCode(
+    int status_code) {
+  change_password_response_code_ = status_code;
+  ContinueProcessing();
+}
+
+void WellKnownChangePasswordState::FetchNonExistingResourceCallback(
+    scoped_refptr<net::HttpResponseHeaders> headers) {
+  non_existing_resource_response_code_ =
+      headers ? headers->response_code() : -1;
+  ContinueProcessing();
+}
+
+void WellKnownChangePasswordState::ContinueProcessing() {
+  if (!BothRequestsFinished())
+    return;
+  delegate_->OnProcessingFinished(SupportsChangePasswordUrl());
+}
+
+bool WellKnownChangePasswordState::BothRequestsFinished() const {
+  return non_existing_resource_response_code_ != 0 &&
+         change_password_response_code_ != 0;
+}
+
+bool WellKnownChangePasswordState::SupportsChangePasswordUrl() const {
+  DCHECK(BothRequestsFinished());
+  return 200 <= change_password_response_code_ &&
+         change_password_response_code_ < 300 &&
+         non_existing_resource_response_code_ == net::HTTP_NOT_FOUND;
+}
+
+}  // namespace password_manager
\ No newline at end of file
diff --git a/components/password_manager/core/browser/well_known_change_password_state.h b/components/password_manager/core/browser/well_known_change_password_state.h
new file mode 100644
index 0000000..d2cb148
--- /dev/null
+++ b/components/password_manager/core/browser/well_known_change_password_state.h
@@ -0,0 +1,70 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_WELL_KNOWN_CHANGE_PASSWORD_STATE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_WELL_KNOWN_CHANGE_PASSWORD_STATE_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+}
+
+namespace password_manager {
+
+// Creates a SimpleURLLoader for a request to the non existing resource path for
+// a given |origin|.
+// TODO(crbug.com/927473): move method to anonymous namespace when State is
+// integrated in NavigationThrottle.
+std::unique_ptr<network::SimpleURLLoader>
+CreateResourceRequestToWellKnownNonExistingResourceFor(const GURL& url);
+
+// A delegate that is notified when the processing is done and its known if
+// .well-known/change-password is supported.
+class WellKnownChangePasswordStateDelegate {
+ public:
+  virtual ~WellKnownChangePasswordStateDelegate() = default;
+  virtual void OnProcessingFinished(bool is_supported) = 0;
+};
+
+// Processes if .well-known/change-password is supported by a site.
+class WellKnownChangePasswordState {
+ public:
+  explicit WellKnownChangePasswordState(
+      password_manager::WellKnownChangePasswordStateDelegate* delegate);
+  ~WellKnownChangePasswordState();
+  // Request the status code from a path that is expected to return 404.
+  void FetchNonExistingResource(
+      network::SharedURLLoaderFactory* url_loader_factory,
+      const GURL& origin);
+  // The request to .well-known/change-password is not made by this State. To
+  // get the response code for the request the owner of the state has to call
+  // this method to tell the state.
+  void SetChangePasswordResponseCode(int status_code);
+
+ private:
+  // Callback for the request to the "not exist" path.
+  void FetchNonExistingResourceCallback(
+      scoped_refptr<net::HttpResponseHeaders> headers);
+  // Function is called when both requests are finished. Decides to continue or
+  // redirect to homepage.
+  void ContinueProcessing();
+  // Checks if both requests are finished.
+  bool BothRequestsFinished() const;
+  // Checks the status codes and returns if change password is supported.
+  bool SupportsChangePasswordUrl() const;
+
+  WellKnownChangePasswordStateDelegate* delegate_ = nullptr;
+  int non_existing_resource_response_code_ = 0;
+  int change_password_response_code_ = 0;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_WELL_KNOWN_CHANGE_PASSWORD_STATE_H_
diff --git a/components/password_manager/core/browser/well_known_change_password_state_unittest.cc b/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
new file mode 100644
index 0000000..fcb0c4e
--- /dev/null
+++ b/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/well_known_change_password_state.h"
+
+#include "base/task/post_task.h"
+#include "base/test/task_environment.h"
+#include "components/password_manager/core/browser/well_known_change_password_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+// To simulate different arrivals of the response codes, a delay for the
+// response is added.
+struct ResponseDelayParams {
+  int change_password_delay;
+  int not_exist_delay;
+};
+
+constexpr char kOrigin[] = "foo.bar";
+
+class MockWellKnownChangePasswordStateDelegate
+    : public WellKnownChangePasswordStateDelegate {
+ public:
+  MockWellKnownChangePasswordStateDelegate() = default;
+  ~MockWellKnownChangePasswordStateDelegate() override = default;
+
+  MOCK_METHOD(void, OnProcessingFinished, (bool), (override));
+};
+
+class WellKnownChangePasswordStateTest
+    : public testing::Test,
+      public testing::WithParamInterface<ResponseDelayParams> {
+ public:
+  WellKnownChangePasswordStateTest() {
+    state_.FetchNonExistingResource(test_shared_loader_factory_.get(),
+                                    GURL(kOrigin));
+  }
+  // Mocking and sending the response for the non_existing request with status
+  // code |status| after a time delay |delay|.
+  void RespondeToNonExistingRequest(net::HttpStatusCode status, int delay);
+  // Mocking and setting the response for the change_password request with
+  // status code |status| after a time delay |delay|.
+  void RespondeToChangePasswordRequest(net::HttpStatusCode status, int delay);
+
+  MockWellKnownChangePasswordStateDelegate* delegate() { return &delegate_; }
+
+  // Wait until all PostTasks are processed.
+  void FastForwardPostTasks() {
+    task_environment_.FastForwardUntilNoTasksRemain();
+  }
+
+ private:
+  base::test::SingleThreadTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  MockWellKnownChangePasswordStateDelegate delegate_;
+  WellKnownChangePasswordState state_{&delegate_};
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
+      base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+          &test_url_loader_factory_);
+};
+
+void WellKnownChangePasswordStateTest::RespondeToNonExistingRequest(
+    net::HttpStatusCode status,
+    int delay) {
+  EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](net::HttpStatusCode status,
+             network::TestURLLoaderFactory* factory) {
+            factory->SimulateResponseForPendingRequest(
+                CreateWellKnownNonExistingResourceURL(GURL(kOrigin)),
+                network::URLLoaderCompletionStatus(net::OK),
+                network::CreateURLResponseHead(status), "");
+          },
+          status, &test_url_loader_factory_),
+      base::TimeDelta::FromMilliseconds(delay));
+}
+
+void WellKnownChangePasswordStateTest::RespondeToChangePasswordRequest(
+    net::HttpStatusCode status,
+    int delay) {
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(
+          &WellKnownChangePasswordState::SetChangePasswordResponseCode,
+          base::Unretained(&state_), status),
+      base::TimeDelta::FromMilliseconds(delay));
+}
+
+TEST_P(WellKnownChangePasswordStateTest, Support_Ok) {
+  ResponseDelayParams params = GetParam();
+
+  EXPECT_CALL(*delegate(), OnProcessingFinished(true));
+
+  RespondeToChangePasswordRequest(net::HTTP_OK, params.change_password_delay);
+  RespondeToNonExistingRequest(net::HTTP_NOT_FOUND, params.not_exist_delay);
+  FastForwardPostTasks();
+}
+
+TEST_P(WellKnownChangePasswordStateTest, Support_PartialContent) {
+  ResponseDelayParams params = GetParam();
+
+  EXPECT_CALL(*delegate(), OnProcessingFinished(true));
+
+  RespondeToChangePasswordRequest(net::HTTP_PARTIAL_CONTENT,
+                                  params.change_password_delay);
+  RespondeToNonExistingRequest(net::HTTP_NOT_FOUND, params.not_exist_delay);
+  FastForwardPostTasks();
+}
+
+TEST_P(WellKnownChangePasswordStateTest, NoSupport_NotFound) {
+  ResponseDelayParams params = GetParam();
+
+  EXPECT_CALL(*delegate(), OnProcessingFinished(false));
+
+  RespondeToChangePasswordRequest(net::HTTP_NOT_FOUND,
+                                  params.change_password_delay);
+  RespondeToNonExistingRequest(net::HTTP_NOT_FOUND, params.not_exist_delay);
+  FastForwardPostTasks();
+}
+
+TEST_P(WellKnownChangePasswordStateTest, NoSupport_Ok) {
+  ResponseDelayParams params = GetParam();
+
+  EXPECT_CALL(*delegate(), OnProcessingFinished(false));
+
+  RespondeToChangePasswordRequest(net::HTTP_OK, params.change_password_delay);
+  RespondeToNonExistingRequest(net::HTTP_OK, params.not_exist_delay);
+  FastForwardPostTasks();
+}
+
+// Expect no support because the State should not handle redirects.
+TEST_P(WellKnownChangePasswordStateTest, NoSupport_Redirect) {
+  ResponseDelayParams params = GetParam();
+
+  EXPECT_CALL(*delegate(), OnProcessingFinished(false));
+
+  RespondeToChangePasswordRequest(net::HTTP_PERMANENT_REDIRECT,
+                                  params.change_password_delay);
+  RespondeToNonExistingRequest(net::HTTP_NOT_FOUND, params.not_exist_delay);
+  FastForwardPostTasks();
+}
+
+constexpr ResponseDelayParams kDelayParams[] = {{0, 1}, {1, 0}};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         WellKnownChangePasswordStateTest,
+                         ::testing::ValuesIn(kDelayParams));
+
+}  // namespace password_manager
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn
index 47fa732..269f94b8 100644
--- a/components/payments/content/BUILD.gn
+++ b/components/payments/content/BUILD.gn
@@ -157,6 +157,7 @@
   sources = [
     "android_app_communication_test_support.h",
     "android_app_communication_unittest.cc",
+    "android_payment_app_factory_unittest.cc",
     "android_payment_app_unittest.cc",
     "payment_method_manifest_table_unittest.cc",
     "service_worker_payment_app_finder_unittest.cc",
diff --git a/components/payments/content/android_payment_app_factory.cc b/components/payments/content/android_payment_app_factory.cc
index 52cc539..f0888a01 100644
--- a/components/payments/content/android_payment_app_factory.cc
+++ b/components/payments/content/android_payment_app_factory.cc
@@ -4,12 +4,28 @@
 
 #include "components/payments/content/android_payment_app_factory.h"
 
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
 #include <utility>
+#include <vector>
 
+#include "base/bind.h"
 #include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
 #include "base/supports_user_data.h"
+#include "components/payments/content/android_app_communication.h"
+#include "components/payments/content/android_payment_app.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "components/payments/core/android_app_description.h"
+#include "components/payments/core/android_app_description_tools.h"
+#include "components/payments/core/method_strings.h"
+#include "components/payments/core/native_error_strings.h"
+#include "components/payments/core/payment_request_data_util.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_document_host_user_data.h"
 #include "content/public/browser/web_contents.h"
 
 namespace payments {
@@ -34,17 +50,81 @@
   AppFinder(const AppFinder& other) = delete;
   AppFinder& operator=(const AppFinder& other) = delete;
 
-  void FindApps(base::WeakPtr<PaymentAppFactory::Delegate> delegate) {
+  void FindApps(base::WeakPtr<AndroidAppCommunication> communication,
+                base::WeakPtr<PaymentAppFactory::Delegate> delegate) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     DCHECK_EQ(nullptr, delegate_.get());
     DCHECK_NE(nullptr, delegate.get());
+    DCHECK_EQ(nullptr, communication_.get());
+    DCHECK_NE(nullptr, communication.get());
+    DCHECK(delegate->GetSpec()->details().id.has_value());
 
     delegate_ = delegate;
+    communication_ = communication;
+
+    std::string twa_package_name = delegate_->GetTwaPackageName();
+    std::set<std::string> twa_payment_method_names = {
+        methods::kGooglePlayBilling,
+    };
+    if (twa_package_name.empty() ||
+        base::STLSetIntersection<std::set<std::string>>(
+            delegate_->GetSpec()->payment_method_identifiers_set(),
+            twa_payment_method_names)
+            .empty()) {
+      OnDoneCreatingPaymentApps();
+      return;
+    }
+
+    communication_->GetAppDescriptions(
+        twa_package_name, base::BindOnce(&AppFinder::OnGetAppDescriptions,
+                                         weak_ptr_factory_.GetWeakPtr()));
+  }
+
+ private:
+  void OnGetAppDescriptions(
+      const base::Optional<std::string>& error_message,
+      std::vector<std::unique_ptr<AndroidAppDescription>> app_descriptions) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    // The browser could be shutting down.
+    if (!communication_ || !delegate_)
+      return;
+
+    if (error_message.has_value()) {
+      delegate_->OnPaymentAppCreationError(error_message.value());
+      OnDoneCreatingPaymentApps();
+      return;
+    }
+
+    std::vector<std::unique_ptr<AndroidAppDescription>> single_activity_apps;
+    for (size_t i = 0; i < app_descriptions.size(); ++i) {
+      auto app = std::move(app_descriptions[i]);
+      SplitPotentiallyMultipleActivities(std::move(app), &single_activity_apps);
+    }
+
+    for (size_t i = 0; i < single_activity_apps.size(); ++i) {
+      auto app = std::move(single_activity_apps[i]);
+
+      const std::string& default_method =
+          app->activities.front()->default_payment_method;
+      DCHECK_EQ(methods::kGooglePlayBilling, default_method);
+
+      std::set<std::string> supported_payment_methods = {default_method};
+
+      delegate_->OnPaymentAppCreated(std::make_unique<AndroidPaymentApp>(
+          base::STLSetIntersection<std::set<std::string>>(
+              delegate_->GetSpec()->payment_method_identifiers_set(),
+              supported_payment_methods),
+          data_util::FilterStringifiedMethodData(
+              delegate_->GetSpec()->stringified_method_data(),
+              supported_payment_methods),
+          delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(),
+          delegate_->GetSpec()->details().id.value(), std::move(app),
+          communication_));
+    }
 
     OnDoneCreatingPaymentApps();
   }
 
- private:
   void OnDoneCreatingPaymentApps() {
     if (delegate_)
       delegate_->OnDoneCreatingPaymentApps();
@@ -54,20 +134,25 @@
 
   base::SupportsUserData* owner_;
   base::WeakPtr<PaymentAppFactory::Delegate> delegate_;
+  base::WeakPtr<AndroidAppCommunication> communication_;
 
   base::WeakPtrFactory<AppFinder> weak_ptr_factory_{this};
 };
 
 }  // namespace
 
-AndroidPaymentAppFactory::AndroidPaymentAppFactory()
-    : PaymentAppFactory(PaymentApp::Type::NATIVE_MOBILE_APP) {}
+AndroidPaymentAppFactory::AndroidPaymentAppFactory(
+    base::WeakPtr<AndroidAppCommunication> communication)
+    : PaymentAppFactory(PaymentApp::Type::NATIVE_MOBILE_APP),
+      communication_(communication) {
+  DCHECK(communication_);
+}
 
 AndroidPaymentAppFactory::~AndroidPaymentAppFactory() = default;
 
 void AndroidPaymentAppFactory::Create(base::WeakPtr<Delegate> delegate) {
   auto app_finder = AppFinder::CreateAndSetOwnedBy(delegate->GetWebContents());
-  app_finder->FindApps(delegate);
+  app_finder->FindApps(communication_, delegate);
 }
 
 }  // namespace payments
diff --git a/components/payments/content/android_payment_app_factory.h b/components/payments/content/android_payment_app_factory.h
index 0c8e8149..09b4df5 100644
--- a/components/payments/content/android_payment_app_factory.h
+++ b/components/payments/content/android_payment_app_factory.h
@@ -5,14 +5,20 @@
 #ifndef COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_APP_FACTORY_H_
 #define COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_APP_FACTORY_H_
 
+#include "base/memory/weak_ptr.h"
 #include "components/payments/content/payment_app_factory.h"
 
 namespace payments {
 
+class AndroidAppCommunication;
+
 // Retrieves Android payment apps.
 class AndroidPaymentAppFactory : public PaymentAppFactory {
  public:
-  AndroidPaymentAppFactory();
+  // The given |communication| is used for communication with Android payment
+  // apps.
+  explicit AndroidPaymentAppFactory(
+      base::WeakPtr<AndroidAppCommunication> communication);
   ~AndroidPaymentAppFactory() override;
 
   AndroidPaymentAppFactory(const AndroidPaymentAppFactory& other) = delete;
@@ -21,6 +27,9 @@
 
   // PaymentAppFactory:
   void Create(base::WeakPtr<Delegate> delegate) override;
+
+ private:
+  base::WeakPtr<AndroidAppCommunication> communication_;
 };
 
 }  // namespace payments
diff --git a/components/payments/content/android_payment_app_factory_unittest.cc b/components/payments/content/android_payment_app_factory_unittest.cc
new file mode 100644
index 0000000..70223e18
--- /dev/null
+++ b/components/payments/content/android_payment_app_factory_unittest.cc
@@ -0,0 +1,367 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/payments/content/android_payment_app_factory.h"
+
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
+#include "components/payments/content/android_app_communication.h"
+#include "components/payments/content/android_app_communication_test_support.h"
+#include "components/payments/content/payment_app_factory.h"
+#include "components/payments/content/payment_manifest_web_data_service.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "components/payments/core/android_app_description.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_web_contents_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace payments {
+namespace {
+
+// A mock delegate for payment app factories.
+class MockPaymentAppFactoryDelegate : public PaymentAppFactory::Delegate {
+ public:
+  explicit MockPaymentAppFactoryDelegate(content::BrowserContext* context)
+      : web_contents_(web_contents_factory_.CreateWebContents(context)),
+        top_origin_("https://top-origin.test"),
+        frame_origin_("https://frame-origin.test") {
+    SetRequestedPaymentMethod("https://play.google.com/billing");
+  }
+
+  ~MockPaymentAppFactoryDelegate() override = default;
+
+  void SetRequestedPaymentMethod(const std::string& method) {
+    auto details = mojom::PaymentDetails::New();
+    details->id = "id";
+
+    std::vector<mojom::PaymentMethodDataPtr> methods;
+    methods.emplace_back(mojom::PaymentMethodData::New());
+    methods.back()->supported_method = method;
+    methods.back()->stringified_data = "{}";
+
+    spec_ = std::make_unique<PaymentRequestSpec>(
+        mojom::PaymentOptions::New(), std::move(details), std::move(methods),
+        /*observer=*/nullptr, /*app_locale=*/"en-US");
+  }
+
+  // PaymentAppFactory::Delegate implementation:
+  content::WebContents* GetWebContents() override { return web_contents_; }
+  const GURL& GetTopOrigin() override { return top_origin_; }
+  const GURL& GetFrameOrigin() override { return frame_origin_; }
+  MOCK_METHOD0(GetFrameSecurityOrigin, const url::Origin&());
+  MOCK_CONST_METHOD0(GetInitiatorRenderFrameHost, content::RenderFrameHost*());
+  MOCK_CONST_METHOD0(GetMethodData,
+                     const std::vector<mojom::PaymentMethodDataPtr>&());
+  MOCK_CONST_METHOD0(GetPaymentManifestWebDataService,
+                     scoped_refptr<PaymentManifestWebDataService>());
+  MOCK_METHOD0(MayCrawlForInstallablePaymentApps, bool());
+  MOCK_CONST_METHOD0(IsOffTheRecord, bool());
+  PaymentRequestSpec* GetSpec() const override { return spec_.get(); }
+  MOCK_CONST_METHOD0(GetTwaPackageName, std::string());
+  MOCK_METHOD0(ShowProcessingSpinner, void());
+  MOCK_METHOD0(GetBillingProfiles,
+               const std::vector<autofill::AutofillProfile*>&());
+  MOCK_METHOD0(IsRequestedAutofillDataAvailable, bool());
+  MOCK_CONST_METHOD0(GetPaymentRequestDelegate,
+                     ContentPaymentRequestDelegate*());
+  MOCK_METHOD1(OnPaymentAppCreated, void(std::unique_ptr<PaymentApp> app));
+  MOCK_METHOD1(OnPaymentAppCreationError,
+               void(const std::string& error_message));
+  MOCK_CONST_METHOD0(SkipCreatingNativePaymentApps, bool());
+  MOCK_METHOD0(OnDoneCreatingPaymentApps, void());
+
+  base::WeakPtr<PaymentAppFactory::Delegate> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ private:
+  content::TestWebContentsFactory web_contents_factory_;
+  content::WebContents* web_contents_;
+  GURL top_origin_;
+  GURL frame_origin_;
+  std::unique_ptr<PaymentRequestSpec> spec_;
+  base::WeakPtrFactory<PaymentAppFactory::Delegate> weak_ptr_factory_{this};
+};
+
+// The scaffolding for testing the Android payment app factory.
+class AndroidPaymentAppFactoryTest : public testing::Test {
+ public:
+  AndroidPaymentAppFactoryTest()
+      : support_(AndroidAppCommunicationTestSupport::Create()),
+        delegate_(support_->context()),
+        factory_(GetCommunication(support_->context())) {}
+
+  std::unique_ptr<AndroidAppCommunicationTestSupport> support_;
+  MockPaymentAppFactoryDelegate delegate_;
+  AndroidPaymentAppFactory factory_;
+
+ private:
+  // Returns the Android app communication that can be used in unit tests.
+  static base::WeakPtr<AndroidAppCommunication> GetCommunication(
+      content::BrowserContext* context) {
+    base::WeakPtr<AndroidAppCommunication> communication =
+        AndroidAppCommunication::GetForBrowserContext(context);
+    communication->SetForTesting();
+    return communication;
+  }
+};
+
+// The payment app factory should return an error if it's unable to invoke
+// Aneroid payment apps on a platform that supports such apps, e.g, when ARC is
+// disabled on Chrome OS.
+TEST_F(AndroidPaymentAppFactoryTest, FactoryReturnsErrorWithoutArc) {
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.example.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+
+  EXPECT_CALL(delegate_,
+              OnPaymentAppCreationError("Unable to invoke Android apps."))
+      .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
+  support_->ExpectNoListOfPaymentAppsQuery();
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// The payment app factory should not return any errors when there're no Android
+// payment apps available.
+TEST_F(AndroidPaymentAppFactoryTest, NoErrorsWhenNoApps) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.example.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
+  support_->ExpectQueryListOfPaymentAppsAndRespond({});
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// The |arg| is of type std::unique_ptr<PaymentApp>.
+MATCHER_P3(PaymentAppMatches, type, package, method, "") {
+  return arg->type() == type && arg->GetId() == package &&
+         base::Contains(arg->GetAppMethodNames(), method);
+}
+
+// The payment app factory should return the TWA payment app when running in TWA
+// mode.
+TEST_F(AndroidPaymentAppFactoryTest, FindTheTwaPaymentAppInTwaMode) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.twa.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(PaymentAppMatches(
+                             PaymentApp::Type::NATIVE_MOBILE_APP, "com.twa.app",
+                             "https://play.google.com/billing")))
+      .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
+
+  std::vector<std::unique_ptr<AndroidAppDescription>> apps;
+  apps.emplace_back(std::make_unique<AndroidAppDescription>());
+  apps.back()->package = "com.twa.app";
+  apps.back()->service_names.push_back("com.twa.app.Service");
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.twa.app.Activity";
+  apps.back()->activities.back()->default_payment_method =
+      "https://play.google.com/billing";
+  support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// The payment app factory should return the correct TWA payment app out of two
+// installed payment apps, when running in TWA mode.
+TEST_F(AndroidPaymentAppFactoryTest, FindTheCorrectTwaAppInTwaMode) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.correct-twa.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+
+  EXPECT_CALL(delegate_,
+              OnPaymentAppCreated(PaymentAppMatches(
+                  PaymentApp::Type::NATIVE_MOBILE_APP, "com.correct-twa.app",
+                  "https://play.google.com/billing")))
+      .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
+  EXPECT_CALL(delegate_,
+              OnPaymentAppCreated(PaymentAppMatches(
+                  PaymentApp::Type::NATIVE_MOBILE_APP, "com.different.app",
+                  "https://play.google.com/billing")))
+      .Times(0);
+
+  std::vector<std::unique_ptr<AndroidAppDescription>> apps;
+  apps.emplace_back(std::make_unique<AndroidAppDescription>());
+  apps.back()->package = "com.correct-twa.app";
+  apps.back()->service_names.push_back("com.correct-twa.app.Service");
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.correct-twa.app.Activity";
+  apps.back()->activities.back()->default_payment_method =
+      "https://play.google.com/billing";
+
+  apps.emplace_back(std::make_unique<AndroidAppDescription>());
+  apps.back()->package = "com.different.app";
+  apps.back()->service_names.push_back("com.different.app.Service");
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.different.app.Activity";
+  apps.back()->activities.back()->default_payment_method =
+      "https://play.google.com/billing";
+
+  support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// The payment app factory does not return non-TWA payment apps when running in
+// TWA mode.
+TEST_F(AndroidPaymentAppFactoryTest, IgnoreNonTwaAppsInTwaMode) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.twa.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
+
+  std::vector<std::unique_ptr<AndroidAppDescription>> apps;
+  apps.emplace_back(std::make_unique<AndroidAppDescription>());
+  apps.back()->package = "com.non-twa.app";
+  apps.back()->service_names.push_back("com.non-twa.app.Service");
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.non-twa.app.Activity";
+  apps.back()->activities.back()->default_payment_method =
+      "https://play.google.com/billing";
+  support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// The payment app factory does not return any payment apps when not running
+// inside of TWA.
+TEST_F(AndroidPaymentAppFactoryTest, DoNotLookForAppsWhenOutsideOfTwaMode) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return(""));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
+  support_->ExpectNoListOfPaymentAppsQuery();
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// The Android payment app factory works only with TWA specific payment methods.
+TEST_F(AndroidPaymentAppFactoryTest, DoNotLookForAppsForNonTwaMethod) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  // "https://example.test" is not a TWA specific payment method.
+  delegate_.SetRequestedPaymentMethod("https://example.test");
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.example.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
+  support_->ExpectNoListOfPaymentAppsQuery();
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// If the TWA supports a non-TWA-specific payment method, then it should be
+// ignored.
+TEST_F(AndroidPaymentAppFactoryTest, IgnoreNonTwaMethodInTheTwa) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.twa.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
+
+  std::vector<std::unique_ptr<AndroidAppDescription>> apps;
+  apps.emplace_back(std::make_unique<AndroidAppDescription>());
+  apps.back()->package = "com.twa.app";
+  apps.back()->service_names.push_back("com.twa.app.Service");
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.twa.app.Activity";
+  apps.back()->activities.back()->default_payment_method =
+      "https://example.test";
+  support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+// If the TWA supports both a TWA-specific and a non-TWA-specific payment
+// method, then only the TWA-specific payment method activity should be
+// returned.
+TEST_F(AndroidPaymentAppFactoryTest,
+       FindOnlyActivitiesWithTwaSpecificMethodName) {
+  // Enable invoking Android payment apps on those platforms that support it.
+  auto scoped_initialization_ = support_->CreateScopedInitialization();
+
+  EXPECT_CALL(delegate_, GetTwaPackageName())
+      .WillRepeatedly(testing::Return("com.twa.app"));
+  EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
+  EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(PaymentAppMatches(
+                             PaymentApp::Type::NATIVE_MOBILE_APP, "com.twa.app",
+                             "https://play.google.com/billing")))
+      .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
+  EXPECT_CALL(delegate_, OnPaymentAppCreated(PaymentAppMatches(
+                             PaymentApp::Type::NATIVE_MOBILE_APP, "com.twa.app",
+                             "https://example.test")))
+      .Times(0);
+
+  std::vector<std::unique_ptr<AndroidAppDescription>> apps;
+  apps.emplace_back(std::make_unique<AndroidAppDescription>());
+  apps.back()->package = "com.twa.app";
+  apps.back()->service_names.push_back("com.twa.app.Service");
+
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.twa.app.ActivityOne";
+  apps.back()->activities.back()->default_payment_method =
+      "https://play.google.com/billing";
+
+  apps.back()->activities.emplace_back(
+      std::make_unique<AndroidActivityDescription>());
+  apps.back()->activities.back()->name = "com.twa.app.ActivityTwo";
+  apps.back()->activities.back()->default_payment_method =
+      "https://example.test";
+
+  support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
+
+  factory_.Create(delegate_.GetWeakPtr());
+}
+
+}  // namespace
+}  // namespace payments
diff --git a/components/payments/content/payment_app_service.cc b/components/payments/content/payment_app_service.cc
index 94c35c9..74b89137 100644
--- a/components/payments/content/payment_app_service.cc
+++ b/components/payments/content/payment_app_service.cc
@@ -5,6 +5,7 @@
 #include "components/payments/content/payment_app_service.h"
 
 #include "base/feature_list.h"
+#include "components/payments/content/android_app_communication.h"
 #include "components/payments/content/android_payment_app_factory.h"
 #include "components/payments/content/autofill_payment_app_factory.h"
 #include "components/payments/content/payment_app.h"
@@ -15,7 +16,7 @@
 
 namespace payments {
 
-PaymentAppService::PaymentAppService() {
+PaymentAppService::PaymentAppService(content::BrowserContext* context) {
   factories_.emplace_back(std::make_unique<AutofillPaymentAppFactory>());
 
   if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) {
@@ -27,7 +28,8 @@
   // apps. (Currently it works only on Chrome OS with app store billing payment
   // methods.)
   if (PaymentsExperimentalFeatures::IsEnabled(features::kAppStoreBilling)) {
-    factories_.emplace_back(std::make_unique<AndroidPaymentAppFactory>());
+    factories_.emplace_back(std::make_unique<AndroidPaymentAppFactory>(
+        AndroidAppCommunication::GetForBrowserContext(context)));
   }
 }
 
diff --git a/components/payments/content/payment_app_service.h b/components/payments/content/payment_app_service.h
index a26ce3e..40f1c18 100644
--- a/components/payments/content/payment_app_service.h
+++ b/components/payments/content/payment_app_service.h
@@ -14,12 +14,17 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/payments/content/payment_app_factory.h"
 
+namespace content {
+class BrowserContext;
+}  // namespace content
+
 namespace payments {
 
 // Retrieves payment apps of all types.
 class PaymentAppService : public KeyedService {
  public:
-  PaymentAppService();
+  // The |context| pointer is not being saved.
+  explicit PaymentAppService(content::BrowserContext* context);
   ~PaymentAppService() override;
 
   // Returns the number of payment app factories, which is the number of times
diff --git a/components/payments/content/payment_app_service_factory.cc b/components/payments/content/payment_app_service_factory.cc
index 3fb5f94..686ac505 100644
--- a/components/payments/content/payment_app_service_factory.cc
+++ b/components/payments/content/payment_app_service_factory.cc
@@ -43,7 +43,7 @@
 
 KeyedService* PaymentAppServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return new PaymentAppService();
+  return new PaymentAppService(context);
 }
 
 content::BrowserContext* PaymentAppServiceFactory::GetBrowserContextToUse(
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc
index 6cfc72c6d..1f910a9 100644
--- a/components/payments/content/payment_request_state_unittest.cc
+++ b/components/payments/content/payment_request_state_unittest.cc
@@ -78,7 +78,7 @@
         std::move(options), std::move(details), std::move(method_data),
         /*observer=*/nullptr, "en-US");
     PaymentAppServiceFactory::SetForTesting(
-        std::make_unique<PaymentAppService>());
+        std::make_unique<PaymentAppService>(/*context=*/nullptr));
     state_ = std::make_unique<PaymentRequestState>(
         /*web_contents=*/nullptr,
         /*render_frame_host=*/nullptr, GURL("https://example.com"),
diff --git a/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc b/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc
index 262cf8ed..1027ffe 100644
--- a/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc
+++ b/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc
@@ -165,8 +165,7 @@
   double GetRelativeTime() {
     base::TimeTicks now = task_environment()->GetMockTickClock()->NowTicks();
     base::TimeDelta elapsed = now - start_;
-    double relative =
-        elapsed.InSecondsF() / policy_->GetMaxTimeoutForTesting().InSecondsF();
+    double relative = elapsed / policy_->GetMaxTimeoutForTesting();
     return relative;
   }
 
diff --git a/components/services/app_service/public/cpp/app_update_unittest.cc b/components/services/app_service/public/cpp/app_update_unittest.cc
index 2d8984bd..4b5bdb4 100644
--- a/components/services/app_service/public/cpp/app_update_unittest.cc
+++ b/components/services/app_service/public/cpp/app_update_unittest.cc
@@ -714,17 +714,15 @@
       auto scheme_condition =
           apps_util::MakeCondition(apps::mojom::ConditionType::kScheme,
                                    std::move(scheme_condition_values));
-      intent_filter->conditions.push_back(std::move(scheme_condition));
 
       std::vector<apps::mojom::ConditionValuePtr> host_condition_values;
       host_condition_values.push_back(apps_util::MakeConditionValue(
           "www.google.com", apps::mojom::PatternMatchType::kNone));
       auto host_condition = apps_util::MakeCondition(
           apps::mojom::ConditionType::kHost, std::move(host_condition_values));
-      intent_filter->conditions.push_back(std::move(host_condition));
 
-      intent_filter->conditions.push_back(scheme_condition.Clone());
-      intent_filter->conditions.push_back(host_condition.Clone());
+      intent_filter->conditions.push_back(std::move(scheme_condition));
+      intent_filter->conditions.push_back(std::move(host_condition));
 
       state->intent_filters.push_back(intent_filter.Clone());
       expect_intent_filters_.push_back(intent_filter.Clone());
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
index dbb5f85..9716fa95 100644
--- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -1996,7 +1996,7 @@
   for (int i = 0; i < 10000; ++i) {
     base::Time result = ComputeLastPollOnStart(last_poll, poll_interval, now);
     base::TimeDelta delay = result + poll_interval - now;
-    double fraction = delay.InSeconds() * 1.0 / poll_interval.InSeconds();
+    double fraction = delay / poll_interval;
     if (fraction > 0.005) {
       found_delay_greater_than_5_permille = true;
     } else {
diff --git a/components/test/data/payments/app_store_billing_tests/index.js b/components/test/data/payments/app_store_billing_tests/index.js
index 91917f0..5e7f528c 100644
--- a/components/test/data/payments/app_store_billing_tests/index.js
+++ b/components/test/data/payments/app_store_billing_tests/index.js
@@ -70,6 +70,21 @@
 }
 
 /**
+ * Check whether payments can be made.
+ * @return {string} - "true", "false", or an error message.
+ */
+async function canMakePayment() { // eslint-disable-line no-unused-vars
+  info('canMakePayment');
+  try {
+    const result = await request.canMakePayment();
+    return (result ? 'true' : 'false');
+  } catch (e) {
+    info('canMakePayment error: ' + e.toString());
+    return e.toString();
+  }
+}
+
+/**
  * Show the payment sheet.
  * @return {string} - a message indicating whether the operation is successful.
  */
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 95266be9..2bc03a5 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -1315,7 +1315,8 @@
 
   // The subscription to the notification of the changing of the render
   // process's blocked state.
-  std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
+  std::unique_ptr<
+      RenderProcessHost::BlockStateChangedCallbackList::Subscription>
       render_process_blocked_state_changed_subscription_;
 
   // The headers used for the request. The value of this comes from
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index f510f16..9667209 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -3609,7 +3609,6 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
                        CheckIsCurrentBeforeAndAfterUnload) {
   IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
-  std::string onunload_script = "window.onunload = function(){ while(1);}";
   GURL url_ab(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b)"));
   GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
@@ -3638,11 +3637,6 @@
   EXPECT_FALSE(rfh_a->IsCurrent());
   EXPECT_FALSE(rfh_b->IsCurrent());
   EXPECT_TRUE(rfh_c->IsCurrent());
-
-  // 6) Resume deletion on rfh_b and run detach on rfh_b to delete its frame.
-  EXPECT_FALSE(delete_rfh_b.deleted());
-  rfh_b->DetachForTesting();
-  EXPECT_TRUE(delete_rfh_b.deleted());
 }
 
 // Test the LifecycleState is updated correctly for the main frame during
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index e31ae09d..f659e68 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -33,6 +33,7 @@
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/browser/media/media_devices_permission_checker.h"
+#include "content/browser/permissions/permission_controller_impl.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/audio_service_listener.h"
 #include "content/browser/renderer_host/media/in_process_video_capture_provider.h"
@@ -667,6 +668,10 @@
 
   std::string tab_capture_device_id;
 
+  int audio_subscription_id = PermissionControllerImpl::kNoPendingOperation;
+
+  int video_subscription_id = PermissionControllerImpl::kNoPendingOperation;
+
  private:
   std::vector<MediaRequestState> state_;
   std::unique_ptr<MediaStreamRequest> ui_request_;
@@ -1319,7 +1324,18 @@
   for (auto request_it = requests_.begin(); request_it != requests_.end();
        ++request_it) {
     if (request_it->first == label) {
+      // Clean up permission controller subscription.
+      GetUIThreadTaskRunner({})->PostTask(
+          FROM_HERE,
+          base::BindOnce(&MediaStreamManager::
+                             UnsubscribeFromPermissionControllerOnUIThread,
+                         request_it->second->requesting_process_id,
+                         request_it->second->requesting_frame_id,
+                         request_it->second->audio_subscription_id,
+                         request_it->second->video_subscription_id));
+
       requests_.erase(request_it);
+
       return;
     }
   }
@@ -1762,6 +1778,19 @@
       NOTREACHED();
   }
 
+  // Subscribe to follow permission changes in order to close streams when the
+  // user denies mic/camera.
+  // It is safe to bind base::Unretained(this) because MediaStreamManager is
+  // owned by BrowserMainLoop.
+  GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &MediaStreamManager::SubscribeToPermissionControllerOnUIThread,
+          base::Unretained(this), label, request->requesting_process_id,
+          request->requesting_frame_id, request->requester_id,
+          request->page_request_id, audio_devices.size() > 0,
+          video_devices.size() > 0, request->salt_and_origin.origin.GetURL()));
+
   // It is safe to bind base::Unretained(this) because MediaStreamManager is
   // owned by BrowserMainLoop and so outlives the IO thread.
   GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult(
@@ -2614,4 +2643,144 @@
   }
 }
 
+// static
+PermissionControllerImpl* MediaStreamManager::GetPermissionController(
+    int requesting_process_id,
+    int requesting_frame_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  RenderFrameHost* rfh =
+      RenderFrameHost::FromID(requesting_process_id, requesting_frame_id);
+  if (!rfh)
+    return nullptr;
+
+  return PermissionControllerImpl::FromBrowserContext(rfh->GetBrowserContext());
+}
+
+void MediaStreamManager::SubscribeToPermissionControllerOnUIThread(
+    const std::string& label,
+    int requesting_process_id,
+    int requesting_frame_id,
+    int requester_id,
+    int page_request_id,
+    bool is_audio_request,
+    bool is_video_request,
+    const GURL& origin) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  PermissionControllerImpl* controller =
+      GetPermissionController(requesting_process_id, requesting_frame_id);
+  if (!controller)
+    return;
+
+  int audio_subscription_id = PermissionControllerImpl::kNoPendingOperation;
+  int video_subscription_id = PermissionControllerImpl::kNoPendingOperation;
+
+  if (is_audio_request) {
+    // It is safe to bind base::Unretained(this) because MediaStreamManager is
+    // owned by BrowserMainLoop.
+    audio_subscription_id = controller->SubscribePermissionStatusChange(
+        PermissionType::AUDIO_CAPTURE,
+        RenderFrameHost::FromID(requesting_process_id, requesting_frame_id),
+        origin,
+        base::BindRepeating(&MediaStreamManager::PermissionChangedCallback,
+                            base::Unretained(this), requesting_process_id,
+                            requesting_frame_id, requester_id,
+                            page_request_id));
+  }
+
+  if (is_video_request) {
+    // It is safe to bind base::Unretained(this) because MediaStreamManager is
+    // owned by BrowserMainLoop.
+    video_subscription_id = controller->SubscribePermissionStatusChange(
+        PermissionType::VIDEO_CAPTURE,
+        RenderFrameHost::FromID(requesting_process_id, requesting_frame_id),
+        origin,
+        base::BindRepeating(&MediaStreamManager::PermissionChangedCallback,
+                            base::Unretained(this), requesting_process_id,
+                            requesting_frame_id, requester_id,
+                            page_request_id));
+  }
+
+  // It is safe to bind base::Unretained(this) because MediaStreamManager is
+  // owned by BrowserMainLoop.
+  GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(&MediaStreamManager::SetPermissionSubscriptionIDs,
+                     base::Unretained(this), label, requesting_process_id,
+                     requesting_frame_id, audio_subscription_id,
+                     video_subscription_id));
+}
+
+void MediaStreamManager::SetPermissionSubscriptionIDs(
+    const std::string& label,
+    int requesting_process_id,
+    int requesting_frame_id,
+    int audio_subscription_id,
+    int video_subscription_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  DeviceRequest* const request = FindRequest(label);
+  if (!request) {
+    // Something happened with the request while the permission subscription was
+    // created, unsubscribe to clean up.
+    // It is safe to bind base::Unretained(this) because MediaStreamManager is
+    // owned by BrowserMainLoop.
+    GetUIThreadTaskRunner({})->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &MediaStreamManager::UnsubscribeFromPermissionControllerOnUIThread,
+            requesting_process_id, requesting_frame_id, audio_subscription_id,
+            video_subscription_id));
+
+    return;
+  }
+
+  request->audio_subscription_id = audio_subscription_id;
+  request->video_subscription_id = video_subscription_id;
+}
+
+// static
+void MediaStreamManager::UnsubscribeFromPermissionControllerOnUIThread(
+    int requesting_process_id,
+    int requesting_frame_id,
+    int audio_subscription_id,
+    int video_subscription_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  PermissionControllerImpl* controller =
+      GetPermissionController(requesting_process_id, requesting_frame_id);
+  if (!controller)
+    return;
+
+  controller->UnsubscribePermissionStatusChange(audio_subscription_id);
+  controller->UnsubscribePermissionStatusChange(video_subscription_id);
+}
+
+void MediaStreamManager::PermissionChangedCallback(
+    int requesting_process_id,
+    int requesting_frame_id,
+    int requester_id,
+    int page_request_id,
+    blink::mojom::PermissionStatus status) {
+  if (status == blink::mojom::PermissionStatus::GRANTED)
+    return;
+
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    // It is safe to bind base::Unretained(this) because MediaStreamManager is
+    // owned by BrowserMainLoop.
+    GetIOThreadTaskRunner({})->PostTask(
+        FROM_HERE,
+        base::BindOnce(&MediaStreamManager::PermissionChangedCallback,
+                       base::Unretained(this), requesting_process_id,
+                       requesting_frame_id, requester_id, page_request_id,
+                       status));
+
+    return;
+  }
+
+  CancelRequest(requesting_process_id, requesting_frame_id, requester_id,
+                page_request_id);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 4d1e4877..045e5f5 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -55,6 +55,7 @@
 #include "third_party/blink/public/common/mediastream/media_stream_controls.h"
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
+#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
 
 namespace media {
 class AudioSystem;
@@ -72,6 +73,7 @@
 class MediaStreamUIProxy;
 class VideoCaptureManager;
 class VideoCaptureProvider;
+class PermissionControllerImpl;
 
 // MediaStreamManager is used to generate and close new media devices, not to
 // start the media flow. The classes requesting new media streams are answered
@@ -534,6 +536,48 @@
   // Activate the specified tab and bring it to the front.
   void ActivateTabOnUIThread(const DesktopMediaID source);
 
+  // Get the permission controller for a particular RFH. Must be called on the
+  // UI thread.
+  static PermissionControllerImpl* GetPermissionController(
+      int requesting_process_id,
+      int requesting_frame_id);
+
+  // Subscribe to the permission controller in order to monitor camera/mic
+  // permission updates for a particular DeviceRequest. All the additional
+  // information is needed because `FindRequest` can't be called on the UI
+  // thread.
+  void SubscribeToPermissionControllerOnUIThread(const std::string& label,
+                                                 int requesting_process_id,
+                                                 int requesting_frame_id,
+                                                 int requester_id,
+                                                 int page_request_id,
+                                                 bool is_audio_request,
+                                                 bool is_video_request,
+                                                 const GURL& origin);
+
+  // Store the subscription ids on a DeviceRequest in order to allow
+  // unsubscribing when the request is deleted.
+  void SetPermissionSubscriptionIDs(const std::string& label,
+                                    int requesting_process_id,
+                                    int requesting_frame_id,
+                                    int audio_subscription_id,
+                                    int video_subscription_id);
+
+  // Unsubscribe from following permission updates for the two specified
+  // subscription IDs. Called when a request is deleted.
+  static void UnsubscribeFromPermissionControllerOnUIThread(
+      int requesting_process_id,
+      int requesting_frame_id,
+      int audio_subscription_id,
+      int video_subscription_id);
+
+  // Callback that the PermissionController calls when a permission is updated.
+  void PermissionChangedCallback(int requesting_process_id,
+                                 int requesting_frame_id,
+                                 int requester_id,
+                                 int page_request_id,
+                                 blink::mojom::PermissionStatus status);
+
   media::AudioSystem* const audio_system_;  // not owned
   scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_;
   scoped_refptr<VideoCaptureManager> video_capture_manager_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index f3aab35..b8a3489 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3763,9 +3763,9 @@
   return is_blocked_;
 }
 
-std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
+std::unique_ptr<RenderProcessHost::BlockStateChangedCallbackList::Subscription>
 RenderProcessHostImpl::RegisterBlockStateChangedCallback(
-    const base::RepeatingCallback<void(bool)>& cb) {
+    const BlockStateChangedCallback& cb) {
   return blocked_state_changed_callback_list_.Add(cb);
 }
 
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index e372136..7ee16a2 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -213,7 +213,7 @@
   bool IsBlocked() override;
   std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
   RegisterBlockStateChangedCallback(
-      const base::RepeatingCallback<void(bool)>& cb) override;
+      const BlockStateChangedCallback& cb) override;
   void Cleanup() override;
   void AddPendingView() override;
   void RemovePendingView() override;
@@ -1107,7 +1107,7 @@
   bool is_blocked_;
 
   // The clients who want to know when the blocked state has changed.
-  base::CallbackList<void(bool)> blocked_state_changed_callback_list_;
+  BlockStateChangedCallbackList blocked_state_changed_callback_list_;
 
   // Records the last time we regarded the child process active.
   base::TimeTicks child_process_activity_time_;
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index ec4696ba..69f8a41 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -1246,7 +1246,8 @@
   base::OneShotTimer input_event_ack_timeout_;
   base::TimeTicks input_event_ack_start_time_;
 
-  std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
+  std::unique_ptr<
+      RenderProcessHost::BlockStateChangedCallbackList::Subscription>
       render_process_blocked_state_changed_subscription_;
 
   std::unique_ptr<TimeoutMonitor> new_content_rendering_timeout_;
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index 1d92376..1be78a3 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -710,6 +710,7 @@
         break;
       case network::mojom::DataElementType::kRawFile:
       case network::mojom::DataElementType::kChunkedDataPipe:
+      case network::mojom::DataElementType::kReadOnceStream:
       case network::mojom::DataElementType::kUnknown:
         NOTREACHED();
         continue;
diff --git a/content/common/widget_messages.h b/content/common/widget_messages.h
index 43dd821..a542ee4 100644
--- a/content/common/widget_messages.h
+++ b/content/common/widget_messages.h
@@ -71,12 +71,6 @@
 IPC_MESSAGE_ROUTED1(WidgetMsg_SetViewportIntersection,
                     blink::ViewportIntersectionState /* intersection_state */)
 
-
-// Sent by the browser to synchronize with the next compositor frame by
-// requesting an ACK be queued. Used only for tests.
-IPC_MESSAGE_ROUTED1(WidgetMsg_WaitForNextFrameForTests,
-                    int /* main_frame_thread_observer_routing_id */)
-
 //
 // Renderer -> Browser Messages.
 //
@@ -105,7 +99,4 @@
 // Close message.
 IPC_MESSAGE_CONTROL1(WidgetHostMsg_Close_ACK, int /* old_route_id */)
 
-// Sent in reply to WidgetMsg_WaitForNextFrameForTests.
-IPC_MESSAGE_ROUTED0(WidgetHostMsg_WaitForNextFrameForTests_ACK)
-
 #endif  //  CONTENT_COMMON_WIDGET_MESSAGES_H_
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 8f613aa..cf488c3 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -284,9 +284,10 @@
   virtual void SetBlocked(bool blocked) = 0;
   virtual bool IsBlocked() = 0;
 
-  virtual std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
-  RegisterBlockStateChangedCallback(
-      const base::RepeatingCallback<void(bool)>& cb) = 0;
+  using BlockStateChangedCallbackList = base::RepeatingCallbackList<void(bool)>;
+  using BlockStateChangedCallback = BlockStateChangedCallbackList::CallbackType;
+  virtual std::unique_ptr<BlockStateChangedCallbackList::Subscription>
+  RegisterBlockStateChangedCallback(const BlockStateChangedCallback& cb) = 0;
 
   // Schedules the host for deletion and removes it from the all_hosts list.
   virtual void Cleanup() = 0;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index ac9260776..ce67fb60 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -2641,40 +2641,25 @@
 MainThreadFrameObserver::MainThreadFrameObserver(
     RenderWidgetHost* render_widget_host)
     : render_widget_host_(render_widget_host),
-      routing_id_(render_widget_host_->GetProcess()->GetNextRoutingID()) {
-  // TODO(lfg): We should look into adding a way to observe RenderWidgetHost
-  // messages similarly to what WebContentsObserver can do with RFH and RVW.
-  render_widget_host_->GetProcess()->AddRoute(routing_id_, this);
-}
+      routing_id_(render_widget_host_->GetProcess()->GetNextRoutingID()) {}
 
-MainThreadFrameObserver::~MainThreadFrameObserver() {
-  render_widget_host_->GetProcess()->RemoveRoute(routing_id_);
-}
+MainThreadFrameObserver::~MainThreadFrameObserver() = default;
 
 void MainThreadFrameObserver::Wait() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  render_widget_host_->Send(new WidgetMsg_WaitForNextFrameForTests(
-      render_widget_host_->GetRoutingID(), routing_id_));
+  static_cast<RenderWidgetHostImpl*>(render_widget_host_)
+      ->InsertVisualStateCallback(base::BindOnce(&MainThreadFrameObserver::Quit,
+                                                 base::Unretained(this)));
   base::RunLoop run_loop;
   quit_closure_ = run_loop.QuitClosure();
   run_loop.Run();
 }
 
-void MainThreadFrameObserver::Quit() {
+void MainThreadFrameObserver::Quit(bool) {
   if (quit_closure_)
     std::move(quit_closure_).Run();
 }
 
-bool MainThreadFrameObserver::OnMessageReceived(const IPC::Message& msg) {
-  if (msg.type() == WidgetHostMsg_WaitForNextFrameForTests_ACK::ID &&
-      msg.routing_id() == routing_id_) {
-    GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE,
-        base::BindOnce(&MainThreadFrameObserver::Quit, base::Unretained(this)));
-  }
-  return true;
-}
-
 InputMsgWatcher::InputMsgWatcher(RenderWidgetHost* render_widget_host,
                                  blink::WebInputEvent::Type type)
     : render_widget_host_(render_widget_host),
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index a4164d5..853008a1 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -1313,20 +1313,17 @@
 // So while the ACK can arrive before a CompositorFrame submission occurs. The
 // processing does not occur until after the FrameToken for that frame
 // submission arrives to the main thread.
-class MainThreadFrameObserver : public IPC::Listener {
+class MainThreadFrameObserver {
  public:
   explicit MainThreadFrameObserver(RenderWidgetHost* render_widget_host);
-  ~MainThreadFrameObserver() override;
+  ~MainThreadFrameObserver();
 
   // Synchronizes the browser main thread with the renderer main thread and impl
   // thread.
   void Wait();
 
-  // Overridden IPC::Listener methods.
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
  private:
-  void Quit();
+  void Quit(bool);
 
   RenderWidgetHost* render_widget_host_;
   base::OnceClosure quit_closure_;
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index d8f2b4f3..7e10cc4 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -261,9 +261,9 @@
   return false;
 }
 
-std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
+std::unique_ptr<RenderProcessHost::BlockStateChangedCallbackList::Subscription>
 MockRenderProcessHost::RegisterBlockStateChangedCallback(
-    const base::RepeatingCallback<void(bool)>& cb) {
+    const BlockStateChangedCallback& cb) {
   return nullptr;
 }
 
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 11e468e..994e712 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -112,9 +112,9 @@
   bool IsInitializedAndNotDead() override;
   void SetBlocked(bool blocked) override;
   bool IsBlocked() override;
-  std::unique_ptr<base::CallbackList<void(bool)>::Subscription>
+  std::unique_ptr<BlockStateChangedCallbackList::Subscription>
   RegisterBlockStateChangedCallback(
-      const base::RepeatingCallback<void(bool)>& cb) override;
+      const BlockStateChangedCallback& cb) override;
   void Cleanup() override;
   void AddPendingView() override;
   void RemovePendingView() override;
diff --git a/content/renderer/loader/web_url_request_util.cc b/content/renderer/loader/web_url_request_util.cc
index 3bcd58f..155d9a4b 100644
--- a/content/renderer/loader/web_url_request_util.cc
+++ b/content/renderer/loader/web_url_request_util.cc
@@ -147,6 +147,7 @@
       case network::mojom::DataElementType::kUnknown:
       case network::mojom::DataElementType::kRawFile:
       case network::mojom::DataElementType::kChunkedDataPipe:
+      case network::mojom::DataElementType::kReadOnceStream:
         NOTREACHED();
         break;
     }
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 0c637e3b..7e336ad 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -434,8 +434,6 @@
     IPC_MESSAGE_HANDLER(WidgetMsg_SetBounds_ACK, OnRequestSetBoundsAck)
     IPC_MESSAGE_HANDLER(WidgetMsg_SetViewportIntersection,
                         OnSetViewportIntersection)
-    IPC_MESSAGE_HANDLER(WidgetMsg_WaitForNextFrameForTests,
-                        OnWaitNextFrameForTests)
     IPC_MESSAGE_HANDLER(DragMsg_TargetDragEnter, OnDragTargetDragEnter)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -1523,13 +1521,6 @@
   render_frames_.RemoveObserver(frame);
 }
 
-void RenderWidget::OnWaitNextFrameForTests(
-    int main_frame_thread_observer_routing_id) {
-  // Sends an ACK to the browser process during the next compositor frame.
-  QueueMessage(std::make_unique<WidgetHostMsg_WaitForNextFrameForTests_ACK>(
-      main_frame_thread_observer_routing_id));
-}
-
 const blink::ScreenInfo& RenderWidget::GetOriginalScreenInfo() const {
   if (device_emulator_)
     return device_emulator_->original_screen_info();
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 49d12393..5e8bf6f 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -454,7 +454,6 @@
                          const gfx::PointF& screen_point,
                          blink::WebDragOperation drag_operation);
   void OnOrientationChange();
-  void OnWaitNextFrameForTests(int routing_id);
 
   // Sets the "hidden" state of this widget.  All modification of is_hidden_
   // should use this method so that we can properly inform the RenderThread of
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 778d3609..f0760bc 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -368,7 +368,7 @@
     "dependencies": ["manifest:mime_types_handler"],
     "contexts": ["blessed_extension"]
   },
-  "mojoPrivate": {
+  "mojoPrivate": [{
     "contexts": ["blessed_extension"],
     "channel": "stable",
     "extension_types": ["platform_app", "extension"],
@@ -378,7 +378,13 @@
       "B41E7F08E1179CC03CBD1F49E57CF353A40ADE07",   // Chrome Camera App Dev
       "A3E3DE9E9F16B41D4A2FAD106BD6CA76B94A0C94"    // Chrome Camera App Stable
     ]
-  },
+  }, {
+    "contexts": ["blessed_extension"],
+    "dependencies": ["behavior:imprivata_in_session_extension"],
+    "extension_types": ["extension"],
+    "location": "policy",
+    "platforms": ["chromeos"]
+  }],
   "networking.config": {
     "dependencies": ["permission:networking.config"],
     "contexts": ["blessed_extension"]
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 4c828e8..c7ca3b8 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -752,6 +752,7 @@
 
       {"keep_alive", IDR_KEEP_ALIVE_JS},
       {"mojo_bindings", IDR_MOJO_MOJO_BINDINGS_JS},
+      {"mojo_bindings_lite", IDR_MOJO_MOJO_BINDINGS_LITE_JS},
       {"extensions/common/mojom/keep_alive.mojom", IDR_KEEP_ALIVE_MOJOM_JS},
 
       // Custom bindings.
diff --git a/fuchsia/engine/browser/accessibility_bridge.cc b/fuchsia/engine/browser/accessibility_bridge.cc
index d2b9ec5..a7d4106 100644
--- a/fuchsia/engine/browser/accessibility_bridge.cc
+++ b/fuchsia/engine/browser/accessibility_bridge.cc
@@ -27,7 +27,7 @@
 }  // namespace
 
 AccessibilityBridge::AccessibilityBridge(
-    fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager,
+    fuchsia::accessibility::semantics::SemanticsManager* semantics_manager,
     fuchsia::ui::views::ViewRef view_ref,
     content::WebContents* web_contents,
     base::OnceCallback<void(zx_status_t)> on_error_callback)
diff --git a/fuchsia/engine/browser/accessibility_bridge.h b/fuchsia/engine/browser/accessibility_bridge.h
index 1528651..8165b12 100644
--- a/fuchsia/engine/browser/accessibility_bridge.h
+++ b/fuchsia/engine/browser/accessibility_bridge.h
@@ -38,9 +38,10 @@
       public fuchsia::accessibility::semantics::SemanticListener,
       public ui::AXTreeObserver {
  public:
+  // |semantics_manager| is used during construction to register the instance.
   // |web_contents| is required to exist for the duration of |this|.
   AccessibilityBridge(
-      fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager,
+      fuchsia::accessibility::semantics::SemanticsManager* semantics_manager,
       fuchsia::ui::views::ViewRef view_ref,
       content::WebContents* web_contents,
       base::OnceCallback<void(zx_status_t)> on_error_callback);
diff --git a/fuchsia/engine/browser/accessibility_bridge_browsertest.cc b/fuchsia/engine/browser/accessibility_bridge_browsertest.cc
index c26862f..5375922c 100644
--- a/fuchsia/engine/browser/accessibility_bridge_browsertest.cc
+++ b/fuchsia/engine/browser/accessibility_bridge_browsertest.cc
@@ -45,7 +45,7 @@
 
 class AccessibilityBridgeTest : public cr_fuchsia::WebEngineBrowserTest {
  public:
-  AccessibilityBridgeTest() : semantics_manager_binding_(&semantics_manager_) {
+  AccessibilityBridgeTest() {
     cr_fuchsia::WebEngineBrowserTest::set_test_server_root(
         base::FilePath(cr_fuchsia::kTestServerRoot));
   }
@@ -64,15 +64,10 @@
   }
 
   void SetUpOnMainThread() override {
-    fuchsia::accessibility::semantics::SemanticsManagerPtr
-        semantics_manager_ptr;
-    semantics_manager_binding_.Bind(semantics_manager_ptr.NewRequest());
-
     frame_ptr_ =
         cr_fuchsia::WebEngineBrowserTest::CreateFrame(&navigation_listener_);
     frame_impl_ = context_impl()->GetFrameImplForTest(&frame_ptr_);
-    frame_impl_->set_semantics_manager_for_test(
-        std::move(semantics_manager_ptr));
+    frame_impl_->set_semantics_manager_for_test(&semantics_manager_);
     frame_ptr_->EnableHeadlessRendering();
 
     semantics_manager_.WaitUntilViewRegistered();
@@ -88,8 +83,6 @@
   fuchsia::web::FramePtr frame_ptr_;
   FrameImpl* frame_impl_;
   FakeSemanticsManager semantics_manager_;
-  fidl::Binding<fuchsia::accessibility::semantics::SemanticsManager>
-      semantics_manager_binding_;
   cr_fuchsia::TestNavigationListener navigation_listener_;
   fuchsia::web::NavigationControllerPtr navigation_controller_;
 };
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
index c409ac62..258cbf2d 100644
--- a/fuchsia/engine/browser/frame_impl.cc
+++ b/fuchsia/engine/browser/frame_impl.cc
@@ -552,19 +552,20 @@
   view_ref_pair.view_ref = std::move(view_ref);
   InitWindowTreeHost(std::move(view_token), std::move(view_ref_pair));
 
-  fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager =
-      semantics_manager_for_test_
-          ? std::move(semantics_manager_for_test_)
-          : base::ComponentContextForProcess()
-                ->svc()
-                ->Connect<
-                    fuchsia::accessibility::semantics::SemanticsManager>();
+  fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager;
+  if (!semantics_manager_for_test_) {
+    semantics_manager =
+        base::ComponentContextForProcess()
+            ->svc()
+            ->Connect<fuchsia::accessibility::semantics::SemanticsManager>();
+  }
 
   // If the SemanticTree owned by |accessibility_bridge_| is disconnected, it
   // will cause |this| to be closed.
   accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
-      std::move(semantics_manager), window_tree_host_->CreateViewRef(),
-      web_contents_.get(),
+      semantics_manager_for_test_ ? semantics_manager_for_test_
+                                  : semantics_manager.get(),
+      window_tree_host_->CreateViewRef(), web_contents_.get(),
       base::BindOnce(&FrameImpl::CloseAndDestroyFrame, base::Unretained(this)));
 }
 
@@ -768,8 +769,8 @@
   gfx::Rect bounds(kHeadlessWindowSize);
   if (semantics_manager_for_test_) {
     accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
-        std::move(semantics_manager_for_test_),
-        window_tree_host_->CreateViewRef(), web_contents_.get(),
+        semantics_manager_for_test_, window_tree_host_->CreateViewRef(),
+        web_contents_.get(),
         base::BindOnce(&FrameImpl::CloseAndDestroyFrame,
                        base::Unretained(this)));
 
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
index b79fcb186..7e18f926a 100644
--- a/fuchsia/engine/browser/frame_impl.h
+++ b/fuchsia/engine/browser/frame_impl.h
@@ -79,9 +79,8 @@
     return accessibility_bridge_.get();
   }
   void set_semantics_manager_for_test(
-      fuchsia::accessibility::semantics::SemanticsManagerPtr
-          semantics_manager) {
-    semantics_manager_for_test_ = std::move(semantics_manager);
+      fuchsia::accessibility::semantics::SemanticsManager* semantics_manager) {
+    semantics_manager_for_test_ = semantics_manager;
   }
   CastStreamingSessionClient* cast_streaming_session_client_for_test() {
     return cast_streaming_session_client_.get();
@@ -246,7 +245,7 @@
   FrameLayoutManager* layout_manager_ = nullptr;
 
   std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
-  fuchsia::accessibility::semantics::SemanticsManagerPtr
+  fuchsia::accessibility::semantics::SemanticsManager*
       semantics_manager_for_test_;
 
   EventFilter event_filter_;
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc
index 449b8c0..d0e88da 100644
--- a/fuchsia/engine/browser/frame_impl_browsertest.cc
+++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -118,11 +118,47 @@
     return WebEngineBrowserTest::CreateFrame(&navigation_listener_);
   }
 
+  // Dummy SemanticsManager to satisfy tests that call CreateView().
+  FakeSemanticsManager fake_semantics_manager_;
+
   cr_fuchsia::TestNavigationListener navigation_listener_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameImplTest);
 };
 
+std::string GetDocumentVisibilityState(fuchsia::web::Frame* frame) {
+  auto visibility = base::MakeRefCounted<base::RefCountedData<std::string>>();
+  base::RunLoop loop;
+  frame->ExecuteJavaScript(
+      {"*"},
+      cr_fuchsia::MemBufferFromString("document.visibilityState;", "test"),
+      [visibility, quit_loop = loop.QuitClosure()](
+          fuchsia::web::Frame_ExecuteJavaScript_Result result) {
+        ASSERT_TRUE(result.is_response());
+        visibility->data = StringFromMemBufferOrDie(result.response().result);
+        quit_loop.Run();
+      });
+  loop.Run();
+  return visibility->data;
+}
+
+// Verifies that Frames are initially "hidden".
+IN_PROC_BROWSER_TEST_F(FrameImplTest, VisibilityState) {
+  fuchsia::web::FramePtr frame = CreateFrame();
+
+  fuchsia::web::NavigationControllerPtr controller;
+  frame->GetNavigationController(controller.NewRequest());
+
+  // Navigate to a page and wait for it to finish loading.
+  ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
+      controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+  navigation_listener_.RunUntilUrlAndTitleEquals(GURL(url::kAboutBlankURL),
+                                                 url::kAboutBlankURL);
+
+  // Query the document.visibilityState before creating a View.
+  EXPECT_EQ(GetDocumentVisibilityState(frame.get()), "\"hidden\"");
+}
+
 void VerifyCanGoBackAndForward(fuchsia::web::NavigationController* controller,
                                bool can_go_back_expected,
                                bool can_go_forward_expected) {
@@ -240,20 +276,13 @@
   EXPECT_TRUE(frame);
   FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame);
 
-  // Sets up a FakeSemanticsManager to be used when an AccessibilityBridge is
-  // created. This prevents the remote handle from being dropped, which causes
-  // the Frame to be torn down.
-  FakeSemanticsManager semantics_manager;
-  fidl::Binding<fuchsia::accessibility::semantics::SemanticsManager>
-      semantics_manager_binding(&semantics_manager);
-  fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager_ptr;
-  semantics_manager_binding.Bind(semantics_manager_ptr.NewRequest());
-  frame_impl->set_semantics_manager_for_test(std::move(semantics_manager_ptr));
+  // CreateView() will cause the AccessibilityBridge to be created.
+  frame_impl->set_semantics_manager_for_test(&fake_semantics_manager_);
 
   auto view_tokens = scenic::ViewTokenPair::New();
-
   frame->CreateView(std::move(view_tokens.view_token));
   base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(frame_impl->has_view_for_test());
 
   base::RunLoop run_loop;
   frame.set_error_handler([&run_loop](zx_status_t status) {
@@ -1481,19 +1510,12 @@
   ASSERT_TRUE(frame_impl);
   EXPECT_FALSE(frame_impl->has_view_for_test());
 
+  // CreateView() will cause the AccessibilityBridge to be created.
+  frame_impl->set_semantics_manager_for_test(&fake_semantics_manager_);
+
   fuchsia::web::NavigationControllerPtr controller;
   frame->GetNavigationController(controller.NewRequest());
 
-  // Sets up a FakeSemanticsManager to be used when an AccessibilityBridge is
-  // created. This prevents the remote handle from being dropped, which causes
-  // the Frame to be torn down.
-  FakeSemanticsManager semantics_manager;
-  fidl::Binding<fuchsia::accessibility::semantics::SemanticsManager>
-      semantics_manager_binding(&semantics_manager);
-  fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager_ptr;
-  semantics_manager_binding.Bind(semantics_manager_ptr.NewRequest());
-  frame_impl->set_semantics_manager_for_test(std::move(semantics_manager_ptr));
-
   // Verify that the Frame can navigate, prior to the View being created.
   const GURL page1_url(embedded_test_server()->GetURL(kPage1Path));
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
@@ -1501,11 +1523,8 @@
   navigation_listener_.RunUntilUrlAndTitleEquals(page1_url, kPage1Title);
 
   // Request a View from the Frame, and pump the loop to process the request.
-  zx::eventpair owner_token, frame_token;
-  ASSERT_EQ(zx::eventpair::create(0, &owner_token, &frame_token), ZX_OK);
-  fuchsia::ui::views::ViewToken view_token;
-  view_token.value = std::move(frame_token);
-  frame->CreateView(std::move(view_token));
+  auto view_tokens = scenic::ViewTokenPair::New();
+  frame->CreateView(std::move(view_tokens.view_token));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(frame_impl->has_view_for_test());
 
@@ -1515,17 +1534,9 @@
       controller.get(), fuchsia::web::LoadUrlParams(), page2_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(page2_url, kPage2Title);
 
-  // Create another FakeSemanticsManager for a second call to CreateView.
-  fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager_ptr2;
-  semantics_manager_binding.Bind(semantics_manager_ptr2.NewRequest());
-  frame_impl->set_semantics_manager_for_test(std::move(semantics_manager_ptr2));
-
   // Create new View tokens and request a new view.
-  zx::eventpair owner_token2, frame_token2;
-  ASSERT_EQ(zx::eventpair::create(0, &owner_token2, &frame_token2), ZX_OK);
-  fuchsia::ui::views::ViewToken view_token2;
-  view_token2.value = std::move(frame_token2);
-  frame->CreateView(std::move(view_token2));
+  auto view_tokens2 = scenic::ViewTokenPair::New();
+  frame->CreateView(std::move(view_tokens2.view_token));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(frame_impl->has_view_for_test());
 
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 13b700a4..8905ba3 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -17335,7 +17335,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17401,7 +17401,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17423,7 +17423,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17445,7 +17445,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17467,7 +17467,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17555,7 +17555,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17577,7 +17577,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17599,7 +17599,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17665,7 +17665,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17687,7 +17687,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17826,7 +17826,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17849,7 +17849,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17959,7 +17959,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -17981,7 +17981,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18091,7 +18091,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18157,7 +18157,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?staging\",\"server_host\":\"staging-goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18314,7 +18314,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18337,7 +18337,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18360,7 +18360,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18383,7 +18383,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18452,7 +18452,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18475,7 +18475,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18546,7 +18546,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11e146\"}"
+      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11e146\"}"
       execution_timeout_secs: 36000
       caches {
         name: "xcode_ios_11e146"
@@ -18571,7 +18571,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11e146\"}"
+      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11e146\"}"
       execution_timeout_secs: 36000
       caches {
         name: "xcode_ios_11e146"
@@ -18690,7 +18690,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18713,7 +18713,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18736,7 +18736,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18759,7 +18759,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18869,7 +18869,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -18891,7 +18891,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
+      properties: "{\"$build/goma\":{\"jobs\":80,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.goma.fyi\",\"recipe\":\"chromium\"}"
       execution_timeout_secs: 36000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/infra/config/subprojects/goma/goma.star b/infra/config/subprojects/goma/goma.star
index 58feba0..6e7df0a1b 100644
--- a/infra/config/subprojects/goma/goma.star
+++ b/infra/config/subprojects/goma/goma.star
@@ -155,6 +155,7 @@
         goma_backend = goma_backend,
         mastername = "chromium.goma.fyi",
         os = os,
+        goma_use_luci_auth = True,
         **kwargs
     )
 
@@ -315,6 +316,7 @@
         goma_backend = goma_backend,
         mastername = "chromium.goma.fyi",
         os = os,
+        goma_use_luci_auth = True,
         **kwargs
     )
 
@@ -383,12 +385,19 @@
     os = os.MAC_DEFAULT,
 )
 
-def goma_builder(*, name, builderless = False, os = os.LINUX_DEFAULT, **kwargs):
+def goma_builder(
+        *,
+        name,
+        builderless = False,
+        os = os.LINUX_DEFAULT,
+        goma_use_luci_auth = True,
+        **kwargs):
     return builder(
         name = name,
         builderless = builderless,
         mastername = "chromium.goma",
         os = os,
+        goma_use_luci_auth = goma_use_luci_auth,
         **kwargs
     )
 
@@ -401,14 +410,12 @@
     name = "Chromium Android ARM 32-bit Goma RBE ToT",
     goma_backend = goma.backend.RBE_TOT,
     goma_enable_ats = False,
-    goma_use_luci_auth = True,
 )
 
 goma_builder(
     name = "Chromium Android ARM 32-bit Goma RBE ToT (ATS)",
     goma_backend = goma.backend.RBE_TOT,
     goma_enable_ats = True,
-    goma_use_luci_auth = True,
 )
 
 goma_builder(
@@ -433,28 +440,33 @@
 
 goma_builder(
     name = "Chromium Linux Goma Staging",
+    goma_use_luci_auth = False,
 )
 
 goma_builder(
     name = "Chromium Linux Goma RBE ToT",
     goma_backend = goma.backend.RBE_TOT,
     goma_enable_ats = False,
-    goma_use_luci_auth = True,
 )
 
 goma_builder(
     name = "Chromium Linux Goma RBE ToT (ATS)",
     goma_backend = goma.backend.RBE_TOT,
     goma_enable_ats = True,
-    goma_use_luci_auth = True,
 )
 
-def goma_mac_builder(*, name, os = os.MAC_DEFAULT, **kwargs):
+def goma_mac_builder(
+        *,
+        name,
+        os = os.MAC_DEFAULT,
+        goma_use_luci_auth = True,
+        **kwargs):
     return goma_builder(
         name = name,
         cores = 4,
         goma_jobs = goma.jobs.J80,
         os = os,
+        goma_use_luci_auth = goma_use_luci_auth,
         **kwargs
     )
 
@@ -462,7 +474,6 @@
     name = "Chromium iOS Goma RBE ToT",
     caches = [xcode_cache.x11e146],
     goma_backend = goma.backend.RBE_TOT,
-    goma_use_luci_auth = True,
     os = os.MAC_10_14,
     properties = {
         "xcode_build_version": "11e146",
@@ -487,18 +498,25 @@
 goma_mac_builder(
     name = "Chromium Mac Goma RBE ToT",
     goma_backend = goma.backend.RBE_TOT,
-    goma_use_luci_auth = True,
 )
 
 goma_mac_builder(
     name = "Chromium Mac Goma Staging",
+    goma_use_luci_auth = False,
 )
 
-def goma_windows_builder(*, name, goma_enable_ats = True, cores = 32, **kwargs):
+def goma_windows_builder(
+        *,
+        name,
+        goma_enable_ats = True,
+        goma_use_luci_auth = True,
+        cores = 32,
+        **kwargs):
     return goma_builder(
         name = name,
         cores = cores,
         goma_enable_ats = goma_enable_ats,
+        goma_use_luci_auth = goma_use_luci_auth,
         os = os.WINDOWS_DEFAULT,
         **kwargs
     )
@@ -516,11 +534,11 @@
 goma_windows_builder(
     name = "Chromium Win Goma RBE ToT",
     goma_backend = goma.backend.RBE_TOT,
-    goma_use_luci_auth = True,
 )
 
 goma_windows_builder(
     name = "CrWinGomaStaging",
     cores = 8,
     goma_enable_ats = False,
+    goma_use_luci_auth = False,
 )
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index c17988f..37e15e36 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -51,7 +51,6 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/base/sync_base_switches.h"
 #include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/engine/sync_engine_switches.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/ukm/ios/features.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_features.h"
@@ -450,10 +449,6 @@
      flag_descriptions::kAutofillPruneSuggestionsName,
      flag_descriptions::kAutofillPruneSuggestionsDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillPruneSuggestions)},
-    {"enable-sync-trusted-vault",
-     flag_descriptions::kEnableSyncTrustedVaultName,
-     flag_descriptions::kEnableSyncTrustedVaultDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(switches::kSyncSupportTrustedVaultPassphrase)},
     {"collections-card-presentation-style",
      flag_descriptions::kCollectionsCardPresentationStyleName,
      flag_descriptions::kCollectionsCardPresentationStyleDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index dc867c02..ac18e50 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -259,11 +259,6 @@
 const char kEnablePersistentDownloadsDescription[] =
     "Enables the new, experimental implementation of persistent downloads";
 
-const char kEnableSyncTrustedVaultName[] =
-    "Enable trusted vault sync passphrase type";
-const char kEnableSyncTrustedVaultDescription[] =
-    "Enables the new, experimental passphrase type for sync data";
-
 const char kExpandedTabStripName[] = "Enable expanded tabstrip";
 const char kExpandedTabStripDescription[] =
     "Enables the new expanded tabstrip. Activated by swiping down the tabstrip"
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 1d1b418..e4bab0b 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -218,9 +218,6 @@
 extern const char kEnablePersistentDownloadsName[];
 extern const char kEnablePersistentDownloadsDescription[];
 
-extern const char kEnableSyncTrustedVaultName[];
-extern const char kEnableSyncTrustedVaultDescription[];
-
 // Title and description for the flag to enable an expanded tab strip.
 extern const char kExpandedTabStripName[];
 extern const char kExpandedTabStripDescription[];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm
index 662878e0..f64db3f 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm
@@ -238,7 +238,15 @@
 
 // Tests that the Address View Controller is dismissed when tapping the outside
 // the popover on iPad.
-- (void)testIPadTappingOutsidePopOverDismissAddressController {
+// TODO(crbug.com/1116887) Flaky on iOS simulator
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_testIPadTappingOutsidePopOverDismissAddressController \
+  DISABLED_testIPadTappingOutsidePopOverDismissAddressController
+#else
+#define MAYBE_testIPadTappingOutsidePopOverDismissAddressController \
+  testIPadTappingOutsidePopOverDismissAddressController
+#endif
+- (void)MAYBE_testIPadTappingOutsidePopOverDismissAddressController {
   if (![ChromeEarlGrey isIPadIdiom]) {
     EARL_GREY_TEST_SKIPPED(@"Test is not applicable for iPhone");
   }
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm b/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm
index ac9f9d41..29eb66c 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/settings/cells/settings_check_cell.h"
 
 #include "base/check.h"
+#include "base/ios/ios_util.h"
 #include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
@@ -101,7 +102,15 @@
     _trailingImageView.hidden = YES;
     [contentView addSubview:_trailingImageView];
     // |activityIndictor| attributes.
-    _activityIndicator = [[UIActivityIndicatorView alloc] init];
+    if (base::ios::IsRunningOnIOS13OrLater()) {
+      // Creates default activity indicator. Color depends on appearance.
+      _activityIndicator = [[UIActivityIndicatorView alloc] init];
+    } else {
+      // For iOS 12 and lower the color should be always gray otherwise
+      // indicator is not visible.
+      _activityIndicator = [[UIActivityIndicatorView alloc]
+          initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
+    }
     _activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
     _activityIndicator.hidden = YES;
     [contentView addSubview:_activityIndicator];
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_item.mm b/ios/chrome/browser/ui/settings/cells/settings_check_item.mm
index 5d5cb07..b18c4340 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_item.mm
@@ -29,7 +29,6 @@
   [super configureCell:cell withStyler:styler];
   cell.textLabel.text = self.text;
   cell.detailTextLabel.text = self.detailText;
-  cell.selectionStyle = UITableViewCellSelectionStyleNone;
   if (self.enabled) {
     [cell setInfoButtonHidden:self.infoButtonHidden];
     [cell setLeadingImage:self.leadingImage
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
index 8c50090..73753ab 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -266,8 +266,6 @@
 
   cell.selectionStyle = UITableViewCellSelectionStyleNone;
 
-  // TODO:(crbug.com/1075494) - Add action to Show/Hide password when user tap
-  // eye icon.
   NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
   switch (itemType) {
     case ItemTypePassword: {
@@ -280,9 +278,11 @@
           forControlEvents:UIControlEventTouchUpInside];
       return textFieldCell;
     }
+    case ItemTypeChangePasswordButton:
+      cell.selectionStyle = UITableViewCellSelectionStyleDefault;
+      break;
     case ItemTypeWebsite:
     case ItemTypeUsername:
-    case ItemTypeChangePasswordButton:
     case ItemTypeChangePasswordRecommendation:
       break;
   }
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
index 0c2a5a6..6a84b78 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -1382,8 +1382,17 @@
 
 - (BOOL)tableView:(UITableView*)tableView
     shouldHighlightRowAtIndexPath:(NSIndexPath*)indexPath {
-  return [self.tableViewModel sectionIdentifierForSection:indexPath.section] !=
-         SectionIdentifierSavePasswordsSwitch;
+  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
+  switch (itemType) {
+    case ItemTypeSavePasswordsSwitch:
+      return NO;
+    case ItemTypePasswordCheckStatus:
+      return self.passwordCheckState == PasswordCheckStateUnSafe;
+    case ItemTypeCheckForProblemsButton:
+      return self.passwordCheckState != PasswordCheckStateRunning &&
+             self.passwordCheckState != PasswordCheckStateDisabled;
+  }
+  return YES;
 }
 
 - (UIView*)tableView:(UITableView*)tableView
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc
index 4818406..06e29d46 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.cc
+++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -97,19 +97,6 @@
   ClearDecodeTaskQueue(DecodeStatus::ABORTED);
 
   weak_this_factory_.InvalidateWeakPtrs();
-
-  // Destroy explicitly to DCHECK() that |vaapi_wrapper_| references are held
-  // inside the accelerator in |decoder_|, by the |allocated_va_surfaces_| and
-  // of course by this class. To clear |allocated_va_surfaces_| we have to first
-  // DestroyContext().
-  decoder_ = nullptr;
-  if (vaapi_wrapper_) {
-    vaapi_wrapper_->DestroyContext();
-    allocated_va_surfaces_.clear();
-
-    DCHECK(vaapi_wrapper_->HasOneRef());
-    vaapi_wrapper_ = nullptr;
-  }
 }
 
 void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
@@ -137,9 +124,6 @@
     DVLOGF(3) << "Reinitializing decoder";
 
     decoder_ = nullptr;
-    // To clear |allocated_va_surfaces_| we have to first DestroyContext().
-    vaapi_wrapper_->DestroyContext();
-    allocated_va_surfaces_.clear();
     vaapi_wrapper_ = nullptr;
     decoder_delegate_ = nullptr;
     SetState(State::kUninitialized);
@@ -316,29 +300,22 @@
     return nullptr;
   }
 
-  DCHECK(frame->GetGpuMemoryBuffer());
-  const gfx::GpuMemoryBufferId frame_id = frame->GetGpuMemoryBuffer()->GetId();
-  scoped_refptr<VASurface> va_surface;
+  scoped_refptr<gfx::NativePixmap> pixmap =
+      CreateNativePixmapDmaBuf(frame.get());
+  if (!pixmap) {
+    LOG(ERROR) << "Failed to create NativePixmap from VideoFrame";
+    SetState(State::kError);
+    return nullptr;
+  }
 
-  if (!base::Contains(allocated_va_surfaces_, frame_id)) {
-    scoped_refptr<gfx::NativePixmap> pixmap =
-        CreateNativePixmapDmaBuf(frame.get());
-    if (!pixmap) {
-      LOG(ERROR) << "Failed to create NativePixmap from VideoFrame";
-      SetState(State::kError);
-      return nullptr;
-    }
+  // Create VASurface from the native pixmap.
+  scoped_refptr<VASurface> va_surface =
+      vaapi_wrapper_->CreateVASurfaceForPixmap(std::move(pixmap));
 
-    va_surface = vaapi_wrapper_->CreateVASurfaceForPixmap(std::move(pixmap));
-    if (!va_surface || va_surface->id() == VA_INVALID_ID) {
-      LOG(ERROR) << "Failed to create VASurface from VideoFrame";
-      SetState(State::kError);
-      return nullptr;
-    }
-
-    allocated_va_surfaces_[frame_id] = va_surface;
-  } else {
-    va_surface = allocated_va_surfaces_[frame_id];
+  if (!va_surface || va_surface->id() == VA_INVALID_ID) {
+    LOG(ERROR) << "Failed to create VASurface from VideoFrame";
+    SetState(State::kError);
+    return nullptr;
   }
 
   // Store the mapping between surface and video frame, so we know which video
@@ -350,12 +327,14 @@
   output_frames_[surface_id] = frame;
 
   // When the decoder is done using the frame for output or reference, it will
-  // drop its reference to the surface. We can then safely remove the associated
-  // video frame from |output_frames_|. To be notified when this happens we wrap
-  // the surface in another surface with ReleaseVideoFrame() as destruction
-  // observer.
-  VASurface::ReleaseCB release_frame_cb =
-      base::BindOnce(&VaapiVideoDecoder::ReleaseVideoFrame, weak_this_);
+  // drop its reference to the surface. We can then safely destroy the surface
+  // and remove the associated video frame from |output_frames_|. To be notified
+  // when this happens we wrap the surface in another surface that calls
+  // ReleaseFrame() on destruction. The |va_surface| object is bound to the
+  // destruction callback to keep it alive, since the associated VAAPI surface
+  // will be automatically destroyed when we drop the reference.
+  VASurface::ReleaseCB release_frame_cb = base::BindOnce(
+      &VaapiVideoDecoder::ReleaseFrame, weak_this_, std::move(va_surface));
 
   return new VASurface(surface_id, frame->layout().coded_size(),
                        GetVaFormatForVideoCodecProfile(profile_),
@@ -437,11 +416,7 @@
   }
 
   // All pending decode operations will be completed before triggering a
-  // resolution change, so we can safely DestroyContext() here; that, in turn,
-  // allows for clearing the |allocated_va_surfaces_|.
-  vaapi_wrapper_->DestroyContext();
-  allocated_va_surfaces_.clear();
-
+  // resolution change, so we can safely destroy the context here.
   if (profile_ != decoder_->GetProfile()) {
     // When a profile is changed, we need to re-initialize VaapiWrapper.
     profile_ = decoder_->GetProfile();
@@ -454,6 +429,8 @@
     }
     decoder_delegate_->set_vaapi_wrapper(new_vaapi_wrapper.get());
     vaapi_wrapper_ = std::move(new_vaapi_wrapper);
+  } else {
+    vaapi_wrapper_->DestroyContext();
   }
 
   vaapi_wrapper_->CreateContext(pic_size);
@@ -470,7 +447,9 @@
   }
 }
 
-void VaapiVideoDecoder::ReleaseVideoFrame(VASurfaceID surface_id) {
+void VaapiVideoDecoder::ReleaseFrame(scoped_refptr<VASurface> va_surface,
+                                     VASurfaceID surface_id) {
+  DCHECK_EQ(va_surface->id(), surface_id);
   DVLOGF(4);
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h
index bece6d3ec..9390bdc 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.h
+++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -15,7 +15,6 @@
 
 #include "base/containers/mru_cache.h"
 #include "base/containers/queue.h"
-#include "base/containers/small_map.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
@@ -30,7 +29,6 @@
 #include "media/video/supported_video_decoder_config.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
 
 namespace media {
 
@@ -105,11 +103,13 @@
   void ClearDecodeTaskQueue(DecodeStatus status);
 
   // Releases the local reference to the VideoFrame associated with the
-  // specified |surface_id|. This is called when |decoder_| has outputted the
-  // VideoFrame and stopped using it as a reference frame. Note that this
-  // doesn't mean the frame can be reused immediately, as it might still be used
-  // by the client.
-  void ReleaseVideoFrame(VASurfaceID surface_id);
+  // specified |surface_id| on the decoder thread. This is called when the last
+  // reference to the associated VASurface has been released, which happens when
+  // |decoder_| outputted the video frame, or stopped using it as a reference
+  // frame. Note that this doesn't mean the frame can be reused immediately, as
+  // it might still be used by the client.
+  void ReleaseFrame(scoped_refptr<VASurface> va_surface,
+                    VASurfaceID surface_id);
   // Callback for |frame_pool_| to notify of available resources.
   void NotifyFrameAvailable();
 
@@ -159,15 +159,6 @@
   // The list of frames currently used as output buffers or reference frames.
   std::map<VASurfaceID, scoped_refptr<VideoFrame>> output_frames_;
 
-  // VASurfaces are created via importing |frame_pool_| resources into libva in
-  // CreateSurface(). The following map keeps those VASurfaces for reuse
-  // according to the expectations of libva vaDestroySurfaces(): "Surfaces can
-  // only be destroyed after all contexts using these surfaces have been
-  // destroyed."
-  // TODO(crbug.com/1040291): remove this keep-alive when using SharedImages.
-  base::small_map<std::map<gfx::GpuMemoryBufferId, scoped_refptr<VASurface>>>
-      allocated_va_surfaces_;
-
   // Platform and codec specific video decoder.
   std::unique_ptr<AcceleratedVideoDecoder> decoder_;
   scoped_refptr<VaapiWrapper> vaapi_wrapper_;
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index 7358258..0f1842f4 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -13,6 +13,7 @@
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/load_flags.h"
+#include "net/http/http_util.h"
 #include "services/network/cors/cors_url_loader.h"
 #include "services/network/cors/preflight_controller.h"
 #include "services/network/crash_keys.h"
@@ -461,6 +462,13 @@
     return false;
   }
 
+  if (!net::HttpUtil::IsToken(request.method)) {
+    // Callers are expected to ensure that |method| follows RFC 7230.
+    mojo::ReportBadMessage(
+        "CorsURLLoaderFactory: invalid characters in method");
+    return false;
+  }
+
   // TODO(yhirano): If the request mode is "no-cors", the redirect mode should
   // be "follow".
   return true;
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index 766cb2c8..effc524 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -466,6 +466,28 @@
   DISALLOW_COPY_AND_ASSIGN(BadMessageTestHelper);
 };
 
+TEST_F(CorsURLLoaderTest, NoCorsWithInvalidMethod) {
+  ResourceRequest request;
+  request.mode = mojom::RequestMode::kNoCors;
+  request.credentials_mode = mojom::CredentialsMode::kInclude;
+  request.url = GURL("http://example.com/");
+  request.request_initiator = base::nullopt;
+  request.method = "GET\r\nHost: other.example.com";
+
+  BadMessageTestHelper bad_message_helper;
+  CreateLoaderAndStart(request);
+  RunUntilComplete();
+
+  EXPECT_FALSE(IsNetworkLoaderStarted());
+  EXPECT_FALSE(client().has_received_redirect());
+  EXPECT_FALSE(client().has_received_response());
+  EXPECT_TRUE(client().has_received_completion());
+  EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
+  EXPECT_THAT(bad_message_helper.bad_message_reports(),
+              ::testing::ElementsAre(
+                  "CorsURLLoaderFactory: invalid characters in method"));
+}
+
 TEST_F(CorsURLLoaderTest, SameOriginWithoutInitiator) {
   ResourceRequest request;
   request.mode = mojom::RequestMode::kSameOrigin;
diff --git a/services/network/public/cpp/data_element.cc b/services/network/public/cpp/data_element.cc
index 9a95984..4a09cb87 100644
--- a/services/network/public/cpp/data_element.cc
+++ b/services/network/public/cpp/data_element.cc
@@ -77,6 +77,13 @@
   chunked_data_pipe_getter_ = std::move(chunked_data_pipe_getter);
 }
 
+void DataElement::SetToReadOnceStream(
+    mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
+        chunked_data_pipe_getter) {
+  type_ = mojom::DataElementType::kReadOnceStream;
+  chunked_data_pipe_getter_ = std::move(chunked_data_pipe_getter);
+}
+
 base::File DataElement::ReleaseFile() {
   return std::move(file_);
 }
@@ -103,7 +110,9 @@
 
 mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
 DataElement::ReleaseChunkedDataPipeGetter() {
-  DCHECK_EQ(mojom::DataElementType::kChunkedDataPipe, type_);
+  DCHECK(type_ == mojom::DataElementType::kChunkedDataPipe ||
+         type_ == mojom::DataElementType::kReadOnceStream)
+      << type_;
   return std::move(chunked_data_pipe_getter_);
 }
 
@@ -138,6 +147,9 @@
     case mojom::DataElementType::kChunkedDataPipe:
       *os << "TYPE_CHUNKED_DATA_PIPE";
       break;
+    case mojom::DataElementType::kReadOnceStream:
+      *os << "TYPE_READ_ONCE_STREAM";
+      break;
     case mojom::DataElementType::kUnknown:
       *os << "TYPE_UNKNOWN";
       break;
@@ -164,6 +176,8 @@
       return false;
     case mojom::DataElementType::kChunkedDataPipe:
       return false;
+    case mojom::DataElementType::kReadOnceStream:
+      return false;
     case mojom::DataElementType::kUnknown:
       NOTREACHED();
       return false;
diff --git a/services/network/public/cpp/data_element.h b/services/network/public/cpp/data_element.h
index 26d0f4fc..ed2eed4a 100644
--- a/services/network/public/cpp/data_element.h
+++ b/services/network/public/cpp/data_element.h
@@ -169,6 +169,10 @@
   // server known to support chunked uploads.
   void SetToChunkedDataPipe(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
                                 chunked_data_pipe_getter);
+  // Almost same as above except |chunked_data_pipe_getter| is read only once
+  // and you must talk with a server supporting chunked upload.
+  void SetToReadOnceStream(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
+                               chunked_data_pipe_getter);
 
   // Takes ownership of the File, if this is of TYPE_RAW_FILE. The file is open
   // for reading (asynchronous reading on Windows).
diff --git a/services/network/public/cpp/network_ipc_param_traits.cc b/services/network/public/cpp/network_ipc_param_traits.cc
index ad07a680..e0f982d4 100644
--- a/services/network/public/cpp/network_ipc_param_traits.cc
+++ b/services/network/public/cpp/network_ipc_param_traits.cc
@@ -57,6 +57,7 @@
                         .release());
       break;
     }
+    case network::mojom::DataElementType::kReadOnceStream:
     case network::mojom::DataElementType::kUnknown: {
       NOTREACHED();
       break;
@@ -148,6 +149,7 @@
       r->SetToChunkedDataPipe(std::move(chunked_data_pipe_getter));
       return true;
     }
+    case network::mojom::DataElementType::kReadOnceStream:
     case network::mojom::DataElementType::kUnknown: {
       NOTREACHED();
       return false;
diff --git a/services/network/public/cpp/resource_request_body.cc b/services/network/public/cpp/resource_request_body.cc
index a865aeb..8797143 100644
--- a/services/network/public/cpp/resource_request_body.cc
+++ b/services/network/public/cpp/resource_request_body.cc
@@ -21,9 +21,15 @@
   return result;
 }
 
+bool ResourceRequestBody::EnableToAppendElement() const {
+  return elements_.empty() ||
+         (elements_.front().type() !=
+              mojom::DataElementType::kChunkedDataPipe &&
+          elements_.front().type() != mojom::DataElementType::kReadOnceStream);
+}
+
 void ResourceRequestBody::AppendBytes(std::vector<uint8_t> bytes) {
-  DCHECK(elements_.empty() ||
-         elements_.front().type() != mojom::DataElementType::kChunkedDataPipe);
+  DCHECK(EnableToAppendElement());
 
   if (bytes.size() > 0) {
     elements_.push_back(DataElement());
@@ -44,8 +50,7 @@
     uint64_t offset,
     uint64_t length,
     const base::Time& expected_modification_time) {
-  DCHECK(elements_.empty() ||
-         elements_.front().type() != mojom::DataElementType::kChunkedDataPipe);
+  DCHECK(EnableToAppendElement());
 
   elements_.push_back(DataElement());
   elements_.back().SetToFilePathRange(file_path, offset, length,
@@ -58,8 +63,7 @@
     uint64_t offset,
     uint64_t length,
     const base::Time& expected_modification_time) {
-  DCHECK(elements_.empty() ||
-         elements_.front().type() != mojom::DataElementType::kChunkedDataPipe);
+  DCHECK(EnableToAppendElement());
 
   elements_.push_back(DataElement());
   elements_.back().SetToFileRange(std::move(file), file_path, offset, length,
@@ -71,8 +75,7 @@
 }
 
 void ResourceRequestBody::AppendBlob(const std::string& uuid, uint64_t length) {
-  DCHECK(elements_.empty() ||
-         elements_.front().type() != mojom::DataElementType::kChunkedDataPipe);
+  DCHECK(EnableToAppendElement());
 
   elements_.push_back(DataElement());
   elements_.back().SetToBlobRange(uuid, 0 /* offset */, length);
@@ -80,8 +83,7 @@
 
 void ResourceRequestBody::AppendDataPipe(
     mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter) {
-  DCHECK(elements_.empty() ||
-         elements_.front().type() != mojom::DataElementType::kChunkedDataPipe);
+  DCHECK(EnableToAppendElement());
 
   elements_.push_back(DataElement());
   elements_.back().SetToDataPipe(std::move(data_pipe_getter));
@@ -96,6 +98,15 @@
   elements_.back().SetToChunkedDataPipe(std::move(chunked_data_pipe_getter));
 }
 
+void ResourceRequestBody::SetToReadOnceStream(
+    mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
+        chunked_data_pipe_getter) {
+  DCHECK(elements_.empty());
+
+  elements_.push_back(DataElement());
+  elements_.back().SetToReadOnceStream(std::move(chunked_data_pipe_getter));
+}
+
 std::vector<base::FilePath> ResourceRequestBody::GetReferencedFiles() const {
   std::vector<base::FilePath> result;
   for (const auto& element : *elements()) {
diff --git a/services/network/public/cpp/resource_request_body.h b/services/network/public/cpp/resource_request_body.h
index 2634327f..e3679f2 100644
--- a/services/network/public/cpp/resource_request_body.h
+++ b/services/network/public/cpp/resource_request_body.h
@@ -80,6 +80,10 @@
   // support chunked uploads.
   void SetToChunkedDataPipe(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
                                 chunked_data_pipe_getter);
+  // Almost same as above except |chunked_data_pipe_getter| is read only once
+  // and you must talk with a server supporting chunked upload.
+  void SetToReadOnceStream(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
+                               chunked_data_pipe_getter);
   void SetAllowHTTP1ForStreamingUpload(bool allow) {
     allow_http1_for_streaming_upload_ = allow;
   }
@@ -118,6 +122,8 @@
                                    scoped_refptr<network::ResourceRequestBody>>;
   ~ResourceRequestBody();
 
+  bool EnableToAppendElement() const;
+
   std::vector<DataElement> elements_;
   int64_t identifier_;
 
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 4751e5ea..f3daedb 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -327,7 +327,8 @@
   }
   static mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>
   chunked_data_pipe_getter(const network::DataElement& element) {
-    if (element.type_ != network::mojom::DataElementType::kChunkedDataPipe)
+    if (element.type_ != network::mojom::DataElementType::kChunkedDataPipe &&
+        element.type_ != network::mojom::DataElementType::kReadOnceStream)
       return mojo::NullRemote();
     return const_cast<network::DataElement&>(element)
         .ReleaseChunkedDataPipeGetter();
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index 9e48b6f..12dd49ad 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -62,6 +62,7 @@
   // Only used for Upload with Network Service as of now:
   kDataPipe,
   kChunkedDataPipe,
+  kReadOnceStream,
   kRawFile,
 
   // Used for Upload when Network Service is disabled:
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index c209506..c89d6749 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -210,12 +210,14 @@
     std::vector<base::File>& opened_files,
     base::SequencedTaskRunner* file_task_runner) {
   // In the case of a chunked upload, there will just be one element.
-  if (body->elements()->size() == 1 &&
-      body->elements()->begin()->type() ==
-          network::mojom::DataElementType::kChunkedDataPipe) {
-    return std::make_unique<ChunkedDataPipeUploadDataStream>(
-        body, const_cast<DataElement&>(body->elements()->front())
-                  .ReleaseChunkedDataPipeGetter());
+  if (body->elements()->size() == 1) {
+    network::mojom::DataElementType type = body->elements()->begin()->type();
+    if (type == network::mojom::DataElementType::kChunkedDataPipe ||
+        type == network::mojom::DataElementType::kReadOnceStream) {
+      return std::make_unique<ChunkedDataPipeUploadDataStream>(
+          body,
+          body->elements_mutable()->begin()->ReleaseChunkedDataPipeGetter());
+    }
   }
 
   auto opened_file = opened_files.begin();
@@ -244,7 +246,8 @@
             body, element.CloneDataPipeGetter()));
         break;
       }
-      case network::mojom::DataElementType::kChunkedDataPipe: {
+      case network::mojom::DataElementType::kChunkedDataPipe:
+      case network::mojom::DataElementType::kReadOnceStream: {
         // This shouldn't happen, as the traits logic should ensure that if
         // there's a chunked pipe, there's one and only one element.
         NOTREACHED();
@@ -1095,22 +1098,13 @@
 
 // static
 bool URLLoader::HasFetchStreamingUploadBody(const ResourceRequest* request) {
-  // Follows blink::mojom::ResourceType::kXhr.
-  const int kXhr = 13;
-  if (request->resource_type != kXhr)
-    return false;
   const ResourceRequestBody* request_body = request->request_body.get();
   if (!request_body)
     return false;
   const std::vector<DataElement>* elements = request_body->elements();
-  if (elements->size() == 0u)
+  if (elements->size() != 1u)
     return false;
-  // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
-  // Body's source is null means the body is not extracted from ReadableStream.
-  // See blink::PopulateResourceRequest() for actual construction.
-  if (elements->size() > 1u)
-    return false;
-  return elements->at(0).type() == mojom::DataElementType::kChunkedDataPipe;
+  return elements->front().type() == mojom::DataElementType::kReadOnceStream;
 }
 
 void URLLoader::OnAuthRequired(net::URLRequest* url_request,
diff --git a/third_party/blink/public/common/fetch/fetch_api_request_body_mojom_traits.h b/third_party/blink/public/common/fetch/fetch_api_request_body_mojom_traits.h
index c99ea3b..ebe9098 100644
--- a/third_party/blink/public/common/fetch/fetch_api_request_body_mojom_traits.h
+++ b/third_party/blink/public/common/fetch/fetch_api_request_body_mojom_traits.h
@@ -79,7 +79,7 @@
   }
   static mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>
   chunked_data_pipe_getter(const network::DataElement& element) {
-    if (element.type_ != network::mojom::DataElementType::kChunkedDataPipe)
+    if (element.type_ != network::mojom::DataElementType::kReadOnceStream)
       return mojo::NullRemote();
     return const_cast<network::DataElement&>(element)
         .ReleaseChunkedDataPipeGetter();
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index 8802716c..e8a85748 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -7,12 +7,6 @@
 
 import("//third_party/blink/renderer/bindings/modules/v8/v8.gni")
 
-declare_args() {
-  # If this variable is set true, we use a new code generator to generate code
-  # of IDL dictionaries.  See https://crbug.com/839389 for the details.
-  use_blink_v8_binding_new_idl_dictionary = false
-}
-
 bindings_core_v8_files =
     get_path_info([
                     "core/v8/active_script_wrappable.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
index 942e6bb..feda0b5 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -334,7 +334,7 @@
   if (GetMicrotasksScopeDepth(isolate, microtask_queue) > kMaxRecursionDepth)
     return ThrowStackOverflowExceptionIfNeeded(isolate, microtask_queue);
 
-  CHECK(!context->ContextLifecycleObserverList().IsIteratingOverObservers());
+  CHECK(!context->ContextLifecycleObserverSet().IsIteratingOverObservers());
 
   // Run the script and keep track of the current recursion depth.
   v8::MaybeLocal<v8::Value> result;
@@ -472,7 +472,7 @@
   if (depth >= kMaxRecursionDepth)
     return ThrowStackOverflowExceptionIfNeeded(isolate, microtask_queue);
 
-  CHECK(!context->ContextLifecycleObserverList().IsIteratingOverObservers());
+  CHECK(!context->ContextLifecycleObserverSet().IsIteratingOverObservers());
 
   if (ScriptForbiddenScope::IsScriptForbidden()) {
     ThrowScriptForbiddenException(isolate);
@@ -525,7 +525,7 @@
   if (depth >= kMaxRecursionDepth)
     return ThrowStackOverflowExceptionIfNeeded(isolate, microtask_queue);
 
-  CHECK(!context->ContextLifecycleObserverList().IsIteratingOverObservers());
+  CHECK(!context->ContextLifecycleObserverSet().IsIteratingOverObservers());
 
   if (ScriptForbiddenScope::IsScriptForbidden()) {
     ThrowScriptForbiddenException(isolate);
diff --git a/third_party/blink/renderer/config.gni b/third_party/blink/renderer/config.gni
index e2b18ed..9be37ad 100644
--- a/third_party/blink/renderer/config.gni
+++ b/third_party/blink/renderer/config.gni
@@ -41,6 +41,10 @@
   support_webgl2_compute_context = !is_android
 
   # If true, the new implementation (experimental) of Blink-V8 bindings
+  # (of IDL dictionary) is used.
+  use_blink_v8_binding_new_idl_dictionary = false
+
+  # If true, the new implementation (experimental) of Blink-V8 bindings
   # (of IDL interface) is used.
   use_blink_v8_binding_new_idl_interface = true
 }
@@ -65,6 +69,10 @@
   feature_defines_list += [ "WTF_USE_WEBAUDIO_PFFFT=1" ]
 }
 
+if (use_blink_v8_binding_new_idl_dictionary) {
+  feature_defines_list += [ "USE_BLINK_V8_BINDING_NEW_IDL_DICTIONARY" ]
+}
+
 if (use_blink_v8_binding_new_idl_interface) {
   feature_defines_list += [ "USE_BLINK_V8_BINDING_NEW_IDL_INTERFACE" ]
 }
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 6d26a233..c797d4e 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -1992,15 +1992,13 @@
                                             playback_rate_);
   }
 
-  AnimationTimeDelta result =
-      playback_rate_ > 0
-          ? content_->TimeToForwardsEffectChange() / playback_rate_
-          : content_->TimeToReverseEffectChange() / -playback_rate_;
+  if (!HasActiveAnimationsOnCompositor() &&
+      (content_->GetPhase() == Timing::kPhaseActive))
+    return AnimationTimeDelta();
 
-  return !HasActiveAnimationsOnCompositor() &&
-                 content_->GetPhase() == Timing::kPhaseActive
-             ? AnimationTimeDelta()
-             : result;
+  return (playback_rate_ > 0)
+             ? (content_->TimeToForwardsEffectChange() / playback_rate_)
+             : (content_->TimeToReverseEffectChange() / -playback_rate_);
 }
 
 void Animation::cancel() {
diff --git a/third_party/blink/renderer/core/animation/animation_time_delta.h b/third_party/blink/renderer/core/animation/animation_time_delta.h
index 0f0c00b..9c330f3 100644
--- a/third_party/blink/renderer/core/animation/animation_time_delta.h
+++ b/third_party/blink/renderer/core/animation/animation_time_delta.h
@@ -76,8 +76,8 @@
   AnimationTimeDelta operator*(T a) const {
     return AnimationTimeDelta(delta_ * a);
   }
-  template <typename V>
-  AnimationTimeDelta& operator*=(V a) {
+  template <typename T>
+  AnimationTimeDelta& operator*=(T a) {
     return *this = (*this * a);
   }
   template <typename T>
diff --git a/third_party/blink/renderer/core/animation/timing_calculations.h b/third_party/blink/renderer/core/animation/timing_calculations.h
index 731b461..f39fdc7b 100644
--- a/third_party/blink/renderer/core/animation/timing_calculations.h
+++ b/third_party/blink/renderer/core/animation/timing_calculations.h
@@ -174,8 +174,7 @@
 // through the current iteration that ignores transformations to the time
 // introduced by the playback direction or timing functions applied to the
 // effect.
-// https://drafts.csswg.org/web-animations/#calculating-the-simple-iteration
-// -progress
+// https://drafts.csswg.org/web-animations/#calculating-the-simple-iteration-progress
 static inline base::Optional<double> CalculateSimpleIterationProgress(
     Timing::Phase phase,
     base::Optional<double> overall_progress,
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index bf288e600..33c232f 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3171,12 +3171,12 @@
   GetFrame()->GetEventHandlerRegistry().DocumentDetached(*this);
 
   // Signal destruction to mutation observers.
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [](SynchronousMutationObserver* observer) {
         observer->ContextDestroyed();
-        observer->ObserverListWillBeCleared();
+        observer->ObserverSetWillBeCleared();
       });
-  synchronous_mutation_observer_list_.Clear();
+  synchronous_mutation_observer_set_.Clear();
 
   cookie_jar_ = nullptr;  // Not accessible after navigated away.
   fetcher_->ClearContext();
@@ -5388,7 +5388,7 @@
     for (Range* range : ranges)
       range->UpdateOwnerDocumentIfNeeded();
   }
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->DidMoveTreeToNewDocument(root);
       });
@@ -5407,7 +5407,7 @@
       ni->NodeWillBeRemoved(n);
   }
 
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->NodeChildrenWillBeRemoved(container);
       });
@@ -5428,7 +5428,7 @@
       range->FixupRemovedNodeAcrossShadowBoundary(n);
   }
 
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->NodeWillBeRemoved(n);
       });
@@ -5444,7 +5444,7 @@
                                          unsigned offset,
                                          unsigned old_length,
                                          unsigned new_length) {
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->DidUpdateCharacterData(character_data, offset, old_length,
                                          new_length);
@@ -5452,7 +5452,7 @@
 }
 
 void Document::NotifyChangeChildren(const ContainerNode& container) {
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->DidChangeChildren(container);
       });
@@ -5482,7 +5482,7 @@
       range->DidMergeTextNodes(node_to_be_removed_with_index, old_length);
   }
 
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->DidMergeTextNodes(merged_node, node_to_be_removed_with_index,
                                     old_length);
@@ -5495,7 +5495,7 @@
   for (Range* range : ranges_)
     range->DidSplitTextNode(old_node);
 
-  synchronous_mutation_observer_list_.ForEachObserver(
+  synchronous_mutation_observer_set_.ForEachObserver(
       [&](SynchronousMutationObserver* observer) {
         observer->DidSplitTextNode(old_node);
       });
@@ -8143,7 +8143,7 @@
   visitor->Trace(computed_node_mapping_);
   visitor->Trace(mime_handler_view_before_unload_event_listener_);
   visitor->Trace(cookie_jar_);
-  visitor->Trace(synchronous_mutation_observer_list_);
+  visitor->Trace(synchronous_mutation_observer_set_);
   visitor->Trace(element_explicitly_set_attr_elements_map_);
   visitor->Trace(display_lock_document_state_);
   visitor->Trace(font_preload_manager_);
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index a40b925..1d08f4c 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -66,7 +66,7 @@
 #include "third_party/blink/renderer/core/loader/font_preload_manager.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
@@ -1609,9 +1609,9 @@
 
   void CancelPendingJavaScriptUrls();
 
-  HeapObserverList<SynchronousMutationObserver>&
-  SynchronousMutationObserverList() {
-    return synchronous_mutation_observer_list_;
+  HeapObserverSet<SynchronousMutationObserver>&
+  SynchronousMutationObserverSet() {
+    return synchronous_mutation_observer_set_;
   }
 
   void NotifyUpdateCharacterData(CharacterData* character_data,
@@ -2135,8 +2135,8 @@
   HeapHashMap<WeakMember<Element>, Member<ExplicitlySetAttrElementsMap>>
       element_explicitly_set_attr_elements_map_;
 
-  HeapObserverList<SynchronousMutationObserver>
-      synchronous_mutation_observer_list_;
+  HeapObserverSet<SynchronousMutationObserver>
+      synchronous_mutation_observer_set_;
 
   Member<DisplayLockDocumentState> display_lock_document_state_;
 
diff --git a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc
index 7deddd69..156a0e88 100644
--- a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc
+++ b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc
@@ -8,7 +8,7 @@
 
 namespace blink {
 
-void SynchronousMutationObserver::ObserverListWillBeCleared() {
+void SynchronousMutationObserver::ObserverSetWillBeCleared() {
   document_ = nullptr;
 }
 
@@ -17,12 +17,12 @@
     return;
 
   if (document_)
-    document_->SynchronousMutationObserverList().RemoveObserver(this);
+    document_->SynchronousMutationObserverSet().RemoveObserver(this);
 
   document_ = document;
 
   if (document_)
-    document_->SynchronousMutationObserverList().AddObserver(this);
+    document_->SynchronousMutationObserverSet().AddObserver(this);
 }
 
 void SynchronousMutationObserver::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
index 82a35ed8..e574de51 100644
--- a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
+++ b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
@@ -76,7 +76,7 @@
   virtual void ContextDestroyed() {}
 
   // Call before clearing an observer list.
-  void ObserverListWillBeCleared();
+  void ObserverSetWillBeCleared();
 
   Document* GetDocument() const { return document_; }
   void SetDocument(Document*);
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc
index 29da30b4..2ec6885 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -119,7 +119,7 @@
   if (lifecycle_state_ == state)
     return;
   lifecycle_state_ = state;
-  context_lifecycle_observer_list_.ForEachObserver(
+  context_lifecycle_observer_set_.ForEachObserver(
       [&](ContextLifecycleObserver* observer) {
         if (!observer->IsExecutionContextLifecycleObserver())
           return;
@@ -141,30 +141,30 @@
 
 void ExecutionContext::NotifyContextDestroyed() {
   is_context_destroyed_ = true;
-  context_lifecycle_observer_list_.ForEachObserver(
+  context_lifecycle_observer_set_.ForEachObserver(
       [](ContextLifecycleObserver* observer) {
         observer->ContextDestroyed();
-        observer->ObserverListWillBeCleared();
+        observer->ObserverSetWillBeCleared();
       });
-  context_lifecycle_observer_list_.Clear();
+  context_lifecycle_observer_set_.Clear();
 }
 
 void ExecutionContext::AddContextLifecycleObserver(
     ContextLifecycleObserver* observer) {
-  context_lifecycle_observer_list_.AddObserver(observer);
+  context_lifecycle_observer_set_.AddObserver(observer);
 }
 
 void ExecutionContext::RemoveContextLifecycleObserver(
     ContextLifecycleObserver* observer) {
-  DCHECK(context_lifecycle_observer_list_.HasObserver(observer));
-  context_lifecycle_observer_list_.RemoveObserver(observer);
+  DCHECK(context_lifecycle_observer_set_.HasObserver(observer));
+  context_lifecycle_observer_set_.RemoveObserver(observer);
 }
 
 unsigned ExecutionContext::ContextLifecycleStateObserverCountForTesting()
     const {
-  DCHECK(!context_lifecycle_observer_list_.IsIteratingOverObservers());
+  DCHECK(!context_lifecycle_observer_set_.IsIteratingOverObservers());
   unsigned lifecycle_state_observers = 0;
-  context_lifecycle_observer_list_.ForEachObserver(
+  context_lifecycle_observer_set_.ForEachObserver(
       [&](ContextLifecycleObserver* observer) {
         if (!observer->IsExecutionContextLifecycleObserver())
           return;
@@ -391,7 +391,7 @@
   visitor->Trace(pending_exceptions_);
   visitor->Trace(csp_delegate_);
   visitor->Trace(timers_);
-  visitor->Trace(context_lifecycle_observer_list_);
+  visitor->Trace(context_lifecycle_observer_set_);
   visitor->Trace(origin_trial_context_);
   ContextLifecycleNotifier::Trace(visitor);
   ConsoleLogger::Trace(visitor);
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index e1264a3..f1ff5a6 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -49,7 +49,7 @@
 #include "third_party/blink/renderer/core/frame/dom_timer_coordinator.h"
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
 #include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
@@ -368,8 +368,8 @@
 
   void AddContextLifecycleObserver(ContextLifecycleObserver*) override;
   void RemoveContextLifecycleObserver(ContextLifecycleObserver*) override;
-  HeapObserverList<ContextLifecycleObserver>& ContextLifecycleObserverList() {
-    return context_lifecycle_observer_list_;
+  HeapObserverSet<ContextLifecycleObserver>& ContextLifecycleObserverSet() {
+    return context_lifecycle_observer_set_;
   }
   unsigned ContextLifecycleStateObserverCountForTesting() const;
 
@@ -439,7 +439,7 @@
 
   DOMTimerCoordinator timers_;
 
-  HeapObserverList<ContextLifecycleObserver> context_lifecycle_observer_list_;
+  HeapObserverSet<ContextLifecycleObserver> context_lifecycle_observer_set_;
 
   // Counter that keeps track of how many window interaction calls are allowed
   // for this ExecutionContext. Callers are expected to call
diff --git a/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc b/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc
index 25ae020..262c2900 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc
@@ -57,7 +57,7 @@
 #endif
   if (ExecutionContext* context = GetExecutionContext()) {
 #if DCHECK_IS_ON()
-    DCHECK(context->ContextLifecycleObserverList().HasObserver(this));
+    DCHECK(context->ContextLifecycleObserverSet().HasObserver(this));
 #endif
     mojom::blink::FrameLifecycleState pause_state =
         context->ContextPauseState();
diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
index 2e7dcdc..88785f8 100644
--- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc
+++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
@@ -255,9 +255,9 @@
 void PausableScriptExecutor::Dispose() {
   // Remove object as a ExecutionContextLifecycleObserver.
   // TODO(keishi): Remove IsIteratingOverObservers() check when
-  // HeapObserverList() supports removal while iterating.
+  // HeapObserverSet() supports removal while iterating.
   if (!GetExecutionContext()
-           ->ContextLifecycleObserverList()
+           ->ContextLifecycleObserverSet()
            .IsIteratingOverObservers()) {
     SetExecutionContext(nullptr);
   }
diff --git a/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc b/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
index 78163e2..f53e8aa 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
@@ -278,9 +278,9 @@
 
 void AutoplayUmaHelper::MaybeUnregisterContextDestroyedObserver() {
   // TODO(keishi): Remove IsIteratingOverObservers() check when
-  // HeapObserverList() supports removal while iterating.
+  // HeapObserverSet() supports removal while iterating.
   if (!ShouldListenToContextDestroyed() && !GetExecutionContext()
-                                                ->ContextLifecycleObserverList()
+                                                ->ContextLifecycleObserverSet()
                                                 .IsIteratingOverObservers()) {
     SetExecutionContext(nullptr);
   }
diff --git a/third_party/blink/renderer/core/layout/layout_progress.cc b/third_party/blink/renderer/core/layout/layout_progress.cc
index de62561..e49c4dfb 100644
--- a/third_party/blink/renderer/core/layout/layout_progress.cc
+++ b/third_party/blink/renderer/core/layout/layout_progress.cc
@@ -62,7 +62,8 @@
 double LayoutProgress::AnimationProgress() const {
   if (!animating_)
     return 0;
-  base::TimeDelta elapsed = base::TimeTicks::Now() - animation_start_time_;
+  const base::TimeDelta elapsed =
+      base::TimeTicks::Now() - animation_start_time_;
   return (elapsed % animation_duration_) / animation_duration_;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
index 15ce9116..6364c6a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -146,24 +146,19 @@
 }
 
 NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutChildren() {
-  scoped_refptr<const NGBlockBreakToken> legend_break_token;
   scoped_refptr<const NGBlockBreakToken> content_break_token;
   bool has_seen_all_children = false;
   if (const auto* token = BreakToken()) {
     const auto child_tokens = token->ChildBreakTokens();
     if (wtf_size_t break_token_count = child_tokens.size()) {
-      DCHECK_LE(break_token_count, 2u);
-      for (wtf_size_t break_token_idx = 0; break_token_idx < break_token_count;
-           break_token_idx++) {
-        scoped_refptr<const NGBlockBreakToken> child_token =
-            To<NGBlockBreakToken>(child_tokens[break_token_idx]);
-        if (child_token && child_token->InputNode().IsRenderedLegend()) {
-          DCHECK_EQ(break_token_idx, 0u);
-          legend_break_token = child_token;
-        } else {
-          content_break_token = child_token;
-        }
+      scoped_refptr<const NGBlockBreakToken> child_token =
+          To<NGBlockBreakToken>(child_tokens[0]);
+      if (child_token) {
+        DCHECK(!child_token->InputNode().IsRenderedLegend());
+        content_break_token = child_token;
       }
+      // There shouldn't be any additional break tokens.
+      DCHECK_EQ(child_tokens.size(), 1u);
     }
     if (token->HasSeenAllChildren()) {
       container_builder_.SetHasSeenAllChildren();
@@ -172,14 +167,8 @@
   }
 
   NGBlockNode legend = Node().GetRenderedLegend();
-  bool legend_needs_layout =
-      legend && (legend_break_token || !IsResumingLayout(BreakToken()));
-
-  if (legend_needs_layout) {
-    NGBreakStatus break_status = LayoutLegend(legend, legend_break_token);
-    if (break_status != NGBreakStatus::kContinue)
-      return break_status;
-
+  if (legend && !IsResumingLayout(BreakToken())) {
+    LayoutLegend(legend);
     // The legend may eat from the available content box block size. Calculate
     // the minimum block size needed to encompass the legend.
     if (!Node().ShouldApplySizeContainment()) {
@@ -231,11 +220,6 @@
   // all live inside an anonymous child box of the fieldset container.
   auto fieldset_content = Node().GetFieldsetContent();
   if (fieldset_content && (content_break_token || !has_seen_all_children)) {
-    if (ConstraintSpace().HasBlockFragmentation() && legend_broke_ &&
-        IsFragmentainerOutOfSpace(ConstraintSpace().FragmentainerOffsetAtBfc() +
-                                  intrinsic_block_size_))
-      return NGBreakStatus::kContinue;
-
     NGBreakStatus break_status =
         LayoutFieldsetContent(fieldset_content, content_break_token,
                               adjusted_padding_box_size, !!legend);
@@ -253,9 +237,7 @@
   return NGBreakStatus::kContinue;
 }
 
-NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutLegend(
-    NGBlockNode& legend,
-    scoped_refptr<const NGBlockBreakToken> legend_break_token) {
+void NGFieldsetLayoutAlgorithm::LayoutLegend(NGBlockNode& legend) {
   // Lay out the legend. While the fieldset container normally ignores its
   // padding, the legend is laid out within what would have been the content
   // box had the fieldset been a regular block with no weirdness.
@@ -265,101 +247,47 @@
       legend.Style(), percentage_size.inline_size,
       ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction());
 
-  if (legend_break_token)
-    legend_margins.block_start = LayoutUnit();
-
-  scoped_refptr<const NGLayoutResult> result;
-  scoped_refptr<const NGLayoutResult> previous_result;
   LayoutUnit block_offset;
-  do {
-    auto legend_space = CreateConstraintSpaceForLegend(
-        legend, ChildAvailableSize(), percentage_size, block_offset);
-    result = legend.Layout(legend_space, legend_break_token.get());
+  auto legend_space = CreateConstraintSpaceForLegend(
+      legend, ChildAvailableSize(), percentage_size);
+  scoped_refptr<const NGLayoutResult> result =
+      legend.Layout(legend_space, BreakToken());
 
-    // TODO(layout-dev): Handle abortions caused by block fragmentation.
-    DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
+  // TODO(layout-dev): Handle abortions caused by block fragmentation.
+  DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
 
-    if (ConstraintSpace().HasBlockFragmentation()) {
-      NGBreakStatus break_status = BreakBeforeChildIfNeeded(
-          ConstraintSpace(), legend, *result.get(),
-          ConstraintSpace().FragmentainerOffsetAtBfc() + block_offset,
-          /*has_container_separation*/ false, &container_builder_);
-      if (break_status != NGBreakStatus::kContinue)
-        return break_status;
-      EBreakBetween break_after = JoinFragmentainerBreakValues(
-          result->FinalBreakAfter(), legend.Style().BreakAfter());
-      container_builder_.SetPreviousBreakAfter(break_after);
-    }
+  const auto& physical_fragment = result->PhysicalFragment();
 
-    const auto& physical_fragment = result->PhysicalFragment();
-    legend_broke_ = physical_fragment.BreakToken();
+  LayoutUnit legend_border_box_block_size =
+      NGFragment(writing_mode_, physical_fragment).BlockSize();
+  LayoutUnit legend_margin_box_block_size = legend_margins.block_start +
+                                            legend_border_box_block_size +
+                                            legend_margins.block_end;
 
-    // We have already adjusted the legend block offset, no need to adjust
-    // again.
-    if (block_offset != LayoutUnit()) {
-      // If adjusting the block_offset caused the legend to break, revert back
-      // to the previous result.
-      if (legend_broke_) {
-        result = std::move(previous_result);
-        block_offset = LayoutUnit();
-      }
-      break;
-    }
+  LayoutUnit space_left = borders_.block_start - legend_border_box_block_size;
+  if (space_left > LayoutUnit()) {
+    // https://html.spec.whatwg.org/C/#the-fieldset-and-legend-elements
+    // * The element is expected to be positioned in the block-flow direction
+    //   such that its border box is centered over the border on the
+    //   block-start side of the fieldset element.
+    block_offset += space_left / 2;
+  }
+  // If the border is smaller than the block end offset of the legend margin
+  // box, intrinsic_block_size_ should now be based on the the block end
+  // offset of the legend margin box instead of the border.
+  LayoutUnit legend_margin_end_offset =
+      block_offset + legend_margin_box_block_size - legend_margins.block_start;
+  if (legend_margin_end_offset > borders_.block_start) {
+    intrinsic_block_size_ = legend_margin_end_offset;
 
-    LayoutUnit legend_border_box_block_size =
-        NGFragment(writing_mode_, physical_fragment).BlockSize();
-    LayoutUnit legend_margin_box_block_size =
-        legend_margins.block_start + legend_border_box_block_size;
+    is_legend_past_border_ = true;
 
-    LayoutUnit block_end_margin = legend_margins.block_end;
-    if (ConstraintSpace().HasKnownFragmentainerBlockSize()) {
-      block_end_margin = AdjustedMarginAfterFinalChildFragment(
-          ConstraintSpace(), legend_margin_box_block_size, block_end_margin);
-    }
-    legend_margin_box_block_size += block_end_margin;
-
-    LayoutUnit space_left = borders_.block_start - legend_border_box_block_size;
-    if (space_left > LayoutUnit()) {
-      // Don't adjust the block-start offset of the legend if the legend broke.
-      if (legend_break_token || legend_broke_)
-        break;
-
-      // https://html.spec.whatwg.org/C/#the-fieldset-and-legend-elements
-      // * The element is expected to be positioned in the block-flow direction
-      //   such that its border box is centered over the border on the
-      //   block-start side of the fieldset element.
-      block_offset += space_left / 2;
-      if (ConstraintSpace().HasBlockFragmentation()) {
-        // Save the previous result in case adjusting the block_offset causes
-        // the legend to break.
-        previous_result = std::move(result);
-        continue;
-      }
-    }
-    // If the border is smaller than the block end offset of the legend margin
-    // box, intrinsic_block_size_ should now be based on the the block end
-    // offset of the legend margin box instead of the border.
-    LayoutUnit legend_margin_end_offset = block_offset +
-                                          legend_margin_box_block_size -
-                                          legend_margins.block_start;
-    if (legend_margin_end_offset > borders_.block_start) {
-      intrinsic_block_size_ = legend_margin_end_offset;
-
-      is_legend_past_border_ = true;
-
-      // Don't adjust the block-start offset of the fragment border if it broke.
-      if (BreakToken() || (ConstraintSpace().HasKnownFragmentainerBlockSize() &&
-                           legend_margin_end_offset >
-                               ConstraintSpace().FragmentainerBlockSize()))
-        break;
-      // If the legend is larger than the width of the fieldset block-start
-      // border, the actual padding edge of the fieldset will be moved
-      // accordingly. This will be the block-start offset for the fieldset
-      // contents anonymous box.
-      borders_.block_start = legend_margin_end_offset;
-    }
-    break;
-  } while (true);
+    // If the legend is larger than the width of the fieldset block-start
+    // border, the actual padding edge of the fieldset will be moved
+    // accordingly. This will be the block-start offset for the fieldset
+    // contents anonymous box.
+    borders_.block_start = legend_margin_end_offset;
+  }
 
   // If the margin box of the legend is at least as tall as the fieldset
   // block-start border width, it will start at the block-start border edge
@@ -375,7 +303,6 @@
   LogicalOffset legend_offset = {legend_inline_start, block_offset};
 
   container_builder_.AddResult(*result, legend_offset);
-  return NGBreakStatus::kContinue;
 }
 
 LayoutUnit NGFieldsetLayoutAlgorithm::ComputeLegendInlineOffset(
@@ -488,8 +415,7 @@
 NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForLegend(
     NGBlockNode legend,
     LogicalSize available_size,
-    LogicalSize percentage_size,
-    LayoutUnit block_offset) {
+    LogicalSize percentage_size) {
   NGConstraintSpaceBuilder builder(
       ConstraintSpace(), legend.Style().GetWritingMode(), /* is_new_fc */ true);
   SetOrthogonalFallbackInlineSizeIfNeeded(Style(), legend, &builder);
@@ -498,12 +424,6 @@
   builder.SetPercentageResolutionSize(percentage_size);
   builder.SetIsShrinkToFit(legend.Style().LogicalWidth().IsAuto());
   builder.SetTextDirection(legend.Style().Direction());
-
-  if (ConstraintSpace().HasBlockFragmentation()) {
-    SetupSpaceBuilderForFragmentation(ConstraintSpace(), legend, block_offset,
-                                      &builder, /* is_new_fc */ true);
-    builder.SetEarlyBreakAppeal(container_builder_.BreakAppeal());
-  }
   return builder.ToConstraintSpace();
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
index 76c61a3..d861135 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
@@ -37,9 +37,7 @@
 
  private:
   NGBreakStatus LayoutChildren();
-  NGBreakStatus LayoutLegend(
-      NGBlockNode& legend,
-      scoped_refptr<const NGBlockBreakToken> legend_break_token);
+  void LayoutLegend(NGBlockNode& legend);
   NGBreakStatus LayoutFieldsetContent(
       NGBlockNode& fieldset_content,
       scoped_refptr<const NGBlockBreakToken> content_break_token,
@@ -49,13 +47,11 @@
   const NGConstraintSpace CreateConstraintSpaceForLegend(
       NGBlockNode legend,
       LogicalSize available_size,
-      LogicalSize percentage_size,
-      LayoutUnit block_offset);
+      LogicalSize percentage_size);
   const NGConstraintSpace CreateConstraintSpaceForFieldsetContent(
       NGBlockNode fieldset_content,
       LogicalSize padding_box_size,
       LayoutUnit block_offset);
-
   bool IsFragmentainerOutOfSpace(LayoutUnit block_offset) const;
 
   const WritingMode writing_mode_;
@@ -76,10 +72,6 @@
   // fragments.
   LayoutUnit consumed_border_block_start_;
 
-  // If true, this indicates that the legend broke during the current layout
-  // pass.
-  bool legend_broke_ = false;
-
   // If true, the legend is taller than the block-start border, so that it
   // sticks below it, allowing for a class C breakpoint [1] before any fieldset
   // content.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
index 3937652a..a46b3a7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -781,8 +781,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-// Tests that a fieldset with auto height will fragment when its legend reaches
-// the fragmentation line.
+// Tests that a fieldset with auto height will not fragment when its legend
+// reaches the fragmentation line.
 TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) {
   SetBodyInnerHTML(R"HTML(
       <style>
@@ -811,20 +811,12 @@
   ASSERT_TRUE(fragment->BreakToken());
 
   String dump = DumpFragmentTree(fragment.get());
+  // TODO(crbug.com/1097012): The height of the outermost fragment here should
+  // be 500, not 490, but the fragmentation machinery gets confused by the
+  // fieldset padding.
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
-)DUMP";
-  EXPECT_EQ(expectation, dump);
-
-  fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
-      node, space, fragment->BreakToken());
-  ASSERT_TRUE(fragment->BreakToken());
-
-  dump = DumpFragmentTree(fragment.get());
-  expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
+  offset:unplaced size:176x490
+    offset:13,0 size:50x500
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -834,14 +826,13 @@
 
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x123
-    offset:13,0 size:50x100
-    offset:3,100 size:170x20
+  offset:unplaced size:176x23
+    offset:3,0 size:170x20
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
 
-// Tests that a fieldset with a set height will fragment when its legend
+// Tests that a fieldset with a set height will not fragment when its legend
 // reaches the fragmentation line. The used height should also be extended to
 // encompass the legend.
 TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) {
@@ -872,20 +863,12 @@
   ASSERT_TRUE(fragment->BreakToken());
 
   String dump = DumpFragmentTree(fragment.get());
+  // TODO(crbug.com/1097012): The height of the outermost fragment here should
+  // be 500, not 490, but the fragmentation machinery gets confused by the
+  // fieldset padding.
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
-)DUMP";
-  EXPECT_EQ(expectation, dump);
-
-  fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
-      node, space, fragment->BreakToken());
-  ASSERT_TRUE(fragment->BreakToken());
-
-  dump = DumpFragmentTree(fragment.get());
-  expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
+  offset:unplaced size:176x490
+    offset:13,0 size:50x500
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -894,16 +877,19 @@
   ASSERT_FALSE(fragment->BreakToken());
 
   dump = DumpFragmentTree(fragment.get());
+  // TODO(crbug.com/1097012): The height of the outermost fragment here should
+  // be 23, not 0, but the fragmentation machinery gets confused by the
+  // fieldset padding.
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x123
-    offset:13,0 size:50x100
-    offset:3,100 size:170x20
+  offset:unplaced size:176x0
+    offset:3,0 size:170x20
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
 
-// Tests that a fieldset with auto height will fragment when its legend/content
-// reaches the fragmentation line.
+// Tests that a fieldset with auto height will not fragment when its legend
+// reaches the fragmentation line. The content of the fieldset should fragment
+// when it reaches the fragmentation line.
 TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) {
   SetBodyInnerHTML(R"HTML(
       <style>
@@ -936,36 +922,26 @@
   ASSERT_TRUE(fragment->BreakToken());
 
   String dump = DumpFragmentTree(fragment.get());
+  // TODO(crbug.com/1097012): The height of the outermost fragment here should
+  // be 500, not 490, but the fragmentation machinery gets confused by the
+  // fieldset padding.
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
+  offset:unplaced size:176x490
+    offset:13,0 size:50x500
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
   fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
       node, space, fragment->BreakToken());
   ASSERT_TRUE(fragment->BreakToken());
-
-  dump = DumpFragmentTree(fragment.get());
-  expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
-)DUMP";
-  EXPECT_EQ(expectation, dump);
-
-  fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
-      node, space, fragment->BreakToken());
-  ASSERT_TRUE(fragment->BreakToken());
-
-  dump = DumpFragmentTree(fragment.get());
   // TODO(crbug.com/1097012): The height of the outermost fragment here should
   // be 200, not 190, but the fragmentation machinery gets confused by the
   // fieldset padding.
+  dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:176x190
-    offset:13,0 size:50x100
-    offset:3,100 size:170x100
-      offset:10,10 size:100x90
+    offset:3,0 size:170x200
+      offset:10,10 size:100x190
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -975,14 +951,15 @@
 
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x123
-    offset:3,0 size:170x120
-      offset:10,0 size:100x110
+  offset:unplaced size:176x23
+    offset:3,0 size:170x20
+      offset:10,0 size:100x10
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
 
-// Tests that a fieldset with a set height will fragment when its legend/content
+// Tests that a fieldset with a set height will fragment when its legend reaches
+// the fragmentation line. The content of the fieldset should fragment when it
 // reaches the fragmentation line.
 TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) {
   SetBodyInnerHTML(R"HTML(
@@ -1016,45 +993,34 @@
   ASSERT_TRUE(fragment->BreakToken());
 
   String dump = DumpFragmentTree(fragment.get());
+  // TODO(crbug.com/1097012): The height of the outermost fragment here should
+  // be 500, not 490, but the fragmentation machinery gets confused by the
+  // fieldset padding.
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
+  offset:unplaced size:176x490
+    offset:13,0 size:50x500
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
   fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
       node, space, fragment->BreakToken());
   ASSERT_TRUE(fragment->BreakToken());
-
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x200
-    offset:13,0 size:50x200
-)DUMP";
-  EXPECT_EQ(expectation, dump);
-
-  fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
-      node, space, fragment->BreakToken());
-  ASSERT_TRUE(fragment->BreakToken());
-
-  dump = DumpFragmentTree(fragment.get());
-  expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:176x123
-    offset:13,0 size:50x100
-    offset:3,100 size:170x20
-      offset:10,10 size:100x90
+  offset:unplaced size:176x0
+    offset:3,0 size:170x20
+      offset:10,10 size:100x190
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
   fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
       node, space, fragment->BreakToken());
   ASSERT_FALSE(fragment->BreakToken());
-
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:176x0
     offset:3,0 size:170x0
-      offset:10,0 size:100x110
+      offset:10,0 size:100x10
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
@@ -1070,7 +1036,7 @@
           <div style="width:55px; height:150px;"></div>
         </legend>
         <div style="width:44px; height:150px;"></div>
-      </div>
+      </fieldset>
   )HTML");
 
   LayoutUnit kFragmentainerSpaceAvailable(100);
@@ -1089,7 +1055,7 @@
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:1000x100
     offset:0,0 size:55x30
-      offset:0,0 size:55x100
+      offset:0,0 size:55x150
     offset:0,30 size:1000x70
       offset:0,0 size:44x70
 )DUMP";
@@ -1102,8 +1068,6 @@
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:1000x80
-    offset:0,0 size:55x0
-      offset:0,0 size:55x50
     offset:0,0 size:1000x80
       offset:0,0 size:44x80
 )DUMP";
@@ -1195,30 +1159,18 @@
 
   scoped_refptr<const NGPhysicalBoxFragment> fragment =
       NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
-  ASSERT_TRUE(fragment->BreakToken());
+  ASSERT_FALSE(fragment->BreakToken());
 
   String dump = DumpFragmentTree(fragment.get());
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:100x100
     offset:0,0 size:75x60
-      offset:0,0 size:50x100
+      offset:0,0 size:50x120
+      offset:0,120 size:40x20
     offset:0,60 size:100x40
       offset:0,0 size:85x10
 )DUMP";
   EXPECT_EQ(expectation, dump);
-
-  fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
-      node, space, fragment->BreakToken());
-  ASSERT_FALSE(fragment->BreakToken());
-
-  dump = DumpFragmentTree(fragment.get());
-  expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:100x0
-    offset:0,0 size:75x0
-      offset:0,0 size:50x20
-      offset:0,20 size:40x20
-)DUMP";
-  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGFieldsetLayoutAlgorithmTest, OverflowedFieldsetContent) {
@@ -1258,7 +1210,7 @@
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:100x100
     offset:0,0 size:75x10
-      offset:0,0 size:50x100
+      offset:0,0 size:50x220
     offset:0,10 size:100x90
       offset:0,0 size:85x10
       offset:0,10 size:65x10
@@ -1273,8 +1225,6 @@
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:100x0
-    offset:0,0 size:75x0
-      offset:0,0 size:50x100
     offset:0,0 size:100x0
       offset:0,0 size:65x0
         offset:0,0 size:51x100
@@ -1288,8 +1238,6 @@
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:100x0
-    offset:0,0 size:75x0
-      offset:0,0 size:50x20
     offset:0,0 size:100x0
       offset:0,0 size:65x0
         offset:0,0 size:51x40
@@ -1442,8 +1390,10 @@
 
   String dump = DumpFragmentTree(fragment.get());
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:1000x100
+  offset:unplaced size:1000x110
     offset:0,0 size:20x50
+    offset:0,50 size:100x60
+      offset:0,0 size:10x60
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -1453,10 +1403,9 @@
 
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:1000x60
-    offset:0,0 size:100x60
-      offset:0,0 size:10x60
-      offset:0,60 size:100x0
+  offset:unplaced size:1000x0
+    offset:0,0 size:100x0
+      offset:0,0 size:100x0
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
@@ -1530,7 +1479,7 @@
     <div id="container">
       <div style="width:20px; height:90px;"></div>
       <fieldset id="fieldset">
-        <legend id="legend" style="break-before:avoid; break-inside:avoid"></legend>
+        <legend id="legend" style="break-before:avoid;"></legend>
       </fieldset>
     </div>
   )HTML");
@@ -1549,8 +1498,10 @@
 
   String dump = DumpFragmentTree(fragment.get());
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:1000x100
+  offset:unplaced size:1000x125
     offset:0,0 size:20x90
+    offset:0,90 size:120x35
+      offset:20,0 size:10x25
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -1560,10 +1511,9 @@
 
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:1000x45
-    offset:0,0 size:120x45
-      offset:20,0 size:10x25
-      offset:10,35 size:100x0
+  offset:unplaced size:1000x10
+    offset:0,0 size:120x10
+      offset:10,0 size:100x0
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
@@ -1659,6 +1609,8 @@
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:1000x100
     offset:0,0 size:20x50
+    offset:0,50 size:100x50
+      offset:0,0 size:10x50
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -1668,10 +1620,9 @@
 
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:1000x75
-    offset:0,0 size:100x75
-      offset:0,0 size:10x50
-      offset:0,50 size:100x25
+  offset:unplaced size:1000x25
+    offset:0,0 size:100x25
+      offset:0,0 size:100x25
         offset:0,0 size:15x25
 )DUMP";
   EXPECT_EQ(expectation, dump);
@@ -1710,8 +1661,11 @@
   ASSERT_TRUE(fragment->BreakToken());
 
   String dump = DumpFragmentTree(fragment.get());
+  // TODO(crbug.com/1097012): The height of the outermost fragment here should
+  // be 100, not 110, but the fragmentation machinery gets confused
+  // and includes the margin bottom.
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:100x100
+  offset:unplaced size:100x110
     offset:0,0 size:0x90
 )DUMP";
   EXPECT_EQ(expectation, dump);
@@ -1763,7 +1717,7 @@
   String dump = DumpFragmentTree(fragment.get());
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:220x60
-    offset:60,0 size:10x40
+    offset:60,5 size:10x50
 )DUMP";
   EXPECT_EQ(expectation, dump);
 
@@ -1774,7 +1728,6 @@
   dump = DumpFragmentTree(fragment.get());
   expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
   offset:unplaced size:220x10
-    offset:60,0 size:10x10
     offset:60,0 size:100x10
 )DUMP";
   EXPECT_EQ(expectation, dump);
diff --git a/third_party/blink/renderer/core/loader/private/prerender_handle.cc b/third_party/blink/renderer/core/loader/private/prerender_handle.cc
index a853a8c..51b6fd76 100644
--- a/third_party/blink/renderer/core/loader/private/prerender_handle.cc
+++ b/third_party/blink/renderer/core/loader/private/prerender_handle.cc
@@ -104,7 +104,7 @@
 PrerenderHandle::~PrerenderHandle() = default;
 
 void PrerenderHandle::Dispose() {
-  if (remote_handle_.is_bound())
+  if (remote_handle_.is_bound() && !GetExecutionContext()->IsContextDestroyed())
     remote_handle_->Abandon();
   Detach();
 }
diff --git a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
index 382ca30..047e741 100644
--- a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
+++ b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
@@ -322,9 +322,9 @@
   void Dispose() {
     parent_ = nullptr;
     // TODO(keishi): Remove IsIteratingOverObservers() check when
-    // HeapObserverList() supports removal while iterating.
+    // HeapObserverSet() supports removal while iterating.
     if (!GetExecutionContext()
-             ->ContextLifecycleObserverList()
+             ->ContextLifecycleObserverSet()
              .IsIteratingOverObservers()) {
       SetExecutionContext(nullptr);
     }
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index 9639965..1b35bb8 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -531,7 +531,7 @@
   if (is_initial_state)
     return;
 
-  page_visibility_observer_list_.ForEachObserver(
+  page_visibility_observer_set_.ForEachObserver(
       [](PageVisibilityObserver* observer) {
         observer->PageVisibilityChanged();
       });
@@ -896,7 +896,7 @@
   visitor->Trace(focus_controller_);
   visitor->Trace(context_menu_controller_);
   visitor->Trace(page_scale_constraints_set_);
-  visitor->Trace(page_visibility_observer_list_);
+  visitor->Trace(page_visibility_observer_set_);
   visitor->Trace(pointer_lock_controller_);
   visitor->Trace(scrolling_coordinator_);
   visitor->Trace(browser_controls_);
@@ -963,11 +963,11 @@
   if (agent_metrics_collector_)
     agent_metrics_collector_->ReportMetrics();
 
-  page_visibility_observer_list_.ForEachObserver(
+  page_visibility_observer_set_.ForEachObserver(
       [](PageVisibilityObserver* observer) {
-        observer->ObserverListWillBeCleared();
+        observer->ObserverSetWillBeCleared();
       });
-  page_visibility_observer_list_.Clear();
+  page_visibility_observer_set_.Clear();
 
   page_scheduler_.reset();
 }
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index 4671cf99..b136f3b8 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -40,7 +40,7 @@
 #include "third_party/blink/renderer/core/page/viewport_description.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
@@ -350,8 +350,8 @@
     return history_navigation_virtual_time_pauser_;
   }
 
-  HeapObserverList<PageVisibilityObserver>& PageVisibilityObserverList() {
-    return page_visibility_observer_list_;
+  HeapObserverSet<PageVisibilityObserver>& PageVisibilityObserverSet() {
+    return page_visibility_observer_set_;
   }
 
   static void PrepareForLeakDetection();
@@ -393,7 +393,7 @@
   const Member<FocusController> focus_controller_;
   const Member<ContextMenuController> context_menu_controller_;
   const Member<PageScaleConstraintsSet> page_scale_constraints_set_;
-  HeapObserverList<PageVisibilityObserver> page_visibility_observer_list_;
+  HeapObserverSet<PageVisibilityObserver> page_visibility_observer_set_;
   const Member<PointerLockController> pointer_lock_controller_;
   Member<ScrollingCoordinator> scrolling_coordinator_;
   const Member<BrowserControls> browser_controls_;
diff --git a/third_party/blink/renderer/core/page/page_visibility_observer.cc b/third_party/blink/renderer/core/page/page_visibility_observer.cc
index 9ad5f41..886d217 100644
--- a/third_party/blink/renderer/core/page/page_visibility_observer.cc
+++ b/third_party/blink/renderer/core/page/page_visibility_observer.cc
@@ -12,7 +12,7 @@
   SetPage(page);
 }
 
-void PageVisibilityObserver::ObserverListWillBeCleared() {
+void PageVisibilityObserver::ObserverSetWillBeCleared() {
   page_ = nullptr;
 }
 
@@ -21,12 +21,12 @@
     return;
 
   if (page_)
-    page_->PageVisibilityObserverList().RemoveObserver(this);
+    page_->PageVisibilityObserverSet().RemoveObserver(this);
 
   page_ = page;
 
   if (page_)
-    page_->PageVisibilityObserverList().AddObserver(this);
+    page_->PageVisibilityObserverSet().AddObserver(this);
 }
 
 void PageVisibilityObserver::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/page/page_visibility_observer.h b/third_party/blink/renderer/core/page/page_visibility_observer.h
index 26aee047..5c8b5912ea 100644
--- a/third_party/blink/renderer/core/page/page_visibility_observer.h
+++ b/third_party/blink/renderer/core/page/page_visibility_observer.h
@@ -39,7 +39,7 @@
   virtual void PageVisibilityChanged() = 0;
 
   // Call before clearing an observer list.
-  void ObserverListWillBeCleared();
+  void ObserverSetWillBeCleared();
 
   Page* GetPage() const { return page_; }
   void SetPage(Page*);
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc
index 1f73e42..7cfbc8e 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -860,6 +860,12 @@
                 script_state, engine_->controller_[branch]);
           }
         }
+
+        // TODO(ricea): Implement https://github.com/whatwg/streams/pull/1045 so
+        // this step can be numbered correctly.
+        // Resolve |cancelPromise| with undefined.
+        engine_->cancel_promise_->ResolveWithUndefined(script_state);
+
         //    3. Set closed to true.
         engine_->closed_ = true;
 
@@ -1068,6 +1074,11 @@
       //      [[readableStreamController]], r).
       ReadableStreamDefaultController::Error(GetScriptState(),
                                              engine_->controller_[1], r);
+
+      // TODO(ricea): Implement https://github.com/whatwg/streams/pull/1045 so
+      // this step can be numbered correctly.
+      // Resolve |cancelPromise| with undefined.
+      engine_->cancel_promise_->ResolveWithUndefined(GetScriptState());
     }
 
     void Trace(Visitor* visitor) const override {
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h b/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
index 1dcec7fa..50b4eb6 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
@@ -69,8 +69,6 @@
         image, container_size_without_zoom, zoom, url));
   }
 
-  bool IsSVGImageForContainer() const override { return true; }
-
   IntSize Size() const override;
   FloatSize SizeAsFloat(RespectImageOrientationEnum) const override;
 
diff --git a/third_party/blink/renderer/modules/vibration/vibration_controller.cc b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
index 25162ef..df723d0d9 100644
--- a/third_party/blink/renderer/modules/vibration/vibration_controller.cc
+++ b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
@@ -181,6 +181,11 @@
 
 void VibrationController::ContextDestroyed() {
   Cancel();
+
+  // If the document context was destroyed, never call the mojo service again.
+  // TODO(crbug.com/1116948): Remove this line once vibration_manager_ switches
+  // to kForceWithContextObserver.
+  vibration_manager_.reset();
 }
 
 void VibrationController::PageVisibilityChanged() {
diff --git a/third_party/blink/renderer/modules/vibration/vibration_controller.h b/third_party/blink/renderer/modules/vibration/vibration_controller.h
index 5828c6d..7d739da 100644
--- a/third_party/blink/renderer/modules/vibration/vibration_controller.h
+++ b/third_party/blink/renderer/modules/vibration/vibration_controller.h
@@ -74,7 +74,14 @@
 
   // Remote to VibrationManager mojo interface. This is reset in
   // |contextDestroyed| and must not be called or recreated after it is reset.
-  HeapMojoRemote<device::mojom::blink::VibrationManager> vibration_manager_;
+  //
+  // TODO(crbug.com/1116948): Remove kForceWithoutContextObserver parameter
+  // after hooking disconnect handler in js is implemented in
+  // MojoInterfaceInterceptor.
+  // See: third_party/blink/web_tests/vibration/vibration-iframe.html
+  HeapMojoRemote<device::mojom::blink::VibrationManager,
+                 HeapMojoWrapperMode::kForceWithoutContextObserver>
+      vibration_manager_;
 
   // Timer for calling |doVibrate| after a delay. It is safe to call
   // |startOneshot| when the timer is already running: it may affect the time
diff --git a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
index 1cce7bb..705c03ab 100644
--- a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
+++ b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
@@ -223,11 +223,10 @@
   // stricter.
   static_assert(kCoarseResolution >= base::TimeDelta::FromSecondsD(
                                          TimeClamper::kResolutionSeconds),
-                "kCoarseResolutionInSeconds should be at least "
-                "as coarse as other clock resolutions");
-  double clamped_time = time.FloorToMultiple(kCoarseResolution).InSecondsF();
+                "kCoarseResolution should be at least as coarse as other clock "
+                "resolutions");
 
-  return clamped_time;
+  return time.FloorToMultiple(kCoarseResolution).InSecondsF();
 }
 
 int VideoFrameCallbackRequesterImpl::requestVideoFrameCallback(
diff --git a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
index cf79960..c8b7a2c 100644
--- a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
+++ b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
@@ -153,8 +153,8 @@
     EXPECT_NE(processing_time.InSecondsF(), metadata->processingDuration());
   }
 
-  double last_now() { return now_; }
-  bool was_invoked() { return was_invoked_; }
+  double last_now() const { return now_; }
+  bool was_invoked() const { return was_invoked_; }
 
  private:
   void VerifyTicksClamping(base::TimeTicks reference,
@@ -167,11 +167,10 @@
   }
 
   double TicksToClampedMillisecondsF(base::TimeTicks ticks) {
-    constexpr double kSecondsToMillis = 1000.0;
     return Performance::ClampTimeResolution(
                timing_.MonotonicTimeToZeroBasedDocumentTime(ticks)
                    .InSecondsF()) *
-           kSecondsToMillis;
+           base::Time::kMillisecondsPerSecond;
   }
 
   double TicksToMillisecondsF(base::TimeTicks ticks) {
@@ -180,12 +179,8 @@
   }
 
   static double ClampElapsedProcessingTime(base::TimeDelta time) {
-    constexpr auto kProcessingTimeResolution =
-        base::TimeDelta::FromMicroseconds(100);
-    double clamped_time =
-        time.FloorToMultiple(kProcessingTimeResolution).InSecondsF();
-
-    return clamped_time;
+    return time.FloorToMultiple(base::TimeDelta::FromMicroseconds(100))
+        .InSecondsF();
   }
 
   double now_;
@@ -344,7 +339,7 @@
   EXPECT_CALL(*media_player(), GetVideoFramePresentationMetadata())
       .WillOnce(Return(ByMove(MetadataHelper::CopyDefaultMedatada())));
 
-  double now_ms =
+  const double now_ms =
       timing.MonotonicTimeToZeroBasedDocumentTime(base::TimeTicks::Now())
           .InMillisecondsF();
 
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 8d3bba71..b97d72fd 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -289,7 +289,9 @@
   }
 
   std::string codec_str = config->codec().Utf8();
-  std::string profile_str = config->profile().Utf8();
+  std::string profile_str;
+  if (config->hasProfile())
+    profile_str = config->profile().Utf8();
   auto codec_type = media::StringToVideoCodec(codec_str);
   if (codec_type == media::kUnknownVideoCodec) {
     HandleError(DOMExceptionCode::kNotFoundError, "Unknown codec type");
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index c0b7fd4..2f42d33 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1136,7 +1136,7 @@
     "graphics/video_frame_submitter.h",
     "graphics/web_graphics_context_3d_provider_wrapper.cc",
     "graphics/web_graphics_context_3d_provider_wrapper.h",
-    "heap_observer_list.h",
+    "heap_observer_set.h",
     "image-decoders/bmp/bmp_image_decoder.cc",
     "image-decoders/bmp/bmp_image_decoder.h",
     "image-decoders/bmp/bmp_image_reader.cc",
@@ -1935,7 +1935,7 @@
     "graphics/placeholder_image_test.cc",
     "graphics/static_bitmap_image_test.cc",
     "graphics/video_frame_submitter_test.cc",
-    "heap_observer_list_test.cc",
+    "heap_observer_set_test.cc",
     "image-decoders/bmp/bmp_image_decoder_test.cc",
     "image-decoders/fast_shared_buffer_reader_test.cc",
     "image-decoders/gif/gif_image_decoder_test.cc",
diff --git a/third_party/blink/renderer/platform/context_lifecycle_observer.cc b/third_party/blink/renderer/platform/context_lifecycle_observer.cc
index e0b406f..9beb179 100644
--- a/third_party/blink/renderer/platform/context_lifecycle_observer.cc
+++ b/third_party/blink/renderer/platform/context_lifecycle_observer.cc
@@ -8,7 +8,7 @@
 
 namespace blink {
 
-void ContextLifecycleObserver::ObserverListWillBeCleared() {
+void ContextLifecycleObserver::ObserverSetWillBeCleared() {
   notifier_ = nullptr;
 }
 
diff --git a/third_party/blink/renderer/platform/context_lifecycle_observer.h b/third_party/blink/renderer/platform/context_lifecycle_observer.h
index b4a4198..bc034a9 100644
--- a/third_party/blink/renderer/platform/context_lifecycle_observer.h
+++ b/third_party/blink/renderer/platform/context_lifecycle_observer.h
@@ -18,7 +18,7 @@
   virtual void ContextDestroyed() = 0;
 
   // Call before clearing an observer list.
-  void ObserverListWillBeCleared();
+  void ObserverSetWillBeCleared();
 
   ContextLifecycleNotifier* GetContextLifecycleNotifier() const {
     return notifier_;
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
index 6684ac6..d81d3a73 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -46,6 +46,8 @@
 #endif  // DCHECK_IS_ON()
 
 const size_t kMaxCacheSize = 1024u;
+const int kMinImageLength = 8;
+const int kMaxImageLength = 100;
 
 // TODO(gilmanmh): If grayscaling images in dark mode proves popular among
 // users, consider experimenting with different grayscale algorithms.
@@ -88,9 +90,7 @@
 DarkModeFilter::DarkModeFilter()
     : text_classifier_(nullptr),
       background_classifier_(nullptr),
-      bitmap_image_classifier_(nullptr),
-      svg_image_classifier_(nullptr),
-      gradient_generated_image_classifier_(nullptr),
+      image_classifier_(nullptr),
       color_filter_(nullptr),
       image_filter_(nullptr),
       inverted_color_cache_(new DarkModeInvertedColorCache()) {
@@ -131,11 +131,7 @@
       DarkModeColorClassifier::MakeTextColorClassifier(settings_);
   background_classifier_ =
       DarkModeColorClassifier::MakeBackgroundColorClassifier(settings_);
-  bitmap_image_classifier_ =
-      DarkModeImageClassifier::MakeBitmapImageClassifier();
-  svg_image_classifier_ = DarkModeImageClassifier::MakeSVGImageClassifier();
-  gradient_generated_image_classifier_ =
-      DarkModeImageClassifier::MakeGradientGeneratedImageClassifier();
+  image_classifier_ = std::make_unique<DarkModeImageClassifier>();
 }
 
 SkColor DarkModeFilter::InvertColorIfNeeded(SkColor color, ElementRole role) {
@@ -152,22 +148,42 @@
   return color;
 }
 
+bool DarkModeFilter::AnalyzeShouldApplyToImage(const SkRect& src,
+                                               const SkRect& dst) {
+  if (settings().image_policy == DarkModeImagePolicy::kFilterNone)
+    return false;
+
+  if (settings().image_policy == DarkModeImagePolicy::kFilterAll)
+    return true;
+
+  // Images being drawn from very smaller |src| rect, i.e. one of the dimensions
+  // is very small, can be used for the border around the content or showing
+  // separator. Consider these images irrespective of size of the rect being
+  // drawn to. Classifying them will not be too costly.
+  if (src.width() <= kMinImageLength || src.height() <= kMinImageLength)
+    return true;
+
+  // Do not consider images being drawn into bigger rect as these images are not
+  // meant for icons or representing smaller widgets. These images are
+  // considered as photos which should be untouched.
+  return (dst.width() <= kMaxImageLength && dst.height() <= kMaxImageLength);
+}
+
 void DarkModeFilter::ApplyToImageFlagsIfNeeded(const SkRect& src,
                                                const SkRect& dst,
                                                const PaintImage& paint_image,
-                                               cc::PaintFlags* flags,
-                                               ElementRole element_role) {
+                                               cc::PaintFlags* flags) {
   // The construction of |paint_image| is expensive, so ensure
   // IsDarkModeActive() is checked prior to calling this function.
   // See: https://crbug.com/1094781.
   DCHECK(IsDarkModeActive());
 
-  if (!image_filter_ ||
-      !ShouldApplyToImage(settings(), src, dst, paint_image, element_role)) {
+  if (!image_filter_ || !AnalyzeShouldApplyToImage(src, dst))
     return;
-  }
 
-  flags->setColorFilter(image_filter_);
+  if (ClassifyImage(settings(), src, dst, paint_image) ==
+      DarkModeClassification::kApplyFilter)
+    flags->setColorFilter(image_filter_);
 }
 
 base::Optional<cc::PaintFlags> DarkModeFilter::ApplyToFlagsIfNeeded(
@@ -235,38 +251,21 @@
   return inverted_color_cache_->size();
 }
 
-bool DarkModeFilter::ShouldApplyToImage(const DarkModeSettings& settings,
-                                        const SkRect& src,
-                                        const SkRect& dst,
-                                        const PaintImage& paint_image,
-                                        ElementRole role) {
+DarkModeClassification DarkModeFilter::ClassifyImage(
+    const DarkModeSettings& settings,
+    const SkRect& src,
+    const SkRect& dst,
+    const PaintImage& paint_image) {
   switch (settings.image_policy) {
-    case DarkModeImagePolicy::kFilterSmart: {
-      DarkModeImageClassifier* classifier;
-
-      switch (role) {
-        case ElementRole::kBitmapImage:
-          classifier = bitmap_image_classifier_.get();
-          break;
-        case ElementRole::kSVGImage:
-          classifier = svg_image_classifier_.get();
-          break;
-        case ElementRole::kGradientGeneratedImage:
-          classifier = gradient_generated_image_classifier_.get();
-          break;
-        default:
-          return false;
-      }
-
-      DarkModeClassification result =
-          classifier->Classify(paint_image, src, dst);
-      return result == DarkModeClassification::kApplyFilter;
-    }
+    case DarkModeImagePolicy::kFilterSmart:
+      return image_classifier_->Classify(paint_image, src, dst);
     case DarkModeImagePolicy::kFilterNone:
-      return false;
+      return DarkModeClassification::kDoNotApplyFilter;
     case DarkModeImagePolicy::kFilterAll:
-      return true;
+      return DarkModeClassification::kApplyFilter;
   }
+
+  NOTREACHED();
 }
 
 ScopedDarkModeElementRoleOverride::ScopedDarkModeElementRoleOverride(
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
index be66288..41a5fe8 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
@@ -10,6 +10,7 @@
 #include "cc/paint/paint_flags.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
@@ -40,28 +41,24 @@
   // TODO(gilmanmh): Add a role for shadows. In general, we don't want to
   // invert shadows, but we may need to do some other kind of processing for
   // them.
-  enum class ElementRole {
-    kText,
-    kListSymbol,
-    kBackground,
-    kSVG,
-    kUnhandledImage,
-    kBitmapImage,
-    kSVGImage,
-    kGradientGeneratedImage
-  };
+  enum class ElementRole { kText, kListSymbol, kBackground, kSVG };
 
   SkColor InvertColorIfNeeded(SkColor color, ElementRole element_role);
   base::Optional<cc::PaintFlags> ApplyToFlagsIfNeeded(
       const cc::PaintFlags& flags,
       ElementRole element_role);
 
-  // |image| and |flags| must not be null.
+  // Decides whether to apply dark mode or not based on |src| and |dst|. True
+  // means dark mode should be applied. For applying the dark mode color filter
+  // to the image call ApplyToImageFlagsIfNeeded().
+  bool AnalyzeShouldApplyToImage(const SkRect& src, const SkRect& dst);
+
+  // Sets dark mode color filter on the flags based on the classification done
+  // on |paint_image|. |flags| must not be null.
   void ApplyToImageFlagsIfNeeded(const SkRect& src,
                                  const SkRect& dst,
                                  const PaintImage& paint_image,
-                                 cc::PaintFlags* flags,
-                                 ElementRole element_role);
+                                 cc::PaintFlags* flags);
 
   SkColorFilter* GetImageFilterForTesting() { return image_filter_.get(); }
   size_t GetInvertedColorCacheSizeForTesting();
@@ -72,17 +69,14 @@
   DarkModeSettings settings_;
 
   bool ShouldApplyToColor(SkColor color, ElementRole role);
-  bool ShouldApplyToImage(const DarkModeSettings& settings,
-                          const SkRect& src,
-                          const SkRect& dst,
-                          const PaintImage& paint_image,
-                          ElementRole role);
+  DarkModeClassification ClassifyImage(const DarkModeSettings& settings,
+                                       const SkRect& src,
+                                       const SkRect& dst,
+                                       const PaintImage& paint_image);
 
   std::unique_ptr<DarkModeColorClassifier> text_classifier_;
   std::unique_ptr<DarkModeColorClassifier> background_classifier_;
-  std::unique_ptr<DarkModeImageClassifier> bitmap_image_classifier_;
-  std::unique_ptr<DarkModeImageClassifier> svg_image_classifier_;
-  std::unique_ptr<DarkModeImageClassifier> gradient_generated_image_classifier_;
+  std::unique_ptr<DarkModeImageClassifier> image_classifier_;
 
   std::unique_ptr<DarkModeColorFilter> color_filter_;
   sk_sp<SkColorFilter> image_filter_;
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc
index da272d2..68b6a14 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc
@@ -114,5 +114,41 @@
   EXPECT_EQ(2u, filter.GetInvertedColorCacheSizeForTesting());
 }
 
+TEST(DarkModeFilterTest, AnalyzeShouldApplyToImage) {
+  DarkModeFilter filter;
+  DarkModeSettings settings;
+  settings.mode = DarkModeInversionAlgorithm::kSimpleInvertForTesting;
+  settings.image_policy = DarkModeImagePolicy::kFilterSmart;
+  filter.UpdateSettings(settings);
+
+  // |dst| is smaller than threshold size.
+  EXPECT_TRUE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(100, 100),
+                                               SkRect::MakeWH(100, 100)));
+
+  // |dst| is smaller than threshold size, even |src| is larger.
+  EXPECT_TRUE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(200, 200),
+                                               SkRect::MakeWH(100, 100)));
+
+  // |dst| is smaller than threshold size, |src| is smaller.
+  EXPECT_TRUE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(20, 20),
+                                               SkRect::MakeWH(100, 100)));
+
+  // |src| having very smaller width, even |dst| is larger than threshold size.
+  EXPECT_TRUE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(5, 200),
+                                               SkRect::MakeWH(5, 200)));
+
+  // |src| having very smaller height, even |dst| is larger than threshold size.
+  EXPECT_TRUE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(200, 5),
+                                               SkRect::MakeWH(200, 5)));
+
+  // |dst| is larger than threshold size.
+  EXPECT_FALSE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(20, 20),
+                                                SkRect::MakeWH(200, 200)));
+
+  // |dst| is larger than threshold size.
+  EXPECT_FALSE(filter.AnalyzeShouldApplyToImage(SkRect::MakeWH(20, 200),
+                                                SkRect::MakeWH(20, 200)));
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
index 092acd4..653be20 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
@@ -37,37 +37,6 @@
 const int kMaxBlocks = 10;
 const float kMinOpaquePixelPercentageForForeground = 0.2;
 
-const int kMinImageSizeForClassification1D = 24;
-const int kMaxImageSizeForClassification1D = 100;
-
-class DarkModeBitmapImageClassifier : public DarkModeImageClassifier {
-  DarkModeClassification DoInitialClassification(const SkRect& dst) override {
-    if (dst.width() < kMinImageSizeForClassification1D ||
-        dst.height() < kMinImageSizeForClassification1D)
-      return DarkModeClassification::kApplyFilter;
-
-    if (dst.width() > kMaxImageSizeForClassification1D ||
-        dst.height() > kMaxImageSizeForClassification1D) {
-      return DarkModeClassification::kDoNotApplyFilter;
-    }
-
-    return DarkModeClassification::kNotClassified;
-  }
-};
-
-class DarkModeSVGImageClassifier : public DarkModeImageClassifier {
-  DarkModeClassification DoInitialClassification(const SkRect& dst) override {
-    return DarkModeClassification::kNotClassified;
-  }
-};
-
-class DarkModeGradientGeneratedImageClassifier
-    : public DarkModeImageClassifier {
-  DarkModeClassification DoInitialClassification(const SkRect& dst) override {
-    return DarkModeClassification::kApplyFilter;
-  }
-};
-
 // DarkModeImageClassificationCache - Implements classification caches for
 // different paint image ids. The classification result for the given |src|
 // rect is added to cache identified by |image_id| and result for the same
@@ -137,21 +106,6 @@
 
 DarkModeImageClassifier::~DarkModeImageClassifier() = default;
 
-std::unique_ptr<DarkModeImageClassifier>
-DarkModeImageClassifier::MakeBitmapImageClassifier() {
-  return std::make_unique<DarkModeBitmapImageClassifier>();
-}
-
-std::unique_ptr<DarkModeImageClassifier>
-DarkModeImageClassifier::MakeSVGImageClassifier() {
-  return std::make_unique<DarkModeSVGImageClassifier>();
-}
-
-std::unique_ptr<DarkModeImageClassifier>
-DarkModeImageClassifier::MakeGradientGeneratedImageClassifier() {
-  return std::make_unique<DarkModeGradientGeneratedImageClassifier>();
-}
-
 DarkModeClassification DarkModeImageClassifier::Classify(
     const PaintImage& paint_image,
     const SkRect& src,
@@ -163,7 +117,6 @@
   if (result != DarkModeClassification::kNotClassified)
     return result;
 
-  result = DoInitialClassification(dst);
   if (result != DarkModeClassification::kNotClassified) {
     cache->Add(image_id, src, result);
     return result;
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
index 73045d72..50d53f3 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
@@ -25,12 +25,8 @@
 // results is not threadsafe. So it can be used only in blink main thread.
 class PLATFORM_EXPORT DarkModeImageClassifier {
  public:
-  virtual ~DarkModeImageClassifier();
-
-  static std::unique_ptr<DarkModeImageClassifier> MakeBitmapImageClassifier();
-  static std::unique_ptr<DarkModeImageClassifier> MakeSVGImageClassifier();
-  static std::unique_ptr<DarkModeImageClassifier>
-  MakeGradientGeneratedImageClassifier();
+  DarkModeImageClassifier();
+  ~DarkModeImageClassifier();
 
   struct Features {
     // True if the image is in color, false if it is grayscale.
@@ -56,11 +52,6 @@
   // Removes cache identified by given |image_id|.
   static void RemoveCache(PaintImage::Id image_id);
 
- protected:
-  DarkModeImageClassifier();
-
-  virtual DarkModeClassification DoInitialClassification(const SkRect& dst) = 0;
-
  private:
   DarkModeClassification ClassifyWithFeatures(const Features& features);
   DarkModeClassification ClassifyUsingDecisionTree(const Features& features);
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
index 1a2ee13..709fb62 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
@@ -22,8 +22,7 @@
 class DarkModeImageClassifierTest : public testing::Test {
  public:
   DarkModeImageClassifierTest() {
-    dark_mode_image_classifier_ =
-        DarkModeImageClassifier::MakeBitmapImageClassifier();
+    dark_mode_image_classifier_ = std::make_unique<DarkModeImageClassifier>();
   }
 
   // Loads the image from |file_name|.
diff --git a/third_party/blink/renderer/platform/graphics/gradient_generated_image.h b/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
index 589bb5c3..1467cd05 100644
--- a/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
+++ b/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
@@ -43,8 +43,6 @@
 
   ~GradientGeneratedImage() override = default;
 
-  bool IsGradientGeneratedImage() const override { return true; }
-
   bool ApplyShader(PaintFlags&, const SkMatrix&) override;
 
  protected:
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index f3df15b..562d39c 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -62,25 +62,6 @@
 
 namespace blink {
 
-namespace {
-DarkModeFilter::ElementRole GetElementRoleForImage(Image* image) {
-  DCHECK(image);
-
-  if (image->IsBitmapImage())
-    return DarkModeFilter::ElementRole::kBitmapImage;
-
-  if (image->IsSVGImage() || image->IsSVGImageForContainer())
-    return DarkModeFilter::ElementRole::kSVGImage;
-
-  if (image->IsGradientGeneratedImage())
-    return DarkModeFilter::ElementRole::kGradientGeneratedImage;
-
-  // TODO(prashant.n): Check if remaining image types need to be treated
-  // separately.
-  return DarkModeFilter::ElementRole::kUnhandledImage;
-}
-}  // namespace
-
 // Helper class that copies |flags| only when dark mode is enabled.
 //
 // TODO(gilmanmh): Investigate removing const from |flags| in the calling
@@ -890,10 +871,10 @@
   image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src));
 
   // Do not classify the image if the element has any CSS filters.
-  if (!has_filter_property && dark_mode_filter_.IsDarkModeActive()) {
+  if (!has_filter_property && dark_mode_filter_.IsDarkModeActive() &&
+      dark_mode_filter_.AnalyzeShouldApplyToImage(src, dest)) {
     dark_mode_filter_.ApplyToImageFlagsIfNeeded(
-        src, dest, image->PaintImageForCurrentFrame(), &image_flags,
-        GetElementRoleForImage(image));
+        src, dest, image->PaintImageForCurrentFrame(), &image_flags);
   }
 
   image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation,
@@ -931,10 +912,11 @@
   image_flags.setFilterQuality(
       ComputeFilterQuality(image, dest.Rect(), src_rect));
 
-  if (dark_mode_filter_.IsDarkModeActive()) {
+  if (dark_mode_filter_.IsDarkModeActive() &&
+      dark_mode_filter_.AnalyzeShouldApplyToImage(src_rect, dest.Rect())) {
     dark_mode_filter_.ApplyToImageFlagsIfNeeded(
-        src_rect, dest.Rect(), image->PaintImageForCurrentFrame(), &image_flags,
-        GetElementRoleForImage(image));
+        src_rect, dest.Rect(), image->PaintImageForCurrentFrame(),
+        &image_flags);
   }
 
   bool use_shader = (visible_src == src_rect) &&
diff --git a/third_party/blink/renderer/platform/graphics/image.h b/third_party/blink/renderer/platform/graphics/image.h
index bb5e190..0ab24e7 100644
--- a/third_party/blink/renderer/platform/graphics/image.h
+++ b/third_party/blink/renderer/platform/graphics/image.h
@@ -87,11 +87,9 @@
       InterpolationQuality = kInterpolationNone);
 
   virtual bool IsSVGImage() const { return false; }
-  virtual bool IsSVGImageForContainer() const { return false; }
   virtual bool IsBitmapImage() const { return false; }
   virtual bool IsStaticBitmapImage() const { return false; }
   virtual bool IsPlaceholderImage() const { return false; }
-  virtual bool IsGradientGeneratedImage() const { return false; }
 
   virtual bool CurrentFrameKnownToBeOpaque() = 0;
 
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.cc b/third_party/blink/renderer/platform/heap/heap_stats_collector.cc
index 49eaf08..97590b9 100644
--- a/third_party/blink/renderer/platform/heap/heap_stats_collector.cc
+++ b/third_party/blink/renderer/platform/heap/heap_stats_collector.cc
@@ -200,12 +200,6 @@
   return foreground_marking_time() + background_marking_time();
 }
 
-double ThreadHeapStatsCollector::Event::marking_time_in_bytes_per_second()
-    const {
-  return marked_bytes ? marking_time().InMillisecondsF() / 1000 / marked_bytes
-                      : 0.0;
-}
-
 base::TimeDelta ThreadHeapStatsCollector::Event::gc_cycle_time() const {
   // Note that scopes added here also have to have a proper BlinkGCInV8Scope
   // scope if they are nested in a V8 scope.
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
index 081f4f0..344d439 100644
--- a/third_party/blink/renderer/platform/heap/heap_stats_collector.h
+++ b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
@@ -265,9 +265,6 @@
     // Overall time spent sweeping the heap.
     base::TimeDelta sweeping_time() const;
 
-    // Marking speed in bytes/s.
-    double marking_time_in_bytes_per_second() const;
-
     // Marked bytes collected during sweeping.
     size_t unique_id = -1;
     size_t marked_bytes = 0;
diff --git a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
index 2b5a7685..948cc8df 100644
--- a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
+++ b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h"
 
+#include "base/numerics/ranges.h"
+
 namespace blink {
 
 constexpr double MarkingSchedulingOracle::kEstimatedMarkingTimeMs;
@@ -51,10 +53,8 @@
 base::TimeDelta MarkingSchedulingOracle::GetMinimumStepDuration() {
   DCHECK_LT(0u, incrementally_marked_bytes_);
   DCHECK(!incremental_marking_time_so_far_.is_zero());
-  base::TimeDelta minimum_duration = incremental_marking_time_so_far_ *
-                                     kMinimumMarkedBytesInStep /
-                                     incrementally_marked_bytes_;
-  return minimum_duration;
+  return incremental_marking_time_so_far_ * kMinimumMarkedBytesInStep /
+         incrementally_marked_bytes_;
 }
 
 base::TimeDelta MarkingSchedulingOracle::GetNextIncrementalStepDurationForTask(
@@ -84,14 +84,12 @@
   // up" by marking (|expected_marked_bytes| - |actual_marked_bytes|).
   // Assuming constant marking speed, duration of the next incremental step
   // should be as follows:
-  double marking_time_to_catch_up_in_ms =
-      (expected_marked_bytes - actual_marked_bytes) *
-      incremental_marking_time_so_far_.InMillisecondsF() /
+  const base::TimeDelta marking_time_to_catch_up =
+      incremental_marking_time_so_far_ *
+      (expected_marked_bytes - actual_marked_bytes) /
       incrementally_marked_bytes_;
-  return std::min(
-      kMaximumIncrementalMarkingStepDuration,
-      std::max(minimum_duration, base::TimeDelta::FromMillisecondsD(
-                                     marking_time_to_catch_up_in_ms)));
+  return base::ClampToRange(marking_time_to_catch_up, minimum_duration,
+                            kMaximumIncrementalMarkingStepDuration);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/test/heap_stats_collector_test.cc b/third_party/blink/renderer/platform/heap/test/heap_stats_collector_test.cc
index 5ee689e..5e421f2 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_stats_collector_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_stats_collector_test.cc
@@ -364,20 +364,6 @@
             stats_collector.previous().atomic_pause_time());
 }
 
-TEST(ThreadHeapStatsCollectorTest, EventMarkingTimePerByteInS) {
-  ThreadHeapStatsCollector stats_collector;
-  stats_collector.NotifyMarkingStarted(BlinkGC::CollectionType::kMajor,
-                                       BlinkGC::GCReason::kForcedGCForTesting,
-                                       true /* is_forced_gc */);
-  stats_collector.IncreaseScopeTime(
-      ThreadHeapStatsCollector::kAtomicPauseMarkTransitiveClosure,
-      base::TimeDelta::FromSeconds(1));
-  stats_collector.NotifyMarkingCompleted(1000);
-  stats_collector.NotifySweepingCompleted();
-  EXPECT_DOUBLE_EQ(
-      .001, stats_collector.previous().marking_time_in_bytes_per_second());
-}
-
 TEST(ThreadHeapStatsCollectorTest, EventSweepingTime) {
   ThreadHeapStatsCollector stats_collector;
   stats_collector.NotifyMarkingStarted(BlinkGC::CollectionType::kMajor,
diff --git a/third_party/blink/renderer/platform/heap/test/write_barrier_perftest.cc b/third_party/blink/renderer/platform/heap/test/write_barrier_perftest.cc
index 5c2c187..bc61502 100644
--- a/third_party/blink/renderer/platform/heap/test/write_barrier_perftest.cc
+++ b/third_party/blink/renderer/platform/heap/test/write_barrier_perftest.cc
@@ -77,12 +77,10 @@
 
   // Reporting.
   auto reporter = SetUpReporter("member_write_performance");
-  reporter.AddResult(
-      kMetricWritesDuringGcRunsPerS,
-      static_cast<double>(kNumElements) / during_gc_duration.InSecondsF());
-  reporter.AddResult(
-      kMetricWritesOutsideGcRunsPerS,
-      static_cast<double>(kNumElements) / outside_gc_duration.InSecondsF());
+  reporter.AddResult(kMetricWritesDuringGcRunsPerS,
+                     kNumElements / during_gc_duration.InSecondsF());
+  reporter.AddResult(kMetricWritesOutsideGcRunsPerS,
+                     kNumElements / outside_gc_duration.InSecondsF());
   reporter.AddResult(kMetricRelativeSpeedDifferenceUnitless,
                      during_gc_duration / outside_gc_duration);
 }
diff --git a/third_party/blink/renderer/platform/heap_observer_list.h b/third_party/blink/renderer/platform/heap_observer_set.h
similarity index 83%
rename from third_party/blink/renderer/platform/heap_observer_list.h
rename to third_party/blink/renderer/platform/heap_observer_set.h
index ac3baf9..87e7db7 100644
--- a/third_party/blink/renderer/platform/heap_observer_list.h
+++ b/third_party/blink/renderer/platform/heap_observer_set.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_
 
 #include "base/auto_reset.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
 
-// A list of observers. Ensures list is not mutated while iterating. Observers
+// A set of observers. Ensures list is not mutated while iterating. Observers
 // are not retained.
 template <class ObserverType>
-class PLATFORM_EXPORT HeapObserverList {
+class PLATFORM_EXPORT HeapObserverSet {
   DISALLOW_NEW();
 
  public:
@@ -49,7 +49,8 @@
     observers_.clear();
   }
 
-  // Safely iterate over the registered lifecycle observers.
+  // Safely iterate over the registered lifecycle observers in an unpredictable
+  // order.
   //
   // Adding or removing observers is not allowed during iteration. The callable
   // will only be called synchronously inside ForEachObserver().
@@ -69,7 +70,7 @@
   void Trace(Visitor* visitor) const { visitor->Trace(observers_); }
 
  private:
-  using ObserverSet = HeapLinkedHashSet<WeakMember<ObserverType>>;
+  using ObserverSet = HeapHashSet<WeakMember<ObserverType>>;
 
   // TODO(keishi): Clean up iteration state once transition from
   // LifecycleObserver is complete.
@@ -88,4 +89,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_
diff --git a/third_party/blink/renderer/platform/heap_observer_list_test.cc b/third_party/blink/renderer/platform/heap_observer_set_test.cc
similarity index 69%
rename from third_party/blink/renderer/platform/heap_observer_list_test.cc
rename to third_party/blink/renderer/platform/heap_observer_set_test.cc
index 225ac271..04c5b14 100644
--- a/third_party/blink/renderer/platform/heap_observer_list_test.cc
+++ b/third_party/blink/renderer/platform/heap_observer_set_test.cc
@@ -24,7 +24,7 @@
  *
  */
 
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
@@ -37,12 +37,12 @@
  public:
   TestingNotifier() = default;
 
-  HeapObserverList<TestingObserver>& ObserverList() { return observer_list_; }
+  HeapObserverSet<TestingObserver>& ObserverList() { return observer_list_; }
 
   void Trace(Visitor* visitor) const { visitor->Trace(observer_list_); }
 
  private:
-  HeapObserverList<TestingObserver> observer_list_;
+  HeapObserverSet<TestingObserver> observer_list_;
 };
 
 class TestingObserver final : public GarbageCollected<TestingObserver> {
@@ -56,12 +56,12 @@
   int count_ = 0;
 };
 
-void Notify(HeapObserverList<TestingObserver>& observer_list) {
+void Notify(HeapObserverSet<TestingObserver>& observer_list) {
   observer_list.ForEachObserver(
       [](TestingObserver* observer) { observer->OnNotification(); });
 }
 
-TEST(HeapObserverListTest, AddRemove) {
+TEST(HeapObserverSetTest, AddRemove) {
   Persistent<TestingNotifier> notifier =
       MakeGarbageCollected<TestingNotifier>();
   Persistent<TestingObserver> observer =
@@ -79,7 +79,7 @@
   EXPECT_EQ(observer->Count(), 1);
 }
 
-TEST(HeapObserverListTest, HasObserver) {
+TEST(HeapObserverSetTest, HasObserver) {
   Persistent<TestingNotifier> notifier =
       MakeGarbageCollected<TestingNotifier>();
   Persistent<TestingObserver> observer =
@@ -94,7 +94,7 @@
   EXPECT_FALSE(notifier->ObserverList().HasObserver(observer.Get()));
 }
 
-TEST(HeapObserverListTest, GarbageCollect) {
+TEST(HeapObserverSetTest, GarbageCollect) {
   Persistent<TestingNotifier> notifier =
       MakeGarbageCollected<TestingNotifier>();
   Persistent<TestingObserver> observer =
@@ -111,7 +111,7 @@
   EXPECT_EQ(weak_ref.Get(), nullptr);
 }
 
-TEST(HeapObserverListTest, IsIteratingOverObservers) {
+TEST(HeapObserverSetTest, IsIteratingOverObservers) {
   Persistent<TestingNotifier> notifier =
       MakeGarbageCollected<TestingNotifier>();
   Persistent<TestingObserver> observer =
@@ -124,42 +124,4 @@
   });
 }
 
-TEST(HeapObserverListTest, ForEachObserverOrder) {
-  Persistent<TestingNotifier> notifier =
-      MakeGarbageCollected<TestingNotifier>();
-  Persistent<TestingObserver> observer1 =
-      MakeGarbageCollected<TestingObserver>();
-  Persistent<TestingObserver> observer2 =
-      MakeGarbageCollected<TestingObserver>();
-
-  HeapVector<Member<TestingObserver>> seen_observers;
-
-  notifier->ObserverList().AddObserver(observer1);
-  notifier->ObserverList().AddObserver(observer2);
-  notifier->ObserverList().ForEachObserver(
-      [&](TestingObserver* observer) { seen_observers.push_back(observer); });
-
-  ASSERT_EQ(2u, seen_observers.size());
-  EXPECT_EQ(observer1.Get(), seen_observers[0].Get());
-  EXPECT_EQ(observer2.Get(), seen_observers[1].Get());
-
-  seen_observers.clear();
-
-  notifier->ObserverList().RemoveObserver(observer1);
-  notifier->ObserverList().AddObserver(observer1);
-  notifier->ObserverList().ForEachObserver(
-      [&](TestingObserver* observer) { seen_observers.push_back(observer); });
-
-  ASSERT_EQ(2u, seen_observers.size());
-  EXPECT_EQ(observer2.Get(), seen_observers[0].Get());
-  EXPECT_EQ(observer1.Get(), seen_observers[1].Get());
-
-  seen_observers.clear();
-
-  notifier->ObserverList().Clear();
-  notifier->ObserverList().ForEachObserver(
-      [&](TestingObserver* observer) { seen_observers.push_back(observer); });
-  ASSERT_EQ(0u, seen_observers.size());
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
index eb6cdc3..2a1a5050 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
@@ -28,7 +28,7 @@
 
   if (mutable_body.StreamBody()) {
     auto out = blink::mojom::blink::FetchAPIDataElement::New();
-    out->type = network::mojom::DataElementType::kChunkedDataPipe;
+    out->type = network::mojom::DataElementType::kReadOnceStream;
     out->chunked_data_pipe_getter = mutable_body.TakeStreamBody();
     out_elements.push_back(std::move(out));
     return out_elements;
@@ -105,7 +105,7 @@
     if (!view.ReadType(&type)) {
       return false;
     }
-    if (type == network::mojom::DataElementType::kChunkedDataPipe) {
+    if (type == network::mojom::DataElementType::kReadOnceStream) {
       auto chunked_data_pipe_getter = view.TakeChunkedDataPipeGetter<
           mojo::PendingRemote<network::mojom::blink::ChunkedDataPipeGetter>>();
       *out = blink::ResourceRequestBody(std::move(chunked_data_pipe_getter));
@@ -162,6 +162,7 @@
       case network::mojom::DataElementType::kBlob:
       case network::mojom::DataElementType::kUnknown:
       case network::mojom::DataElementType::kChunkedDataPipe:
+      case network::mojom::DataElementType::kReadOnceStream:
       case network::mojom::DataElementType::kRawFile:
         NOTREACHED();
         return false;
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
index 3f3a945..b1050ec 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
@@ -358,7 +358,7 @@
     dest->request_body = base::MakeRefCounted<network::ResourceRequestBody>();
     mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>
         network_stream_body(stream_body.PassPipe(), 0u);
-    dest->request_body->SetToChunkedDataPipe(std::move(network_stream_body));
+    dest->request_body->SetToReadOnceStream(std::move(network_stream_body));
     dest->request_body->SetAllowHTTP1ForStreamingUpload(
         src.AllowHTTP1ForStreamingUpload());
   }
diff --git a/third_party/blink/renderer/platform/mojo/DEPS b/third_party/blink/renderer/platform/mojo/DEPS
index 2748153..5a7db27e 100644
--- a/third_party/blink/renderer/platform/mojo/DEPS
+++ b/third_party/blink/renderer/platform/mojo/DEPS
@@ -22,7 +22,7 @@
     "+third_party/blink/renderer/platform/wtf",
     "+third_party/blink/renderer/platform/context_lifecycle_observer.h",
     "+third_party/blink/renderer/platform/context_lifecycle_notifier.h",
-    "+third_party/blink/renderer/platform/heap_observer_list.h",
+    "+third_party/blink/renderer/platform/heap_observer_set.h",
     "+third_party/blink/renderer/platform/heap",
 ]
 
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
index ce48d2e..3dc9d88 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
@@ -15,7 +15,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
@@ -49,7 +49,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
index 7972a26..95811f1 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
@@ -41,7 +41,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
index 349c21b..f8b016d 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
@@ -41,7 +41,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 class ServiceImpl : public sample::blink::Service {
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
index 56c1394..c7fb431 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
@@ -15,7 +15,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
@@ -48,7 +48,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 template <HeapMojoWrapperMode Mode, typename ContextType>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
index f2a4475..94390be 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/features.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
@@ -45,7 +45,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
index 7547cb9..97b764b5 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/features.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
@@ -45,7 +45,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 class ServiceImpl : public sample::blink::Service {
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
index d9b2821..f3fe302 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap_observer_list.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
@@ -43,7 +43,7 @@
   }
 
  private:
-  HeapObserverList<ContextLifecycleObserver> observers_;
+  HeapObserverSet<ContextLifecycleObserver> observers_;
 };
 
 template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/network/network_state_notifier.cc b/third_party/blink/renderer/platform/network/network_state_notifier.cc
index 6c865ac5..32328e8 100644
--- a/third_party/blink/renderer/platform/network/network_state_notifier.cc
+++ b/third_party/blink/renderer/platform/network/network_state_notifier.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
 
 #include <memory>
+
 #include "net/nqe/effective_connection_type.h"
 #include "net/nqe/network_quality_estimator_params.h"
 #include "third_party/blink/public/common/client_hints/client_hints.h"
@@ -430,23 +431,19 @@
 uint32_t NetworkStateNotifier::RoundRtt(
     const String& host,
     const base::Optional<base::TimeDelta>& rtt) const {
-  // Limit the size of the buckets and the maximum reported value to reduce
-  // fingerprinting.
-  static const auto kGranularity = base::TimeDelta::FromMilliseconds(50);
-  static const auto kMaxRtt = base::TimeDelta::FromSeconds(3);
-
   if (!rtt.has_value()) {
     // RTT is unavailable. So, return the fastest value.
     return 0;
   }
 
-  base::TimeDelta modified_rtt = rtt.value();
-  modified_rtt *= GetRandomMultiplier(host);
-  modified_rtt = std::min(modified_rtt, kMaxRtt);
+  // Limit the maximum reported value and the granularity to reduce
+  // fingerprinting.
+  constexpr auto kMaxRtt = base::TimeDelta::FromSeconds(3);
+  constexpr auto kGranularity = base::TimeDelta::FromMilliseconds(50);
 
-  DCHECK_LE(base::TimeDelta(), modified_rtt);
-  DCHECK_GE(kMaxRtt, modified_rtt);
-
+  const base::TimeDelta modified_rtt =
+      std::min(rtt.value() * GetRandomMultiplier(host), kMaxRtt);
+  DCHECK_GE(modified_rtt, base::TimeDelta());
   return static_cast<uint32_t>(
       modified_rtt.RoundToMultiple(kGranularity).InMilliseconds());
 }
diff --git a/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc b/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
index 6b81b51..9022792 100644
--- a/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
+++ b/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
@@ -183,17 +183,16 @@
 
 scoped_refptr<Hyphenation> Hyphenation::PlatformGetHyphenation(
     const AtomicString& locale) {
-  scoped_refptr<HyphenationMinikin> hyphenation(
-      base::AdoptRef(new HyphenationMinikin));
-  if (hyphenation->OpenDictionary(locale.LowerASCII()))
-    return hyphenation;
-  hyphenation = nullptr;
-
   DEFINE_STATIC_LOCAL(LocaleMap, locale_fallback, (CreateLocaleFallbackMap()));
   const auto& it = locale_fallback.find(locale);
   if (it != locale_fallback.end())
     return LayoutLocale::Get(it->value)->GetHyphenation();
 
+  scoped_refptr<HyphenationMinikin> hyphenation(
+      base::AdoptRef(new HyphenationMinikin));
+  if (hyphenation->OpenDictionary(locale.LowerASCII()))
+    return hyphenation;
+
   return nullptr;
 }
 
diff --git a/third_party/blink/renderer/platform/timer_perf_test.cc b/third_party/blink/renderer/platform/timer_perf_test.cc
index 796af13a..5df1e5dc 100644
--- a/third_party/blink/renderer/platform/timer_perf_test.cc
+++ b/third_party/blink/renderer/platform/timer_perf_test.cc
@@ -57,7 +57,7 @@
 
   test::EnterRunLoop();
 
-  double posting_time = (post_end - post_start).InMicroseconds();
+  double posting_time = (post_end - post_start).InMicrosecondsF();
   double posting_time_us_per_call =
       posting_time / static_cast<double>(kNumIterations);
   LOG(INFO) << "TimerBase::startOneShot cost (us/call) "
@@ -99,13 +99,13 @@
 
   test::EnterRunLoop();
 
-  double posting_time = (post_end - post_start).InMicroseconds();
+  double posting_time = (post_end - post_start).InMicrosecondsF();
   double posting_time_us_per_call =
       posting_time / static_cast<double>(kNumIterations);
   LOG(INFO) << "TimerBase::startOneShot cost (us/call) "
             << posting_time_us_per_call << " (total " << posting_time << " us)";
 
-  double cancel_time = (cancel_end - cancel_start).InMicroseconds();
+  double cancel_time = (cancel_end - cancel_start).InMicrosecondsF();
   double cancel_time_us_per_call =
       cancel_time / static_cast<double>(kNumIterations);
   LOG(INFO) << "TimerBase::stop cost (us/call) " << cancel_time_us_per_call
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 0df20be..76f29eb 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2689,18 +2689,6 @@
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 external/wpt/dom/events/Event-dispatch-click.html [ Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/streams/readable-streams/tee.any.serviceworker.html [ Timeout ]
-crbug.com/626703 [ Mac ] external/wpt/streams/readable-streams/tee.any.serviceworker.html [ Timeout ]
-crbug.com/626703 [ Win ] external/wpt/streams/readable-streams/tee.any.serviceworker.html [ Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/streams/readable-streams/tee.any.sharedworker.html [ Timeout ]
-crbug.com/626703 [ Mac ] external/wpt/streams/readable-streams/tee.any.sharedworker.html [ Timeout ]
-crbug.com/626703 [ Win ] external/wpt/streams/readable-streams/tee.any.sharedworker.html [ Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/streams/readable-streams/tee.any.html [ Timeout ]
-crbug.com/626703 [ Mac ] external/wpt/streams/readable-streams/tee.any.html [ Timeout ]
-crbug.com/626703 [ Win ] external/wpt/streams/readable-streams/tee.any.html [ Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/streams/readable-streams/tee.any.worker.html [ Timeout ]
-crbug.com/626703 [ Mac ] external/wpt/streams/readable-streams/tee.any.worker.html [ Timeout ]
-crbug.com/626703 [ Win ] external/wpt/streams/readable-streams/tee.any.worker.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/input-events/input-events-get-target-ranges-backspace.tentative.html [ Timeout ]
 crbug.com/626703 [ Mac ] external/wpt/input-events/input-events-get-target-ranges-backspace.tentative.html [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/input-events/input-events-get-target-ranges-backspace.tentative.html [ Timeout ]
@@ -6750,3 +6738,6 @@
 
 # Sheriff 2020-08-14
 crbug.com/1116681 [ Mac ] fast/frames/iframe-scaling-with-scroll.html [ Pass Failure ]
+
+# Sheriff 2020-08-17
+crbug.com/1069546 [ Mac ] compositing/layer-creation/overflow-scroll-overlap.html [ Pass Failure ]
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 94870592..97cfc52 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -184083,11 +184083,11 @@
       []
      ],
      "range-percent-intrinsic-size-2-ref.html": [
-      "9a6e9287d96089912d00684166494e5dcb902b40",
+      "d98c8220164bcb92ada82f9799ba4da0e6425ea7",
       []
      ],
      "range-percent-intrinsic-size-2a-ref.html": [
-      "9aab2aede09aaaea2acb3fd5e3e98a6e70286fb3",
+      "11afa34a654ec071c00971b11a2261ff95397904",
       []
      ],
      "slice-intrinsic-size-ref.html": [
@@ -219400,16 +219400,6 @@
        []
       ]
      },
-     "mpadded": {
-      "mpadded-001-expected.txt": [
-       "f652024378226e188c8f1ef011e64a059d2ea432",
-       []
-      ],
-      "mpadded-003-expected.txt": [
-       "2b658e2389a02b7c7cd17ccfb17c002ef832d2c8",
-       []
-      ]
-     },
      "mrow": {
       "dynamic-mrow-like-001-ref.html": [
        "2f823ba9550d1c5a2cac2fe5b4b3bc5867a1be75",
@@ -238690,6 +238680,12 @@
      ]
     }
    },
+   "webcodecs": {
+    "pattern.png": [
+     "85676f29ff5806a32ac6713e601fdcb71dd03777",
+     []
+    ]
+   },
    "webdriver": {
     "META.yml": [
      "a397b497c32234d3889c738f51b96a3ba3b2a96f",
@@ -356831,7 +356827,7 @@
        ]
       ],
       "mpadded-002.html": [
-       "d376bd3da1f60d3f4c7e7b9294095e35598f853a",
+       "a5f77523e15ae745b57c1a355274554802dfc8cb",
        [
         null,
         {}
@@ -388369,7 +388365,7 @@
       ]
      ],
      "bad-underlying-sinks.any.js": [
-      "cf04e01b0c0c4daa0b193e46fee6583c0ed7cba1",
+      "0bfc036246a8709bd14117b252c1d186b8d8df0d",
       [
        null,
        {
@@ -402583,6 +402579,13 @@
     ]
    },
    "webcodecs": {
+    "video-encoder.html": [
+     "ce03f058f78ec551afc8024203f633e64cb1a29f",
+     [
+      null,
+      {}
+     ]
+    ],
     "video-track-reader.html": [
      "087e0bb935b6033876c9b7eed10274bab02d8910",
      [
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any-expected.txt
index 7fb3f0f..6b0a4ca 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any-expected.txt
@@ -12,6 +12,8 @@
 PASS ReadableStream teeing: erroring a teed stream should error both branches
 PASS ReadableStream teeing: closing the original should immediately close the branches
 PASS ReadableStream teeing: erroring the original should immediately error the branches
+PASS ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream
+PASS ReadableStream teeing: canceling branch1 should finish when original stream errors
 PASS ReadableStreamTee should not use a modified ReadableStream constructor from the global object
 FAIL ReadableStreamTee should not pull more chunks than can fit in the branch queue assert_array_equals: pull should only be called once lengths differ, expected array ["pull"] length 1, got ["pull", "pull"] length 2
 PASS ReadableStreamTee should only pull enough to fill the emptiest queue
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.serviceworker-expected.txt
index 7fb3f0f..6b0a4ca 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.serviceworker-expected.txt
@@ -12,6 +12,8 @@
 PASS ReadableStream teeing: erroring a teed stream should error both branches
 PASS ReadableStream teeing: closing the original should immediately close the branches
 PASS ReadableStream teeing: erroring the original should immediately error the branches
+PASS ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream
+PASS ReadableStream teeing: canceling branch1 should finish when original stream errors
 PASS ReadableStreamTee should not use a modified ReadableStream constructor from the global object
 FAIL ReadableStreamTee should not pull more chunks than can fit in the branch queue assert_array_equals: pull should only be called once lengths differ, expected array ["pull"] length 1, got ["pull", "pull"] length 2
 PASS ReadableStreamTee should only pull enough to fill the emptiest queue
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.sharedworker-expected.txt
index 7fb3f0f..6b0a4ca 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.sharedworker-expected.txt
@@ -12,6 +12,8 @@
 PASS ReadableStream teeing: erroring a teed stream should error both branches
 PASS ReadableStream teeing: closing the original should immediately close the branches
 PASS ReadableStream teeing: erroring the original should immediately error the branches
+PASS ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream
+PASS ReadableStream teeing: canceling branch1 should finish when original stream errors
 PASS ReadableStreamTee should not use a modified ReadableStream constructor from the global object
 FAIL ReadableStreamTee should not pull more chunks than can fit in the branch queue assert_array_equals: pull should only be called once lengths differ, expected array ["pull"] length 1, got ["pull", "pull"] length 2
 PASS ReadableStreamTee should only pull enough to fill the emptiest queue
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.worker-expected.txt
index 7fb3f0f..6b0a4ca 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/tee.any.worker-expected.txt
@@ -12,6 +12,8 @@
 PASS ReadableStream teeing: erroring a teed stream should error both branches
 PASS ReadableStream teeing: closing the original should immediately close the branches
 PASS ReadableStream teeing: erroring the original should immediately error the branches
+PASS ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream
+PASS ReadableStream teeing: canceling branch1 should finish when original stream errors
 PASS ReadableStreamTee should not use a modified ReadableStream constructor from the global object
 FAIL ReadableStreamTee should not pull more chunks than can fit in the branch queue assert_array_equals: pull should only be called once lengths differ, expected array ["pull"] length 1, got ["pull", "pull"] length 2
 PASS ReadableStreamTee should only pull enough to fill the emptiest queue
diff --git a/third_party/blink/web_tests/external/wpt/streams/writable-streams/bad-underlying-sinks.any.js b/third_party/blink/web_tests/external/wpt/streams/writable-streams/bad-underlying-sinks.any.js
index cf04e01..0bfc036 100644
--- a/third_party/blink/web_tests/external/wpt/streams/writable-streams/bad-underlying-sinks.any.js
+++ b/third_party/blink/web_tests/external/wpt/streams/writable-streams/bad-underlying-sinks.any.js
@@ -159,6 +159,24 @@
 
 test(() => {
   assert_throws_js(TypeError, () => new WritableStream({
+    start: 'test'
+  }), 'constructor should throw');
+}, 'start: non-function start method');
+
+test(() => {
+  assert_throws_js(TypeError, () => new WritableStream({
+    write: 'test'
+  }), 'constructor should throw');
+}, 'write: non-function write method');
+
+test(() => {
+  assert_throws_js(TypeError, () => new WritableStream({
+    close: 'test'
+  }), 'constructor should throw');
+}, 'close: non-function close method');
+
+test(() => {
+  assert_throws_js(TypeError, () => new WritableStream({
     abort: { apply() {} }
   }), 'constructor should throw');
 }, 'abort: non-function abort method with .apply');
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-format-style-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-format-style-expected.txt
deleted file mode 100644
index 5d9bc538..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-format-style-expected.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-CONSOLE MESSAGE: line 14: %cBlue!. color: blue;
-CONSOLE MESSAGE: line 15: %cBlue! %cRed! color: blue; color: red;
-CONSOLE MESSAGE: line 16: %cBlue!
-%cRed! color: blue; color: red;
-CONSOLE MESSAGE: line 17: %cwww.google.com color: blue
-CONSOLE WARNING: line 18: %cwww.google.com color: blue; background: blue
-CONSOLE ERROR: line 19: %cwww.google.com color: blue; background: blue
-CONSOLE MESSAGE: line 20: 12345678
-CONSOLE MESSAGE: line 21: %d%f%s%d%f%s%d%f 1 1.1 a 2 2.2 b 3 3.3
-Tests that console logging dumps properly styled messages.
-
-console-format-style.js:14 Blue!.
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
-console-format-style.js:15 Blue! Red!
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
-Styled text #1: contain: paint; display: inline-block; max-width: 100%; color: red;
-console-format-style.js:16 Blue!Red!
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
-Styled text #1: NO STYLES DEFINED
-Styled text #2: contain: paint; display: inline-block; max-width: 100%; color: blue;
-Styled text #3: contain: paint; display: inline-block; max-width: 100%; color: red;
-console-format-style.js:17 www.google.com
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
-Styled text #1: -webkit-text-stroke: 0px !important; text-decoration: underline !important; color: rgb(84, 84, 84) !important; background-color: rgb(255, 255, 255) !important;
-console-format-style.js:18 www.google.com
-onload @ console-format-style.js:18
-(anonymous) @ console-format-style.js:22
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue; background: blue;
-Styled text #1: -webkit-text-stroke: 0px !important; text-decoration: underline !important; color: rgb(84, 84, 84) !important; background-color: rgb(255, 251, 229) !important;
-console-format-style.js:19 www.google.com
-onload @ console-format-style.js:19
-(anonymous) @ console-format-style.js:22
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue; background: blue;
-Styled text #1: -webkit-text-stroke: 0px !important; text-decoration: underline !important; color: rgb(84, 84, 84) !important; background-color: rgb(255, 240, 240) !important;
-console-format-style.js:20 12345678
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: black;
-Styled text #1: contain: paint; display: inline-block; max-width: 100%; color: red;
-Styled text #2: contain: paint; display: inline-block; max-width: 100%; color: darkgray;
-Styled text #3: contain: paint; display: inline-block; max-width: 100%;
-Styled text #4: contain: paint; display: inline-block; max-width: 100%; background: black;
-Styled text #5: contain: paint; display: inline-block; max-width: 100%; background: red;
-Styled text #6: contain: paint; display: inline-block; max-width: 100%; background: darkgray;
-Styled text #7: contain: paint; display: inline-block; max-width: 100%;
-console-format-style.js:21 11.1a22.2b33.3
-Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: black;
-Styled text #1: contain: paint; display: inline-block; max-width: 100%; color: red;
-Styled text #2: contain: paint; display: inline-block; max-width: 100%; color: darkgray;
-Styled text #3: contain: paint; display: inline-block; max-width: 100%;
-Styled text #4: contain: paint; display: inline-block; max-width: 100%; background: black;
-Styled text #5: contain: paint; display: inline-block; max-width: 100%; background: red;
-Styled text #6: contain: paint; display: inline-block; max-width: 100%; background: darkgray;
-Styled text #7: contain: paint; display: inline-block; max-width: 100%;
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-group-click-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-group-click-expected.txt
deleted file mode 100644
index 81d900c..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-group-click-expected.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-CONSOLE MESSAGE: line 12: group with object [object Object]
-CONSOLE MESSAGE: line 13: Message inside group
-CONSOLE MESSAGE: line 14: console.groupEnd
-Tests that clicks on console.group target the appropriate element.
-
-
-Before
-console-group-click.js:12 group with object {x: 1}
-
-Click on the group
-console-group-click.js:12 group with object {x: 1}
-console-group-click.js:13 Message inside group
-
-Click on the object
-console-group-click.js:12 group with object {x: 1}x: 1__proto__: Object
-console-group-click.js:13 Message inside group
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-link-to-snippet-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-link-to-snippet-expected.txt
deleted file mode 100644
index 01f147a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-link-to-snippet-expected.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-CONSOLE MESSAGE: line 1: 239
-CONSOLE ERROR: line 2: 42
-CONSOLE ERROR: line 3: 0
-CONSOLE ERROR: line 4: false
-CONSOLE ERROR: line 5: null
-Test that link to snippet works.
-
-
-Running: testConsoleLogAndReturnMessageLocation
-name1:1 239
-name1:1 42
-
-Running: testSnippetSyntaxError
-Line Message was added: snippet:///name2 Error 'Uncaught SyntaxError: Unexpected token '}'':1:1
-name2:2 Uncaught SyntaxError: Unexpected token '}'
-
-Running: testConsoleErrorHighlight
-Line Message was added: snippet:///name3 Error '42':1:8
-Line Message was added: snippet:///name3 Error '-0':2:8
-Line Message was added: snippet:///name3 Error 'false':3:8
-Line Message was added: snippet:///name3 Error 'null':4:8
-name3:2 42
-(anonymous) @ name3:2
-name3:3 -0
-(anonymous) @ name3:3
-name3:4 false
-(anonymous) @ name3:4
-name3:5 null
-(anonymous) @ name3:5
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-linkify-relative-links-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-linkify-relative-links-expected.txt
deleted file mode 100644
index 6082bf1..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-linkify-relative-links-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-CONSOLE MESSAGE: line 10: Error with relative links
-    at (foo1.js:10:50)
-    at (//foo2.js:10:50)
-    at (/foo3.js:10:50)
-    at (../foo4.js:10:50)
-    at (./foo5.js:10:50)
-    at (./bar/foo6.js:10:50)
-Test that logging an error in console would linkify relative URLs
-
-console-linkify-relative-links.js:10 Error with relative links
-    at (foo1.js:10)
-    at (foo2.js:10)
-    at (:8000/foo3.js:10)
-    at (:8000/devtools/foo4.js:10)
-    at (foo5.js:10)
-    at (bar/foo6.js:10)
-Link: foo1.js:10, href: http://127.0.0.1:8000/devtools/resources/foo1.js
-Link: foo2.js:10, href: http://foo2.js
-Link: :8000/foo3.js:10, href: http://127.0.0.1:8000/foo3.js
-Link: :8000/devtools/foo4.js:10, href: http://127.0.0.1:8000/devtools/foo4.js
-Link: foo5.js:10, href: http://127.0.0.1:8000/devtools/resources/foo5.js
-Link: bar/foo6.js:10, href: http://127.0.0.1:8000/devtools/resources/bar/foo6.js
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
deleted file mode 100644
index 6d42fb9..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-CONSOLE MESSAGE: line 13: direct console.log()
-CONSOLE MESSAGE: line 7: framework log
-Tests console.log() anchor location when the skip-stack-frames feature is enabled.
-
-console-log-wrapped-in-framework.js:13 direct console.log()
-console-log-wrapped-in-framework.js:14 framework log
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-message-contains-async-stack-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-message-contains-async-stack-expected.txt
deleted file mode 100644
index 8d44c715..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-message-contains-async-stack-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected end of input
-Tests exception message with empty stack in console contains async stack trace.
-
-VM:1 Uncaught SyntaxError: Unexpected end of input
-setTimeout (async)
-(anonymous) @ console-message-cont…s-async-stack.js:14
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-table-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-table-expected.txt
deleted file mode 100644
index 25b819c..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-table-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-CONSOLE MESSAGE: [object Object],[object Object],[object Object],[object Object]
-CONSOLE MESSAGE: [object Object],[object Object],[object Object],[object Object]
-Tests that console.table is properly rendered on tables with more than 20 columns(maxColumnsToRender).
-
-HEADER (index) | b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 | b11 | b12 | b13 | b14 | a0 | a1 | a2 | a3 | a4 | 
-ROW "b0" | "b1" | "b2" | "b3" | "b4" | "b5" | "b6" | "b7" | "b8" | "b9" | "b10" | "b11" | "b12" | "b13" | "b14" | 
-ROW "b0" | "b1" | "b2" | "b3" | "b4" | "b5" | "b6" | "b7" | "b8" | "b9" | "b10" | "b11" | "b12" | "b13" | "b14" | "a0" | "a1" | "a2" | "a3" | "a4" | 
-ROW "b0" | "b1" | "b2" | "b3" | "b4" | "b5" | "b6" | "b7" | "b8" | "b9" | "b10" | "b11" | "b12" | "b13" | "b14" | 
-ROW "b0" | "b1" | "b2" | "b3" | "b4" | "b5" | "b6" | "b7" | "b8" | "b9" | "b10" | "b11" | "b12" | "b13" | "b14" | "a0" | "a1" | "a2" | "a3" | "a4" | 
-HEADER (index) | a0 | a1 | a2 | a3 | a4 | a5 | a6 | a7 | a8 | a9 | a10 | a11 | a12 | a13 | a14 | b0 | b1 | b2 | b3 | b4 | 
-ROW "a0" | "a1" | "a2" | "a3" | "a4" | "a5" | "a6" | "a7" | "a8" | "a9" | "a10" | "a11" | "a12" | "a13" | "a14" | "b0" | "b1" | "b2" | "b3" | "b4" | 
-ROW "b0" | "b1" | "b2" | "b3" | "b4" | 
-ROW "a0" | "a1" | "a2" | "a3" | "a4" | "a5" | "a6" | "a7" | "a8" | "a9" | "a10" | "a11" | "a12" | "a13" | "a14" | "b0" | "b1" | "b2" | "b3" | "b4" | 
-ROW "b0" | "b1" | "b2" | "b3" | "b4" | 
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-trace-in-eval-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-trace-in-eval-expected.txt
deleted file mode 100644
index 7af7cab..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/console-trace-in-eval-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-CONSOLE MESSAGE: line 5: console.trace
-Tests that when console.trace is called in eval'ed script ending with //# sourceURL=url it will dump a stack trace that will have the url as the script source. Bug 47252.
-
-evalURL.js:5 console.trace
-b @ evalURL.js:5
-a @ evalURL.js:10
-evalSource @ evalURL.js:13
-eval @ evalURL.js:14
-(anonymous) @ console-trace-in-eval.js:29
-setTimeout (async)
-doEvalSource @ console-trace-in-eval.js:28
-(anonymous) @ console-trace-in-eval.js:39
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt
deleted file mode 100644
index 26e2811e..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt
+++ /dev/null
@@ -1,342 +0,0 @@
-CONSOLE WARNING: line 26: warning
-CONSOLE MESSAGE: line 35: group
-CONSOLE MESSAGE: line 35: log child
-CONSOLE MESSAGE: line 51: before
-CONSOLE MESSAGE: line 51: text [object Object] [object Object]
-CONSOLE MESSAGE: line 51: after
-CONSOLE MESSAGE: line 74: before
-CONSOLE MESSAGE: line 74: text [object Object] [object Object]
-CONSOLE MESSAGE: line 74: after
-CONSOLE MESSAGE: line 117: before
-CONSOLE WARNING: line 117: warning [object Object]
-CONSOLE MESSAGE: line 117: after
-CONSOLE MESSAGE: line 167: before
-CONSOLE MESSAGE: line 167: [object HTMLDivElement]
-CONSOLE MESSAGE: line 167: after
-CONSOLE MESSAGE: line 181: before
-CONSOLE MESSAGE: line 181: [object Object]
-CONSOLE MESSAGE: line 199: [object Object]
-CONSOLE MESSAGE: line 199: after
-CONSOLE MESSAGE: line 226: [object Object]
-Tests that console artifacts can be expanded, collapsed via keyboard.
-
-
-Running: testExpandingTraces
-Evaluating: console.warn("warning")
-Message count: 1
-
-Force selecting index 0
-Viewport virtual selection: 0
-Is trace expanded: NO
-
-ArrowRight:
-Viewport virtual selection: 0
-Is trace expanded: YES
-
-ArrowLeft:
-Viewport virtual selection: 0
-Is trace expanded: NO
-
-Running: testExpandingGroups
-Evaluating: console.group("group"); console.log("log child");
-Message count: 2
-
-Force selecting index 0
-Viewport virtual selection: 0
-Is group expanded: YES
-console-key-expand.js:35 group
-console-key-expand.js:35 log child
-
-ArrowLeft:
-Viewport virtual selection: 0
-Is group expanded: NO
-console-key-expand.js:35 group
-
-ArrowRight:
-Viewport virtual selection: 0
-Is group expanded: YES
-console-key-expand.js:35 group
-console-key-expand.js:35 log child
-
-Running: testNavigateBetweenObjectsAndLogs
-Evaluating: console.log("before");console.log("text", obj1, obj2);console.log("after");
-Message count: 3
-
-Force selecting index 1
-Viewport virtual selection: 1
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:51 text {x: 1} {y: 2}
-
-ArrowRight:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {x: 1}
-
-ArrowDown:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {y: 2}
-
-ArrowDown:
-Viewport virtual selection: 1
-activeElement: SPAN.devtools-link
-active text: console-key-expand.js:51
-
-ArrowDown:
-Viewport virtual selection: 2
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:51 after
-
-ArrowUp:
-Viewport virtual selection: 1
-activeElement: SPAN.devtools-link
-active text: console-key-expand.js:51
-
-ArrowUp:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {y: 2}
-
-ArrowLeft:
-Viewport virtual selection: 1
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:51 text {x: 1} {y: 2}
-
-Running: testExpandingObjects
-Evaluating: console.log("before");console.log("text", obj1, obj2);console.log("after");
-Message count: 3
-
-Force selecting index 1
-Viewport virtual selection: 1
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:74 text {x: 1} {y: 2}
-
-ArrowRight:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {x: 1}
-
-ArrowRight:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected.expanded
-active text: {x: 1}
-
-ArrowDown:
-Viewport virtual selection: 1
-activeElement: LI.selected
-active text: x: 1
-
-ArrowDown:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {y: 2}
-
-ArrowRight:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected.expanded
-active text: {y: 2}
-
-ArrowDown:
-
-ArrowDown:
-
-ArrowDown:
-Viewport virtual selection: 2
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:74 after
-
-ArrowUp:
-
-ArrowUp:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.expanded.selected
-active text: {y: 2}
-
-ArrowLeft:
-Viewport virtual selection: 1
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {y: 2}
-
-ArrowLeft:
-Viewport virtual selection: 1
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:74 text {x: 1}x: 1 {y: 2}y: 2
-
-Running: testExpandingObjectInTrace
-Evaluating: console.log("before");console.warn("warning", obj1);console.log("after");
-Message count: 3
-
-Force selecting index 1
-Viewport virtual selection: 1
-Has object: collapsed
-Is trace expanded: NO
-activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected
-active text: console-key-expand.js:117 warning {x: 1}
-(anonymous) @ console-key-expand.js:117
-
-ArrowRight:
-Viewport virtual selection: 1
-Has object: collapsed
-Is trace expanded: YES
-activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected
-active text: console-key-expand.js:117 warning {x: 1}
-(anonymous) @ console-key-expand.js:117
-
-ArrowRight:
-Viewport virtual selection: 1
-Has object: collapsed
-Is trace expanded: YES
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {x: 1}
-
-ArrowRight:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: YES
-activeElement: LI.parent.object-properties-section-root-element.selected.expanded
-active text: {x: 1}
-
-ArrowDown:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: YES
-activeElement: LI.selected
-active text: x: 1
-
-ArrowDown:
-
-ArrowDown:
-
-ArrowDown:
-Viewport virtual selection: 2
-Has object: expanded
-Is trace expanded: YES
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:117 after
-
-ArrowUp:
-
-ArrowUp:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: YES
-activeElement: SPAN.devtools-link
-active text: console-key-expand.js:117
-
-ArrowUp:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: YES
-activeElement: LI.parent.object-properties-section-root-element.expanded.selected
-active text: {x: 1}
-
-ArrowUp:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: YES
-activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected
-active text: console-key-expand.js:117 warning {x: 1}x: 1
-(anonymous) @ console-key-expand.js:117
-
-ArrowLeft:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: NO
-activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected
-active text: console-key-expand.js:117 warning {x: 1}x: 1
-(anonymous) @ console-key-expand.js:117
-
-ArrowLeft:
-Viewport virtual selection: 1
-Has object: expanded
-Is trace expanded: NO
-activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected
-active text: console-key-expand.js:117 warning {x: 1}x: 1
-(anonymous) @ console-key-expand.js:117
-
-Running: testExpandingElement
-Evaluating: console.log("before");console.log(el);console.log("after");
-Message count: 3
-
-Force selecting index 1
-Viewport virtual selection: 1
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:167 <div>​…​</div>​
-
-ArrowDown:
-
-ArrowDown:
-Viewport virtual selection: 1
-activeElement: LI.parent.selected
-active text: <div>​…​</div>​
-
-ArrowRight:
-Viewport virtual selection: 1
-activeElement: LI.parent.selected.expanded
-active text: <div>​
-
-Running: testShiftTabShouldSelectLastObject
-Evaluating: console.log("before");console.log(obj1);
-Message count: 2
-Setting focus in prompt:
-
-Shift+Tab:
-
-ArrowUp:
-Viewport virtual selection: 1
-Has object: collapsed
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {x: 1}
-
-ArrowRight:
-Viewport virtual selection: 1
-Has object: expanded
-activeElement: LI.parent.object-properties-section-root-element.selected.expanded
-active text: {x: 1}
-
-Running: testArrowUpToFirstVisibleMessageShouldSelectLastObject
-Evaluating: console.log(obj1);console.log("after");
-Message count: 2
-Setting focus in prompt:
-
-Shift+Tab:
-
-ArrowUp:
-Viewport virtual selection: 1
-Has object: collapsed
-activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-expand.js:199 after
-
-ArrowUp:
-
-ArrowUp:
-Viewport virtual selection: 0
-Has object: collapsed
-activeElement: LI.parent.object-properties-section-root-element.selected
-active text: {x: 1}
-
-Running: testFocusLastChildInBigObjectShouldScrollIntoView
-Evaluating: console.log(bigObj);
-Message count: 1
-Setting focus in prompt:
-
-Shift+Tab:
-
-ArrowUp:
-
-ArrowRight:
-
-Tab:
-Viewport virtual selection: -1
-Has object: expanded
-activeElement: TEXTAREA
-
-Shift+Tab:
-
-ArrowUp:
-Viewport virtual selection: 0
-Has object: expanded
-activeElement: LI.parent.object-properties-section-root-element.expanded.selected
-active text: {a0: 0, a1: 1, a2: 2, a3: 3, a4: 4, …}
-Is at bottom: false, should stick: false
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/extensions/extensions-reload-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/extensions/extensions-reload-expected.txt
deleted file mode 100644
index 24bdb25d..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/extensions/extensions-reload-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-CONSOLE MESSAGE: 42
-Tests that webInspector.inspectedWindow.reload() successfully injects and preprocesses user's code upon reload
-
-Started extension.
-Running tests...
-RUNNING TEST: extension_testReloadInjectsCode
-Page reloaded.
-Page reloaded.
-With injected code: foo = 42
-Without injected code: foo = undefined
-RUNNING TEST: extension_testReloadInjectsCodeWithMessage
-Page reloaded.
-Source received:
-console.log(42)
-All tests done.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/indexeddb/resources-panel-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/indexeddb/resources-panel-expected.txt
deleted file mode 100644
index 864b6cb2e..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/indexeddb/resources-panel-expected.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-CONSOLE MESSAGE: line 49: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 49: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 49: InspectorTest.IndexedDB_callback3
-Tests IndexedDB tree element on resources panel.
-
-Expanded IndexedDB tree element.
-Dumping IndexedDB tree:
-    (empty)
-Creating database.
-Created database.
-Refreshing.
-Refreshed.
-Dumping IndexedDB tree:
-    database: testDatabase - http://127.0.0.1:8000
-        Object store: testObjectStore
-            Index: testIndexName
-Navigating to another security origin.
-Navigated to another security origin.
-Dumping IndexedDB tree:
-    (empty)
-Navigating back.
-Navigated back.
-Refreshing.
-Refreshed.
-Dumping IndexedDB tree:
-    database: testDatabase - http://127.0.0.1:8000
-        Object store: testObjectStore
-            Index: testIndexName
-Deleting database.
-Deleted database.
-Refreshing.
-Refreshed.
-Dumping IndexedDB tree:
-    (empty)
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/search/search-ignore-binary-files-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/search/search-ignore-binary-files-expected.txt
deleted file mode 100644
index aa63e1b..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/search/search-ignore-binary-files-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CONSOLE ERROR: line 6: Uncaught (in promise) ReferenceError: TestRunner is not defined
-Verify that search doesn't search in binary resources.
-
-Search result #1: uiSourceCode.url = http://127.0.0.1:8000/devtools/search/search-ignore-binary-files.js
-  search match #1: lineNumber = 17, lineContent = '    var searchConfig = new Search.SearchConfig('sources.search-in-files', 'AAAAAAA', true, false);'
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/sources/debugger/debugger-scope-resolve-this-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/sources/debugger/debugger-scope-resolve-this-expected.txt
deleted file mode 100644
index b0c0af8..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/http/tests/devtools/sources/debugger/debugger-scope-resolve-this-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-CONSOLE MESSAGE: line 7: [object Object]
-Tests resolving this object name via source maps.
-
-Set timer for test function.
-Script execution paused.
-
-Scope variables sidebar pane:
-Local
-    this: Foo {}
-Closure (Foo.bar)
-WindowGlobal
-    <section collapsed>
-Script execution resumed.
-
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 69be957..e081650a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -52697,6 +52697,8 @@
   <int value="1203" label="Show Emoji Suggestions"/>
   <int value="1204" label="Change System Language"/>
   <int value="1205" label="Offer Translation"/>
+  <int value="1206" label="Add Input Method"/>
+  <int value="1207" label="Spell Check"/>
   <int value="1300" label="Google Drive Connection"/>
   <int value="1400" label="Add Printer"/>
   <int value="1401" label="Saved Printers"/>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index b866834a..6f27d27 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -353,7 +353,7 @@
  <item id="webstore_install_helper" hash_code="25921771" type="0" content_hash_code="10206361" os_list="linux,windows" file_path="chrome/browser/extensions/webstore_install_helper.cc"/>
  <item id="webstore_installer" hash_code="18764319" type="0" content_hash_code="70871152" os_list="linux,windows" file_path="chrome/browser/extensions/webstore_installer.cc"/>
  <item id="webui_content_scripts_download" hash_code="100545943" type="0" content_hash_code="119898059" os_list="linux,windows" file_path="extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc"/>
- <item id="well_known_path_that_should_not_exist" hash_code="134618785" type="0" content_hash_code="55913167" os_list="linux,windows" file_path="chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc"/>
+ <item id="well_known_path_that_should_not_exist" hash_code="134618785" type="0" content_hash_code="55913167" os_list="linux,windows" file_path="components/password_manager/core/browser/well_known_change_password_state.cc"/>
  <item id="worker_script_load" hash_code="72087791" type="0" content_hash_code="24889169" os_list="linux,windows" file_path="content/browser/worker_host/worker_script_fetcher.cc"/>
  <item id="xmpp_signal_strategy" hash_code="88906454" type="0" deprecated="2019-07-16" content_hash_code="88958321" file_path=""/>
 </annotations>
diff --git a/ui/android/edge_effect.cc b/ui/android/edge_effect.cc
index 81d220b..bc09abc4 100644
--- a/ui/android/edge_effect.cc
+++ b/ui/android/edge_effect.cc
@@ -204,9 +204,8 @@
   if (IsFinished())
     return false;
 
-  const base::TimeDelta dt = current_time - start_time_;
-  const double t = std::min(dt / duration_, 1.);
-  const float interp = static_cast<float>(Damp(t, 1.));
+  const double t = std::min((current_time - start_time_) / duration_, 1.0);
+  const float interp = static_cast<float>(Damp(t, 1.0));
 
   glow_alpha_ = Lerp(glow_alpha_start_, glow_alpha_finish_, interp);
   glow_scale_y_ = Lerp(glow_scale_y_start_, glow_scale_y_finish_, interp);
@@ -222,8 +221,8 @@
         glow_alpha_start_ = glow_alpha_;
         glow_scale_y_start_ = glow_scale_y_;
 
-        glow_alpha_finish_ = 0.f;
-        glow_scale_y_finish_ = 0.f;
+        glow_alpha_finish_ = 0.0f;
+        glow_scale_y_finish_ = 0.0f;
         break;
       case STATE_PULL:
         state_ = STATE_PULL_DECAY;
@@ -234,8 +233,8 @@
         glow_scale_y_start_ = glow_scale_y_;
 
         // After pull, the glow should fade to nothing.
-        glow_alpha_finish_ = 0.f;
-        glow_scale_y_finish_ = 0.f;
+        glow_alpha_finish_ = 0.0f;
+        glow_scale_y_finish_ = 0.0f;
         break;
       case STATE_PULL_DECAY:
         state_ = STATE_RECEDE;
diff --git a/ui/base/prediction/linear_resampling.cc b/ui/base/prediction/linear_resampling.cc
index d066205..850e99c 100644
--- a/ui/base/prediction/linear_resampling.cc
+++ b/ui/base/prediction/linear_resampling.cc
@@ -13,19 +13,16 @@
 namespace {
 // Minimum time difference between last two consecutive events before attempting
 // to resample.
-constexpr base::TimeDelta kResampleMinDelta =
-    base::TimeDelta::FromMilliseconds(2);
+constexpr auto kResampleMinDelta = base::TimeDelta::FromMilliseconds(2);
 // Maximum time to predict forward from the last event, to avoid predicting too
 // far into the future. This time is further bounded by 50% of the last time
 // delta.
-constexpr base::TimeDelta kResampleMaxPrediction =
-    base::TimeDelta::FromMilliseconds(8);
+constexpr auto kResampleMaxPrediction = base::TimeDelta::FromMilliseconds(8);
 // Align events to a few milliseconds before frame_time. This is to make the
 // resampling either doing interpolation or extrapolating a closer future time
 // so that resampled result is more accurate and has less noise. This adds some
 // latency during resampling but a few ms should be fine.
-constexpr base::TimeDelta kResampleLatency =
-    base::TimeDelta::FromMilliseconds(5);
+constexpr auto kResampleLatency = base::TimeDelta::FromMilliseconds(5);
 
 // Get position at |sample_time| by linear interpolate/extrapolate a and b.
 inline gfx::PointF lerp(const InputPredictor::InputData& a,
diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc
index 1aa05fd..1aa2631 100644
--- a/ui/compositor/layer_animator_unittest.cc
+++ b/ui/compositor/layer_animator_unittest.cc
@@ -1210,7 +1210,7 @@
   // should be enormous. Arbitrarily choosing 1 minute as the threshold,
   // though a much smaller value would probably have sufficed.
   delta = base::TimeTicks::Now() - animator->last_step_time();
-  EXPECT_GT(60.0, delta.InSecondsF());
+  EXPECT_LT(delta, base::TimeDelta::FromMinutes(1));
 }
 
 //-------------------------------------------------------
@@ -3503,17 +3503,15 @@
   Layer root;
   compositor->SetRootLayer(&root);
 
-  constexpr base::TimeDelta kAnimationDuration =
-      base::TimeDelta::FromMilliseconds(50);
+  constexpr auto kAnimationDuration = base::TimeDelta::FromMilliseconds(50);
 
   // Draw enough frames so that missing the start frame number would cause the
   // reporter to always report 100% smoothness. 4 times of the expected
   // animation frames because somehow the refresh rate changes from 60fps to
   // 200fps when reporting.
-  const float frame_interval =
-      base::Time::kMillisecondsPerSecond / compositor->refresh_rate();
   const int kStartFrameNumber =
-      base::ClampFloor(kAnimationDuration.InMillisecondsF() / frame_interval) *
+      base::ClampFloor(kAnimationDuration.InSecondsF() *
+                       compositor->refresh_rate()) *
       4;
   while (compositor->activated_frame_count() < kStartFrameNumber) {
     compositor->ScheduleFullRedraw();
diff --git a/ui/events/gestures/physics_based_fling_curve.cc b/ui/events/gestures/physics_based_fling_curve.cc
index 74b1942..d480d7c4 100644
--- a/ui/events/gestures/physics_based_fling_curve.cc
+++ b/ui/events/gestures/physics_based_fling_curve.cc
@@ -4,6 +4,8 @@
 
 #include "ui/events/gestures/physics_based_fling_curve.h"
 
+#include <cmath>
+
 namespace {
 
 // These constants are defined based on UX experiment.
@@ -15,8 +17,8 @@
 const float kMaxCurveDurationForFling = 2.0f;
 const float kDefaultPhysicalDeceleration = 2.7559e-5f;  // inch/ms^2.
 
-inline gfx::Vector2dF GetPositionAtTime(const gfx::Vector2dF& end_point,
-                                        double progress) {
+inline gfx::Vector2dF GetPositionAtValue(const gfx::Vector2dF& end_point,
+                                         double progress) {
   return gfx::ScaleVector2d(end_point, progress);
 }
 
@@ -27,12 +29,9 @@
 }
 
 float GetOffset(float velocity, float deceleration, float duration) {
-  float position =
+  const float position =
       (std::abs(velocity) - deceleration * duration * 0.5) * duration;
-  if (velocity < 0.0f)
-    return -position;
-
-  return position;
+  return std::copysign(position, velocity);
 }
 
 gfx::Vector2dF GetDecelerationInPixelsPerMs2(
@@ -101,7 +100,8 @@
       bezier_(p1_.x(), p1_.y(), p2_.x(), p2_.y()),
       previous_time_delta_(base::TimeDelta()) {
   DCHECK(!velocity.IsZero());
-  CHECK(!std::isnan(velocity.x()) && !std::isnan(velocity.y()));
+  DCHECK(!std::isnan(velocity.x()));
+  DCHECK(!std::isnan(velocity.y()));
 }
 
 PhysicsBasedFlingCurve::~PhysicsBasedFlingCurve() = default;
@@ -111,38 +111,33 @@
                                                  gfx::Vector2dF* velocity) {
   DCHECK(offset);
   DCHECK(velocity);
-  base::TimeDelta elapsed_time = time - start_timestamp_;
+
+  const base::TimeDelta elapsed_time = time - start_timestamp_;
   if (elapsed_time < base::TimeDelta()) {
     *offset = gfx::Vector2dF();
     *velocity = gfx::Vector2dF();
     return true;
   }
 
-  bool still_active = true;
-  double x = elapsed_time / curve_duration_;
-  if (x < 1.0f) {
-    double progress = bezier_.Solve(x);
-    *offset = GetPositionAtTime(distance_, progress);
+  const double x = elapsed_time / curve_duration_;
+  const bool still_active = x < 1.0f;
+  if (still_active) {
+    const double progress = bezier_.Solve(x);
+    *offset = GetPositionAtValue(distance_, progress);
     *velocity = GetVelocityAtTime(*offset, prev_offset_,
                                   elapsed_time - previous_time_delta_);
     prev_offset_ = *offset;
     previous_time_delta_ = elapsed_time;
-    still_active = true;
   } else {
-    // At the end of animation, we should have travel distance equal to
-    // distance_
+    // At the end of animation, we should have traveled a distance equal to
+    // |distance_|.
     *offset = distance_;
     *velocity = gfx::Vector2dF();
-    still_active = false;
   }
 
   return still_active;
 }
 
-// This method calculate the curve duration and generate the control points for
-// bezier curve based on velocity and |distance_|. It calculate the slope based
-// on the input velocity (initial velocity), curve duration and |distance_|.
-// Slope is then used to configure the value of control points for curve.
 base::TimeDelta
 PhysicsBasedFlingCurve::CalculateDurationAndConfigureControlPoints(
     const gfx::Vector2dF& velocity) {
diff --git a/ui/events/gestures/physics_based_fling_curve.h b/ui/events/gestures/physics_based_fling_curve.h
index 392d834..c467ecf 100644
--- a/ui/events/gestures/physics_based_fling_curve.h
+++ b/ui/events/gestures/physics_based_fling_curve.h
@@ -52,6 +52,9 @@
   // increases the upper bound of the scroll distance for a fling.
   constexpr static int kDefaultBoundsMultiplier = 3;
 
+  // Calculates the curve duration and generates the control points for a bezier
+  // curve. The slope is based on the input initial |velocity|, calculated curve
+  // duration, and |distance_|. Returns the duration.
   base::TimeDelta CalculateDurationAndConfigureControlPoints(
       const gfx::Vector2dF& velocity);
 
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index ce95db8..dd1cf2a 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -107,12 +107,9 @@
 
   // Touchscreen: use TouchEventConverterEvdev.
   if (devinfo.HasTouchscreen()) {
-    std::unique_ptr<TouchEventConverterEvdev> converter(
-        new TouchEventConverterEvdev(std::move(fd), params.path, params.id,
-                                     devinfo, params.shared_palm_state,
-                                     params.dispatcher));
-    converter->Initialize(devinfo);
-    return std::move(converter);
+    return TouchEventConverterEvdev::Create(
+        std::move(fd), params.path, params.id, devinfo,
+        params.shared_palm_state, params.dispatcher);
   }
 
   // Graphics tablet
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
index afab037..3daca1f 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -138,6 +138,27 @@
 TouchEventConverterEvdev::~TouchEventConverterEvdev() {
 }
 
+// static
+std::unique_ptr<TouchEventConverterEvdev> TouchEventConverterEvdev::Create(
+    base::ScopedFD fd,
+    base::FilePath path,
+    int id,
+    const EventDeviceInfo& devinfo,
+    SharedPalmDetectionFilterState* shared_palm_state,
+    DeviceEventDispatcherEvdev* dispatcher) {
+  auto converter = std::make_unique<TouchEventConverterEvdev>(
+      std::move(fd), std::move(path), id, devinfo, shared_palm_state,
+      dispatcher);
+  converter->Initialize(devinfo);
+  if (!converter->GetTouchscreenSize().GetCheckedArea().IsValid()) {
+    LOG(WARNING) << "Ignoring touchscreen \"" << converter->input_device().name
+                 << "\" reporting invalid size "
+                 << converter->GetTouchscreenSize().ToString();
+    return nullptr;
+  }
+  return converter;
+}
+
 void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) {
   has_mt_ = info.HasMultitouch();
   has_pen_ = info.HasKeyEvent(BTN_TOOL_PEN);
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.h b/ui/events/ozone/evdev/touch_event_converter_evdev.h
index 82da9b0..276d71e 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.h
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -50,6 +50,14 @@
                            DeviceEventDispatcherEvdev* dispatcher);
   ~TouchEventConverterEvdev() override;
 
+  static std::unique_ptr<TouchEventConverterEvdev> Create(
+      base::ScopedFD fd,
+      base::FilePath path,
+      int id,
+      const EventDeviceInfo& devinfo,
+      SharedPalmDetectionFilterState* shared_palm_state,
+      DeviceEventDispatcherEvdev* dispatcher);
+
   // EventConverterEvdev:
   bool HasTouchscreen() const override;
   bool HasPen() const override;
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
index 5d59d971..4b74359 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
@@ -2290,4 +2291,18 @@
   EXPECT_FLOAT_EQ(14.f, in_progress_event.major);
   EXPECT_FLOAT_EQ(11.f, in_progress_event.minor);
 }
+
+// b/162596241
+TEST_F(TouchEventConverterEvdevTest, InvalidDimensions) {
+  EventDeviceInfo devinfo;
+  input_absinfo absinfo = {};
+  absinfo.maximum = 1 << 16;
+  devinfo.SetAbsInfo(ABS_X, absinfo);
+  devinfo.SetAbsInfo(ABS_MT_POSITION_X, absinfo);
+  devinfo.SetAbsInfo(ABS_Y, absinfo);
+  devinfo.SetAbsInfo(ABS_MT_POSITION_Y, absinfo);
+  EXPECT_FALSE(
+      TouchEventConverterEvdev::Create({}, base::FilePath(kTestDevicePath), 0,
+                                       devinfo, shared_palm_state(), nullptr));
+}
 }  // namespace ui
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js
index c87b256..ed06659 100644
--- a/ui/file_manager/file_manager/background/js/launcher_search.js
+++ b/ui/file_manager/file_manager/background/js/launcher_search.js
@@ -320,17 +320,12 @@
   createSearchResult_(entry) {
     // TODO(yawano): Use filetype_folder_shared.png for a shared
     //     folder.
-    // TODO(yawano): Add archive launcher filetype icon.
     let icon = FileType.getIcon(entry);
-    if (icon === 'UNKNOWN' || icon === 'archive') {
+
+    if (icon === 'UNKNOWN') {
       icon = 'generic';
     }
 
-    const useHighDpiIcon = window.devicePixelRatio > 1.0;
-    const iconUrl = chrome.runtime.getURL(
-        'foreground/images/launcher_filetypes/' +
-        (useHighDpiIcon ? '2x/' : '') + 'launcher_filetype_' + icon + '.png');
-
     // Hide extensions for hosted files.
     const title = FileType.isHosted(entry) ?
         entry.name.substr(
@@ -340,7 +335,7 @@
     return {
       itemId: entry.toURL(),
       title: title,
-      iconUrl: iconUrl,
+      iconType: icon,
       // Relevance is set as 2 for all results as a temporary
       // implementation. 2 is the middle value.
       // TODO(yawano): Implement practical relevance calculation.
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 066c882..5d4a99c 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1409,6 +1409,14 @@
 };
 
 /**
+ * Returns true if filters in Recents view is enabled.
+ * @return {boolean}
+ */
+util.isRecentsFilterEnabled = () => {
+  return loadTimeData.getBoolean('FILTERS_IN_RECENTS_ENABLED');
+};
+
+/**
  * Returns true when FilesZipMount feature is enabled.
  * TODO(crbug.com/912236) Remove once transition to new ZIP system is finished.
  * @return {boolean}
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 1239b66..62d63bc 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1403,6 +1403,15 @@
   color: rgb(168, 168, 168);
 }
 
+body.files-ng .dialog-footer cr-button[disabled],
+body.files-ng .dialog-footer cr-button[disabled]:hover,
+body.files-ng .dialog-footer button[disabled],
+body.files-ng .dialog-footer button[disabled]:hover {
+  background-color:
+      var(--cros-button-background-color-primary-disabled);
+  color: var(--cros-button-label-color-primary-disabled);
+}
+
 body:not(.files-ng) .dialog-footer .primary,
 body:not(.files-ng) .dialog-footer .primary:hover {
   background-color: rgb(51, 103, 214);
@@ -3697,6 +3706,37 @@
   z-index: 520;
 }
 
+/* File type filter buttons in Recents view.
+   TODO(fukino): The style is temporary. Revisit it before the feature is
+   shipped. */
+#file-type-filter-container {
+  display: flex;
+  font-size: 13px;
+  height: 30x;
+  margin-top: 5px;
+}
+
+.file-type-filter-button {
+  align-items: center;
+  border: 1px solid rgba(0, 0, 0, 15%);
+  border-radius: 20px;
+  box-sizing: border-box;
+  color: var(--google-grey-700);
+  cursor: pointer;
+  display: flex;
+  font-weight: 500;
+  height: 32px;
+  margin-inline-end: 3px;
+  margin-inline-start: 3px;
+  padding: 0 10px;
+}
+
+.file-type-filter-button.active {
+  background-color: var(--google-blue-50);
+  border: 1px solid transparent;
+  color: var(--google-blue-600);
+}
+
 /*
  * Preventing FOUC
  */
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_archive.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_archive.png
deleted file mode 100644
index a7e0336..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_archive.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png
deleted file mode 100644
index ab4e881..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png
deleted file mode 100644
index 81f2671..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png
deleted file mode 100644
index 711f385..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png
deleted file mode 100644
index ff90fa0..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png
deleted file mode 100644
index 3455f4b..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png
deleted file mode 100644
index 9ff4fbb..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png
deleted file mode 100644
index 2c66a9d3f..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gform.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gform.png
deleted file mode 100644
index 250b238..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gform.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gmap.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gmap.png
deleted file mode 100644
index ac91a69..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gmap.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png
deleted file mode 100644
index 300f038..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsite.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsite.png
deleted file mode 100644
index 5931e788..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsite.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png
deleted file mode 100644
index bb7b70c..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png
deleted file mode 100644
index d1c49764..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png
deleted file mode 100644
index b371d67..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png
deleted file mode 100644
index 599c208..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png
deleted file mode 100644
index 5de1dbe..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png
deleted file mode 100644
index 639a1b5..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_shared.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_shared.png
deleted file mode 100644
index c18c88c..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_shared.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png
deleted file mode 100644
index fe0a4cf..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_tini.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_tini.png
deleted file mode 100644
index 4f01d0b..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_tini.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png
deleted file mode 100644
index 1c9afd3..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png
deleted file mode 100644
index 6eebc26..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_archive.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_archive.png
deleted file mode 100644
index a782879..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_archive.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png
deleted file mode 100644
index 085e4b4..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png
deleted file mode 100644
index 4474ade1..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png
deleted file mode 100644
index c8cf7538..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png
deleted file mode 100644
index 947a5eb..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png
deleted file mode 100644
index 8955353a..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png
deleted file mode 100644
index 8320816..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png
deleted file mode 100644
index ca220760..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gform.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gform.png
deleted file mode 100644
index 2a11534..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gform.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gmap.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gmap.png
deleted file mode 100644
index 028a2f6e..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gmap.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png
deleted file mode 100644
index 9a7ccb0..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsite.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsite.png
deleted file mode 100644
index a0c8d5be..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsite.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png
deleted file mode 100644
index 97d0e5e..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png
deleted file mode 100644
index dbf0320..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png
deleted file mode 100644
index a0012c76..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png
deleted file mode 100644
index 76548fd..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png
deleted file mode 100644
index f698bba..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png
deleted file mode 100644
index 3f34037..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_shared.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_shared.png
deleted file mode 100644
index 497bbfd..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_shared.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png
deleted file mode 100644
index bbb8b179..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_tini.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_tini.png
deleted file mode 100644
index d93e6dd..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_tini.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png
deleted file mode 100644
index f76e9c5..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png
deleted file mode 100644
index c0c3a3f..0000000
--- a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 338795f9..9225f7db 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -45,6 +45,7 @@
     ":file_selection",
     ":file_tasks",
     ":file_transfer_controller",
+    ":file_type_filters_controller",
     ":file_watcher",
     ":folder_shortcuts_data_model",
     ":gear_menu_controller",
@@ -358,6 +359,7 @@
     ":empty_folder_controller",
     ":file_selection",
     ":file_transfer_controller",
+    ":file_type_filters_controller",
     ":folder_shortcuts_data_model",
     ":gear_menu_controller",
     ":import_controller",
@@ -488,6 +490,20 @@
   ]
 }
 
+js_library("file_type_filters_controller") {
+  deps = [
+    ":directory_model",
+    "//ui/file_manager/file_manager/common/js:files_app_entry_types",
+  ]
+}
+
+js_unittest("file_type_filters_controller_unittest") {
+  deps = [
+    ":file_type_filters_controller",
+    "//ui/webui/resources/js:webui_resource_test",
+  ]
+}
+
 js_library("file_watcher") {
   deps = [
     "//ui/file_manager/base/js:volume_manager_types",
@@ -847,6 +863,7 @@
     ":file_manager_commands_unittest",
     ":file_tasks_unittest",
     ":file_transfer_controller_unittest",
+    ":file_type_filters_controller_unittest",
     ":import_controller_unittest",
     ":list_thumbnail_loader_unittest",
     ":navigation_list_model_unittest",
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 21617c72..145ef44 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -259,6 +259,9 @@
     /** @private {?QuickViewController} */
     this.quickViewController_ = null;
 
+    /** @private {?FileTypeFiltersController} */
+    this.fileTypeFiltersController_ = null;
+
     /**
      * Records histograms of directory-changed event.
      * @private {?NavigationUma}
@@ -327,6 +330,12 @@
      * @private {?NavigationModelFakeItem}
      */
     this.fakeDriveItem_ = null;
+
+    /**
+     * A fake entry for Recents.
+     * @private {?FakeEntry}
+     */
+    this.recentEntry_ = null;
   }
 
   /**
@@ -1051,6 +1060,10 @@
         this.launchParams_.showAndroidPickerApps,
         this.launchParams_.includeAllFiles, this.launchParams_.typeList);
 
+    this.recentEntry_ = new FakeEntry(
+        str('RECENT_ROOT_LABEL'), VolumeManagerCommon.RootType.RECENT,
+        this.getSourceRestriction_());
+
     assert(this.launchParams_);
     this.selectionHandler_ = new FileSelectionHandler(
         assert(this.directoryModel_), assert(this.fileOperationManager_),
@@ -1121,6 +1134,13 @@
         this.metadataModel_, this.volumeManager_, this.fileFilter_,
         this.namingController_, this.selectionHandler_, this.launchParams_);
 
+    // Create file-type filter controller.
+    if (util.isRecentsFilterEnabled()) {
+      this.fileTypeFiltersController_ = new FileTypeFiltersController(
+          this.ui_.fileTypeFilterContainer, this.directoryModel_,
+          this.recentEntry_);
+    }
+
     return directoryTreePromise;
   }
 
@@ -1144,10 +1164,7 @@
                 !DialogType.isFolderDialog(this.launchParams_.type) ?
             new NavigationModelFakeItem(
                 str('RECENT_ROOT_LABEL'), NavigationModelItemType.RECENT,
-                new FakeEntry(
-                    str('RECENT_ROOT_LABEL'),
-                    VolumeManagerCommon.RootType.RECENT,
-                    this.getSourceRestriction_())) :
+                assert(this.recentEntry_)) :
             null,
         assert(this.directoryModel_), assert(this.androidAppListModel_));
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js
new file mode 100644
index 0000000..01846fa
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js
@@ -0,0 +1,125 @@
+// Copyright 2020 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.
+
+/**
+ * This class controls wires file-type filter UI and the filter settings in
+ * Recents view.
+ */
+class FileTypeFiltersController {
+  /**
+   * @param {!HTMLElement} fileTypeFilterContainer
+   * @param {!DirectoryModel} directoryModel
+   * @param {!FakeEntry} recentEntry
+   */
+  constructor(fileTypeFilterContainer, directoryModel, recentEntry) {
+    /**
+     * @private {!HTMLElement}
+     * @const
+     */
+    this.container_ = fileTypeFilterContainer;
+
+    /**
+     * @private {!DirectoryModel}
+     * @const
+     */
+    this.directoryModel_ = directoryModel;
+
+    /**
+     * @private {!FakeEntry}
+     * @const
+     */
+    this.recentEntry_ = recentEntry;
+
+    /**
+     * @private {!HTMLElement}
+     * @const
+     */
+    this.audioFilterButton_ =
+        this.createFilterButton_(str('MEDIA_VIEW_AUDIO_ROOT_LABEL'));
+
+    /**
+     * @private {!HTMLElement}
+     * @const
+     */
+    this.imageFilterButton_ =
+        this.createFilterButton_(str('MEDIA_VIEW_IMAGES_ROOT_LABEL'));
+
+    /**
+     * @private {!HTMLElement}
+     * @const
+     */
+    this.videoFilterButton_ =
+        this.createFilterButton_(str('MEDIA_VIEW_VIDEOS_ROOT_LABEL'));
+
+    this.directoryModel_.addEventListener(
+        'directory-changed', this.onCurrentDirectoryChanged_.bind(this));
+  }
+
+  /**
+   * Creates filter button's UI element.
+   * @param {string} label Label of the filter button.
+   * @private
+   */
+  createFilterButton_(label) {
+    const button = util.createChild(this.container_, 'file-type-filter-button');
+    button.textContent = label;
+    button.onclick = this.onFilterButtonClicked_.bind(this);
+    return button;
+  }
+
+  /**
+   * Updates the UI when the current directory changes.
+   * @param {!Event} event Event.
+   * @private
+   */
+  onCurrentDirectoryChanged_(event) {
+    // We show filter buttons only in Recents view at this moment.
+    this.container_.hidden = !(event.newDirEntry == this.recentEntry_);
+    // Reset the filter buttons' active state on leaving Recents view.
+    if (event.previousDirEntry == this.recentEntry_ &&
+        event.newDirEntry != this.recentEntry_) {
+      this.audioFilterButton_.classList.toggle('active', false);
+      this.imageFilterButton_.classList.toggle('active', false);
+      this.videoFilterButton_.classList.toggle('active', false);
+    }
+  }
+
+  /**
+   * Updates the UI when one of the filter buttons is clicked.
+   * @param {Event} event Event.
+   * @private
+   */
+  onFilterButtonClicked_(event) {
+    // Toggle active state of clicked filter. When one filter button is clicked,
+    // other filter buttons should become inactive.
+    this.audioFilterButton_.classList.toggle(
+        'active', event.target == this.audioFilterButton_ ? undefined : false);
+    this.imageFilterButton_.classList.toggle(
+        'active', event.target == this.imageFilterButton_ ? undefined : false);
+    this.videoFilterButton_.classList.toggle(
+        'active', event.target == this.videoFilterButton_ ? undefined : false);
+    this.refreshRecentView_();
+  }
+
+  /**
+   * Refreshes the current directory based on the filter settings.
+   * @private
+   */
+  refreshRecentView_() {
+    // Update the Recent entry's setting based on the 'active' state of
+    // filter buttons.
+    let fileType = chrome.fileManagerPrivate.RecentFileType.ALL;
+    if (this.audioFilterButton_.classList.contains('active')) {
+      fileType = chrome.fileManagerPrivate.RecentFileType.AUDIO;
+    } else if (this.imageFilterButton_.classList.contains('active')) {
+      fileType = chrome.fileManagerPrivate.RecentFileType.IMAGE;
+    } else if (this.videoFilterButton_.classList.contains('active')) {
+      fileType = chrome.fileManagerPrivate.RecentFileType.VIDEO;
+    }
+    this.recentEntry_.recentFileType = fileType;
+    // Refresh current directory with the updated Recent setting.
+    // We don't need to invalidate the cached metadata for this rescan.
+    this.directoryModel_.rescan(false);
+  }
+}
diff --git a/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.js
new file mode 100644
index 0000000..ef28d317a
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.js
@@ -0,0 +1,217 @@
+// Copyright 2020 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.
+
+/**
+ * @type {!HTMLElement}
+ */
+let container;
+
+/**
+ * @type {!DirectoryModel}
+ */
+let directoryModel;
+
+/**
+ * @type {!FakeEntry}
+ */
+let recentEntry;
+
+/**
+ * @type {!EntryList}
+ */
+let myFilesEntry;
+
+/**
+ * @type {!FileTypeFiltersController}
+ */
+let fileTypeFiltersController;
+
+function setUp() {
+  // Mock loadTimeData strings.
+  window.loadTimeData.data = {
+    MEDIA_VIEW_AUDIO_ROOT_LABEL: 'Audio',
+    MEDIA_VIEW_IMAGES_ROOT_LABEL: 'Images',
+    MEDIA_VIEW_VIDEOS_ROOT_LABEL: 'Videos',
+  };
+
+  class MockDirectoryModel extends cr.EventTarget {
+    constructor() {
+      super();
+
+      this.currentDirEntry = null;
+      window.isRescanCalled = false;
+    }
+
+    rescan(refresh) {
+      window.isRescanCalled = true;
+    }
+
+    changeDirectoryEntry(dirEntry) {
+      // Change the directory model's current directory to |dirEntry|.
+      const previousDirEntry = this.currentDirEntry;
+      this.currentDirEntry = dirEntry;
+
+      // Emit 'directory-changed' event synchronously to simplify testing.
+      const event = new Event('directory-changed');
+      event.previousDirEntry = previousDirEntry;
+      event.newDirEntry = this.currentDirEntry;
+      this.dispatchEvent(event);
+    }
+
+    static create() {
+      const model = /** @type {!Object} */ (new MockDirectoryModel());
+      return /** @type {!DirectoryModel} */ (model);
+    }
+  }
+
+  // Create FileTypeFiltersController instance with dependencies.
+  container = /** @type {!HTMLInputElement} */ (document.createElement('div'));
+  directoryModel = MockDirectoryModel.create();
+  recentEntry = new FakeEntry(
+      'Recent', VolumeManagerCommon.RootType.RECENT,
+      chrome.fileManagerPrivate.SourceRestriction.ANY_SOURCE);
+  fileTypeFiltersController =
+      new FileTypeFiltersController(container, directoryModel, recentEntry);
+
+  // Create a directory entry which is not Recents to simulate directory change.
+  myFilesEntry =
+      new EntryList('My Files', VolumeManagerCommon.RootType.MY_FILES);
+}
+
+/**
+ * Tests that creating FileTypeFiltersController generates three buttons in the
+ * given container element.
+ */
+function testCreatedButtonLabels() {
+  const buttons = container.children;
+  assertEquals(buttons.length, 3);
+
+  assertEquals(buttons[0].textContent, 'Audio');
+  assertEquals(buttons[1].textContent, 'Images');
+  assertEquals(buttons[2].textContent, 'Videos');
+}
+
+/**
+ * Tests that initial states of all buttons inside container are inactive.
+ */
+function testButtonInitialActiveState() {
+  const buttons = container.children;
+  assertEquals(buttons.length, 3);
+
+  assertFalse(buttons[0].classList.contains('active'));
+  assertFalse(buttons[0].classList.contains('active'));
+  assertFalse(buttons[0].classList.contains('active'));
+}
+
+/**
+ * Tests that click events toggle button state (inactive -> active -> inactive).
+ */
+function testButtonToggleState() {
+  const buttons = container.children;
+  assertEquals(buttons.length, 3);
+
+  assertFalse(buttons[0].classList.contains('active'));
+  buttons[0].click();
+  assertTrue(buttons[0].classList.contains('active'));
+  buttons[0].click();
+  assertFalse(buttons[0].classList.contains('active'));
+}
+
+/**
+ * Tests that only one button can be inactive.
+ * If button_1 is clicked then button_0 is active, button_0 becomes inactive and
+ * button_1 becomes active.
+ */
+function testOnlyOneButtonCanActive() {
+  const buttons = container.children;
+  assertEquals(buttons.length, 3);
+
+  assertFalse(buttons[0].classList.contains('active'));
+  buttons[0].click();
+  assertTrue(buttons[0].classList.contains('active'));
+  assertFalse(buttons[1].classList.contains('active'));
+  assertFalse(buttons[2].classList.contains('active'));
+
+  buttons[1].click();
+  assertFalse(buttons[0].classList.contains('active'));
+  assertTrue(buttons[1].classList.contains('active'));
+  assertFalse(buttons[2].classList.contains('active'));
+
+  buttons[2].click();
+  assertFalse(buttons[0].classList.contains('active'));
+  assertFalse(buttons[1].classList.contains('active'));
+  assertTrue(buttons[2].classList.contains('active'));
+}
+
+/**
+ * Tests that container element is visible only when the current directory is
+ * Recents view.
+ */
+function testContainerIsShownOnlyInRecents() {
+  container.hidden = true;
+  directoryModel.changeDirectoryEntry(recentEntry);
+  assertFalse(container.hidden);
+  directoryModel.changeDirectoryEntry(myFilesEntry);
+  assertTrue(container.hidden);
+}
+
+/**
+ * Tests that button's active state is reset to inactive when the user leaves
+ * Recents view.
+ */
+function testActiveButtonIsResetOnLeavingRecents() {
+  const buttons = container.children;
+  assertEquals(buttons.length, 3);
+
+  directoryModel.changeDirectoryEntry(recentEntry);
+
+  buttons[0].click();
+  assertTrue(buttons[0].classList.contains('active'));
+  assertFalse(buttons[1].classList.contains('active'));
+  assertFalse(buttons[2].classList.contains('active'));
+
+  directoryModel.changeDirectoryEntry(myFilesEntry);
+  assertFalse(buttons[0].classList.contains('active'));
+  assertFalse(buttons[1].classList.contains('active'));
+  assertFalse(buttons[2].classList.contains('active'));
+}
+
+/**
+ * Tests that the active state of each button is reflected to the Recent entry's
+ * recentFileType property, and DirectoryModel.rescan() is called after the
+ * Recent entry's property is modified.
+ */
+function testAppliedFilters() {
+  const buttons = container.children;
+  assertEquals(buttons.length, 3);
+
+  directoryModel.changeDirectoryEntry(recentEntry);
+
+  buttons[0].click();
+  assertEquals(
+      recentEntry.recentFileType,
+      chrome.fileManagerPrivate.RecentFileType.AUDIO);
+  assertTrue(window.isRescanCalled);
+  window.isRescanCalled = false;
+
+  buttons[1].click();
+  assertEquals(
+      recentEntry.recentFileType,
+      chrome.fileManagerPrivate.RecentFileType.IMAGE);
+  assertTrue(window.isRescanCalled);
+  window.isRescanCalled = false;
+
+  buttons[2].click();
+  assertEquals(
+      recentEntry.recentFileType,
+      chrome.fileManagerPrivate.RecentFileType.VIDEO);
+  assertTrue(window.isRescanCalled);
+  window.isRescanCalled = false;
+
+  buttons[2].click();
+  assertEquals(
+      recentEntry.recentFileType, chrome.fileManagerPrivate.RecentFileType.ALL);
+  assertTrue(window.isRescanCalled);
+  window.isRescanCalled = false;
+}
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index 42df2a4..78375ce8 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -122,6 +122,7 @@
 // <include src="file_selection.js">
 // <include src="file_tasks.js">
 // <include src="file_transfer_controller.js">
+// <include src="file_type_filters_controller.js">
 // <include src="file_watcher.js">
 // <include src="folder_shortcuts_data_model.js">
 // <include src="sort_menu_controller.js">
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index 23e8c9e..9242a9c 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -565,7 +565,7 @@
 
     if (this.recentModelItem_) {
       this.navigationItems_.push(this.recentModelItem_);
-      if (util.isUnifiedMediaViewEnabled()) {
+      if (util.isUnifiedMediaViewEnabled() && !util.isRecentsFilterEnabled()) {
         // Unified Media View (Images, Videos and Audio).
         this.navigationItems_.push(createFilteredRecentModelItem(
             str('MEDIA_VIEW_AUDIO_ROOT_LABEL'),
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index 90725d6..8422e61 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -374,6 +374,13 @@
         /** @type {!FilesToast} */ (document.querySelector('files-toast'));
 
     /**
+     * Container of file-type filter buttons.
+     * @const {!HTMLElement}
+     */
+    this.fileTypeFilterContainer =
+        queryRequiredElement('#file-type-filter-container', this.element);
+
+    /**
      * A hidden div that can be used to announce text to screen
      * reader/ChromeVox.
      * @private {!HTMLElement}
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 2802fa3a..01e6acd8 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -533,6 +533,7 @@
               </div>
               <div class="downloads-warning" hidden></div>
               <files-message id='files-message' hidden></files-message>
+              <div id="file-type-filter-container" hidden></div>
               <div id="list-container" role="main">
                 <div id="more-actions-info" hidden>$i18n{SEE_MENU_FOR_ACTIONS}</div>
                 <div id="sort-column-asc" hidden>$i18n{COLUMN_ASC_SORT_MESSAGE}</div>
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index 32c3ade..09c49296 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -100,52 +100,6 @@
       <include name="IDR_FILE_MANAGER_GALLERY_ICON_192" file="gallery/images/icon192.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_GALLERY_ICON_256" file="gallery/images/icon256.png" type="BINDATA" />
 
-      <!-- Resources used for file type icon in launcher search result. -->
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_AUDIO" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_ARCHIVE" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_archive.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_CHART" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_EXCEL" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_FOLDER" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GDOC" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GDRAW" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GENERIC" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GFORM" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gform.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GMAP" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gmap.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GSHEET" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GSITE" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsite.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GSLIDES" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GTABLE" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_IMAGE" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_PDF" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_PPT" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_SCRIPT" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_SITES" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_TINI" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_tini.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_VIDEO" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_WORD" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_AUDIO" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_ARCHIVE" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_archive.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_CHART" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_EXCEL" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_FOLDER" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GDOC" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GDRAW" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GENERIC" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GFORM" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gform.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GMAP" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gmap.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSHEET" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSITE" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsite.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSLIDES" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GTABLE" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_IMAGE" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PDF" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PPT" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_SCRIPT" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_SITES" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_TINI" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_tini.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_VIDEO" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_WORD" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png" type="BINDATA" />
-
       <!-- Resources used for non-flattened HTML files. -->
       <include name="IDR_FILE_MANAGER_DRIVE_WELCOME_STYLE" file="file_manager/foreground/css/drive_welcome.css" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_IMG_UI_CLOUDS" file="file_manager/foreground/images/files/ui/clouds.png" type="BINDATA" />
diff --git a/ui/gfx/animation/linear_animation.cc b/ui/gfx/animation/linear_animation.cc
index f17a3f3..3d8d29e 100644
--- a/ui/gfx/animation/linear_animation.cc
+++ b/ui/gfx/animation/linear_animation.cc
@@ -45,8 +45,7 @@
 
 void LinearAnimation::SetCurrentValue(double new_value) {
   new_value = base::ClampToRange(new_value, 0.0, 1.0);
-  base::TimeDelta time_delta = base::TimeDelta::FromMicroseconds(
-      static_cast<int64_t>(duration_.InMicroseconds() * (new_value - state_)));
+  const base::TimeDelta time_delta = duration_ * (new_value - state_);
   SetStartTime(start_time() - time_delta);
   state_ = new_value;
 }
@@ -72,18 +71,13 @@
                ? animation_duration_scale
                : 1.0;
   }();
-  duration_ = duration * duration_scale_factor;
-  if (duration_ < timer_interval())
-    duration_ = timer_interval();
+  duration_ = std::max(duration * duration_scale_factor, timer_interval());
   if (is_animating())
     SetStartTime(container()->last_tick_time());
 }
 
 void LinearAnimation::Step(base::TimeTicks time_now) {
-  base::TimeDelta elapsed_time = time_now - start_time();
-  state_ = elapsed_time / duration_;
-  if (state_ >= 1.0)
-    state_ = 1.0;
+  state_ = std::min((time_now - start_time()) / duration_, 1.0);
 
   AnimateToState(state_);
 
diff --git a/ui/gfx/paint_throbber.cc b/ui/gfx/paint_throbber.cc
index 8b02c44..e6f6f208 100644
--- a/ui/gfx/paint_throbber.cc
+++ b/ui/gfx/paint_throbber.cc
@@ -95,12 +95,12 @@
   // The sweep angle ranges from -270 to 270 over 1333ms. CSS
   // animation timing functions apply in between key frames, so we have to
   // break up the 1333ms into two keyframes (-270 to 0, then 0 to 270).
-  const double arc_progress = (elapsed_time % kArcTime) / kArcTime;
+  const double elapsed_ratio = elapsed_time / kArcTime;
+  const int64_t sweep_frame = base::ClampFloor<int64_t>(elapsed_ratio);
+  const double arc_progress = elapsed_ratio - sweep_frame;
   // This tween is equivalent to cubic-bezier(0.4, 0.0, 0.2, 1).
   double sweep = kMaxArcSize *
                  Tween::CalculateValue(Tween::FAST_OUT_SLOW_IN, arc_progress);
-  const int64_t sweep_frame =
-      base::ClampFloor<int64_t>(elapsed_time / kArcTime);
   if (sweep_frame % 2 == 0)
     sweep -= kMaxArcSize;
 
@@ -160,13 +160,13 @@
   if (waiting_state->arc_time_offset.is_zero()) {
     for (int64_t arc_ms = 0; arc_ms <= kArcTime.InMillisecondsRoundedUp();
          ++arc_ms) {
-      double arc_size_progress =
-          std::min(1.0, arc_ms / kArcTime.InMillisecondsF());
+      const base::TimeDelta arc_time =
+          std::min(base::TimeDelta::FromMilliseconds(arc_ms), kArcTime);
       if (kMaxArcSize * Tween::CalculateValue(Tween::FAST_OUT_SLOW_IN,
-                                              arc_size_progress) >=
+                                              arc_time / kArcTime) >=
           waiting_sweep) {
         // Add kArcTime to sidestep the |sweep_keyframe == 0| offset below.
-        waiting_state->arc_time_offset = kArcTime * (arc_size_progress + 1);
+        waiting_state->arc_time_offset = kArcTime + arc_time;
         break;
       }
     }
diff --git a/ui/gfx/skia_vector_animation.cc b/ui/gfx/skia_vector_animation.cc
index a39ea1d..63966d00 100644
--- a/ui/gfx/skia_vector_animation.cc
+++ b/ui/gfx/skia_vector_animation.cc
@@ -82,8 +82,7 @@
 }
 
 base::TimeDelta SkiaVectorAnimation::GetAnimationDuration() const {
-  return base::TimeDelta::FromMilliseconds(
-      std::floor(SkScalarToFloat(skottie_->duration()) * 1000.f));
+  return base::TimeDelta::FromSecondsD(skottie_->duration());
 }
 
 gfx::Size SkiaVectorAnimation::GetOriginalSize() const {
@@ -148,13 +147,11 @@
       DCHECK(timer_control_);
       return timer_control_->GetNormalizedEndOffset();
     case PlayState::kPaused:
-      if (timer_control_) {
-        return timer_control_->GetNormalizedCurrentCycleProgress();
-      } else {
-        // It may be that the timer hasn't been initialized which may happen if
-        // the animation was paused while it was in |kScheculePlay| state.
-        return scheduled_start_offset_ / GetAnimationDuration();
-      }
+      // It may be that the timer hasn't been initialized, which may happen if
+      // the animation was paused while it was in the kSchedulePlay state.
+      return timer_control_
+                 ? timer_control_->GetNormalizedCurrentCycleProgress()
+                 : (scheduled_start_offset_ / GetAnimationDuration());
     case PlayState::kSchedulePlay:
     case PlayState::kPlaying:
     case PlayState::kScheduleResume:
diff --git a/ui/gfx/skia_vector_animation.h b/ui/gfx/skia_vector_animation.h
index 69f1dcf..8c5d252 100644
--- a/ui/gfx/skia_vector_animation.h
+++ b/ui/gfx/skia_vector_animation.h
@@ -185,7 +185,7 @@
     // Time duration from 0 which marks the beginning of a cycle.
     const base::TimeDelta start_offset_;
 
-    // Time duration  from 0 which marks the end of a cycle.
+    // Time duration from 0 which marks the end of a cycle.
     const base::TimeDelta end_offset_;
 
     // Time duration for one cycle. This is essentially a cache of the
diff --git a/ui/gfx/skia_vector_animation_unittest.cc b/ui/gfx/skia_vector_animation_unittest.cc
index 6b2607d..c8209263 100644
--- a/ui/gfx/skia_vector_animation_unittest.cc
+++ b/ui/gfx/skia_vector_animation_unittest.cc
@@ -151,7 +151,7 @@
     return test_clock_.NowTicks() - ticks;
   }
 
-  const base::TimeTicks NowTicks() const { return test_clock_.NowTicks(); }
+  base::TimeTicks NowTicks() const { return test_clock_.NowTicks(); }
 
   double GetTimerStartOffset() const {
     return animation_->timer_control_->GetNormalizedStartOffset();
@@ -276,7 +276,7 @@
                   kAdvance / kAnimationDuration);
 
   animation_->Stop();
-  EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0.f);
+  EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0.0f);
   EXPECT_TRUE(IsStopped());
 }
 
@@ -410,7 +410,7 @@
 
   EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0);
   EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0);
-  EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.f);
+  EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.0f);
 
   EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
 
@@ -552,7 +552,6 @@
 }
 
 TEST_F(SkiaVectorAnimationTest, PlayThrobbingAnimation) {
-
   TestAnimationObserver observer;
   animation_->SetAnimationObserver(&observer);
 
@@ -570,7 +569,7 @@
 
   EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0);
   EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0);
-  EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.f);
+  EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.0f);
 
   EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
 
@@ -588,7 +587,7 @@
   EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()),
             kAnimationDuration - kAdvance);
   animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
-  EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 1.f);
+  EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 1.0f);
   EXPECT_TRUE(IsPlaying());
   EXPECT_FALSE(observer.animation_cycle_ended());
 
@@ -777,10 +776,9 @@
   EXPECT_TRUE(IsPlaying());
 }
 
+// Test to see if the race condition is handled correctly. It may happen that we
+// pause the video before it even starts playing.
 TEST_F(SkiaVectorAnimationTest, PauseBeforePlay) {
-  // Test to see if the race condition is handled correctly. It may happen that
-  // we pause the video before it even starts playing.
-
   TestAnimationObserver observer;
   animation_->SetAnimationObserver(&observer);
 
@@ -810,38 +808,32 @@
 }
 
 TEST_F(SkiaVectorAnimationTest, PaintTest) {
-  std::unique_ptr<gfx::Canvas> canvas(new gfx::Canvas(
-      gfx::Size(kAnimationWidth, kAnimationHeight), 1.f, false));
+  gfx::Canvas canvas(gfx::Size(kAnimationWidth, kAnimationHeight), 1.f, false);
 
   AdvanceClock(base::TimeDelta::FromMilliseconds(300));
 
   animation_->Start(SkiaVectorAnimation::Style::kLinear);
-  animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize());
+  animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
 
   AdvanceClock(base::TimeDelta::FromMilliseconds(50));
-  animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize());
-  SkBitmap bitmap = canvas->GetBitmap();
-  IsAllSameColor(SK_ColorGREEN, bitmap);
+  animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
+  IsAllSameColor(SK_ColorGREEN, canvas.GetBitmap());
 
   AdvanceClock(base::TimeDelta::FromMilliseconds(2450));
-  animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize());
-  bitmap = canvas->GetBitmap();
-  IsAllSameColor(SK_ColorGREEN, bitmap);
+  animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
+  IsAllSameColor(SK_ColorGREEN, canvas.GetBitmap());
 
   AdvanceClock(base::TimeDelta::FromMilliseconds(50));
-  animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize());
-  bitmap = canvas->GetBitmap();
-  IsAllSameColor(SK_ColorBLUE, bitmap);
+  animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
+  IsAllSameColor(SK_ColorBLUE, canvas.GetBitmap());
 
   AdvanceClock(base::TimeDelta::FromMilliseconds(1000));
-  animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize());
-  bitmap = canvas->GetBitmap();
-  IsAllSameColor(SK_ColorBLUE, bitmap);
+  animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
+  IsAllSameColor(SK_ColorBLUE, canvas.GetBitmap());
 
   AdvanceClock(base::TimeDelta::FromMilliseconds(1400));
-  animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize());
-  bitmap = canvas->GetBitmap();
-  IsAllSameColor(SK_ColorBLUE, bitmap);
+  animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
+  IsAllSameColor(SK_ColorBLUE, canvas.GetBitmap());
 }
 
 }  // namespace gfx
diff --git a/ui/touch_selection/touch_handle.cc b/ui/touch_selection/touch_handle.cc
index 2443b22..579f998 100644
--- a/ui/touch_selection/touch_handle.cc
+++ b/ui/touch_selection/touch_handle.cc
@@ -21,17 +21,17 @@
 
 // Maximum amount of travel for a fade sequence. This avoids handle "ghosting"
 // when the handle is moving rapidly while the fade is active.
-const double kFadeDistanceSquared = 20.f * 20.f;
+constexpr double kFadeDistanceSquared = 20.0f * 20.0f;
 
 // Avoid using an empty touch rect, as it may fail the intersection test event
 // if it lies within the other rect's bounds.
-const float kMinTouchMajorForHitTesting = 1.f;
+constexpr float kMinTouchMajorForHitTesting = 1.0f;
 
 // The maximum touch size to use when computing whether a touch point is
 // targetting a touch handle. This is necessary for devices that misreport
 // touch radii, preventing inappropriately largely touch sizes from completely
 // breaking handle dragging behavior.
-const float kMaxTouchMajorForHitTesting = 36.f;
+constexpr float kMaxTouchMajorForHitTesting = 36.0f;
 
 // Note that the intersection region is boundary *exclusive*.
 bool RectIntersectsCircle(const gfx::RectF& rect,
@@ -236,18 +236,17 @@
 
   DCHECK(enabled_);
 
-  float time_u = 1.f - (fade_end_time_ - frame_time) / kFadeDuration;
-  float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() /
-                     kFadeDistanceSquared;
-  float u = std::max(time_u, position_u);
-  SetAlpha(is_visible_ ? u : 1.f - u);
+  const float time_u = 1.0f - (fade_end_time_ - frame_time) / kFadeDuration;
+  const float position_u =
+      (focus_bottom_ - fade_start_position_).LengthSquared() /
+      kFadeDistanceSquared;
+  const float u = std::max(time_u, position_u);
+  SetAlpha(is_visible_ ? u : 1.0f - u);
 
-  if (u >= 1.f) {
+  if (u >= 1)
     EndFade();
-    return false;
-  }
 
-  return true;
+  return u < 1;
 }
 
 gfx::RectF TouchHandle::GetVisibleBounds() const {
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index beb2c3e..afbbc32 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -2984,10 +2984,9 @@
   InitTextfield();
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("abc123");
-  ui::TextInputClient* client = textfield_;
-  client->SetCompositionText(composition);
+  textfield_->SetCompositionText(composition);
   uint32_t composed_text_length =
-      client->ConfirmCompositionText(/* keep_selection */ false);
+      textfield_->ConfirmCompositionText(/* keep_selection */ false);
 
   EXPECT_EQ(composed_text_length, static_cast<uint32_t>(6));
 }
@@ -2996,10 +2995,9 @@
   InitTextfield();
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("");
-  ui::TextInputClient* client = textfield_;
-  client->SetCompositionText(composition);
+  textfield_->SetCompositionText(composition);
   uint32_t composed_text_length =
-      client->ConfirmCompositionText(/* keep_selection */ false);
+      textfield_->ConfirmCompositionText(/* keep_selection */ false);
 
   EXPECT_EQ(composed_text_length, static_cast<uint32_t>(0));
 }
@@ -3009,31 +3007,32 @@
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("abc123");
   const uint32_t char_count = static_cast<uint32_t>(composition.text.length());
-  ui::TextInputClient* client = textfield_;
 
   // Compare the composition character bounds with surrounding cursor bounds.
   for (uint32_t i = 0; i < char_count; ++i) {
     composition.selection = gfx::Range(i);
-    client->SetCompositionText(composition);
+    textfield_->SetCompositionText(composition);
     gfx::Point cursor_origin = GetCursorBounds().origin();
     views::View::ConvertPointToScreen(textfield_, &cursor_origin);
 
     composition.selection = gfx::Range(i + 1);
-    client->SetCompositionText(composition);
+    textfield_->SetCompositionText(composition);
     gfx::Point next_cursor_bottom_left = GetCursorBounds().bottom_left();
     views::View::ConvertPointToScreen(textfield_, &next_cursor_bottom_left);
 
     gfx::Rect character;
-    EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &character));
+    EXPECT_TRUE(textfield_->GetCompositionCharacterBounds(i, &character));
     EXPECT_EQ(character.origin(), cursor_origin) << " i=" << i;
     EXPECT_EQ(character.bottom_right(), next_cursor_bottom_left) << " i=" << i;
   }
 
   // Return false if the index is out of range.
   gfx::Rect rect;
-  EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count, &rect));
-  EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 1, &rect));
-  EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect));
+  EXPECT_FALSE(textfield_->GetCompositionCharacterBounds(char_count, &rect));
+  EXPECT_FALSE(
+      textfield_->GetCompositionCharacterBounds(char_count + 1, &rect));
+  EXPECT_FALSE(
+      textfield_->GetCompositionCharacterBounds(char_count + 100, &rect));
 }
 
 TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) {
@@ -3059,13 +3058,12 @@
 
   ui::CompositionText composition;
   composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount);
-  ui::TextInputClient* client = textfield_;
-  client->SetCompositionText(composition);
+  textfield_->SetCompositionText(composition);
 
   // Make sure GetCompositionCharacterBounds never fails for index.
   gfx::Rect rects[kUtf16CharsCount];
   for (uint32_t i = 0; i < kUtf16CharsCount; ++i)
-    EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &rects[i]));
+    EXPECT_TRUE(textfield_->GetCompositionCharacterBounds(i, &rects[i]));
 
   // Here we might expect the following results but it actually depends on how
   // Uniscribe or HarfBuzz treats them with given font.
@@ -3077,90 +3075,85 @@
 #if defined(OS_CHROMEOS)
 TEST_F(TextfieldTest, SetAutocorrectRangeText) {
   InitTextfield();
-  ui::TextInputClient* client = textfield_;
 
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("Initial txt");
-  client->SetCompositionText(composition);
-  client->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                              gfx::Range(8, 11));
+  textfield_->SetCompositionText(composition);
+  textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
+                                  gfx::Range(8, 11));
 
-  gfx::Range autocorrect_range = client->GetAutocorrectRange();
+  gfx::Range autocorrect_range = textfield_->GetAutocorrectRange();
   EXPECT_EQ(autocorrect_range, gfx::Range(8, 24));
 
   base::string16 text;
-  client->GetTextFromRange(gfx::Range(0, 24), &text);
+  textfield_->GetTextFromRange(gfx::Range(0, 24), &text);
   EXPECT_EQ(text, UTF8ToUTF16("Initial text replacement"));
 }
 
 TEST_F(TextfieldTest, SetAutocorrectRangeExplicitlySet) {
   InitTextfield();
-  ui::TextInputClient* client = textfield_;
-  client->InsertText(UTF8ToUTF16("Initial txt"));
-  client->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                              gfx::Range(8, 11));
+  textfield_->InsertText(UTF8ToUTF16("Initial txt"));
+  textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
+                                  gfx::Range(8, 11));
 
-  gfx::Range autocorrectRange = client->GetAutocorrectRange();
+  gfx::Range autocorrectRange = textfield_->GetAutocorrectRange();
   EXPECT_EQ(autocorrectRange, gfx::Range(8, 24));
 
   base::string16 text;
-  client->GetTextFromRange(gfx::Range(0, 24), &text);
+  textfield_->GetTextFromRange(gfx::Range(0, 24), &text);
   EXPECT_EQ(text, UTF8ToUTF16("Initial text replacement"));
 }
 
 TEST_F(TextfieldTest, DoesNotSetAutocorrectRangeWhenRangeGivenIsInvalid) {
   InitTextfield();
-  ui::TextInputClient* client = textfield_;
 
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("Initial");
-  client->SetCompositionText(composition);
+  textfield_->SetCompositionText(composition);
 
-  EXPECT_FALSE(client->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                                           gfx::Range(8, 11)));
-  EXPECT_EQ(gfx::Range(0, 0), client->GetAutocorrectRange());
+  EXPECT_FALSE(textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
+                                               gfx::Range(8, 11)));
+  EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
   gfx::Range range;
-  client->GetTextRange(&range);
+  textfield_->GetTextRange(&range);
   base::string16 text;
-  client->GetTextFromRange(range, &text);
+  textfield_->GetTextFromRange(range, &text);
   EXPECT_EQ(composition.text, text);
 }
 
 TEST_F(TextfieldTest,
        ClearsAutocorrectRangeWhenSetAutocorrectRangeWithEmptyText) {
   InitTextfield();
-  ui::TextInputClient* client = textfield_;
 
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("Initial");
-  client->SetCompositionText(composition);
+  textfield_->SetCompositionText(composition);
 
   EXPECT_TRUE(
-      client->SetAutocorrectRange(base::EmptyString16(), gfx::Range(0, 2)));
-  EXPECT_EQ(gfx::Range(0, 0), client->GetAutocorrectRange());
+      textfield_->SetAutocorrectRange(base::EmptyString16(), gfx::Range(0, 2)));
+  EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
   gfx::Range range;
-  client->GetTextRange(&range);
+  textfield_->GetTextRange(&range);
   base::string16 text;
-  client->GetTextFromRange(range, &text);
+  textfield_->GetTextFromRange(range, &text);
   EXPECT_EQ(composition.text, text);
 }
 
 TEST_F(TextfieldTest,
        ClearsAutocorrectRangeWhenSetAutocorrectRangeWithEmptyRange) {
   InitTextfield();
-  ui::TextInputClient* client = textfield_;
 
   ui::CompositionText composition;
   composition.text = UTF8ToUTF16("Initial");
-  client->SetCompositionText(composition);
+  textfield_->SetCompositionText(composition);
 
   EXPECT_TRUE(
-      client->SetAutocorrectRange(UTF8ToUTF16("Test"), gfx::Range(0, 0)));
-  EXPECT_EQ(gfx::Range(0, 0), client->GetAutocorrectRange());
+      textfield_->SetAutocorrectRange(UTF8ToUTF16("Test"), gfx::Range(0, 0)));
+  EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
   gfx::Range range;
-  client->GetTextRange(&range);
+  textfield_->GetTextRange(&range);
   base::string16 text;
-  client->GetTextFromRange(range, &text);
+  textfield_->GetTextFromRange(range, &text);
   EXPECT_EQ(composition.text, text);
 }