diff --git a/AUTHORS b/AUTHORS
index aec4fb2..f560625 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1033,6 +1033,7 @@
 Rakuten Kobo Inc. <*@kobo.com>
 Rakuten Kobo Inc. <*@rakuten.com>
 Seznam.cz, a.s. <*@firma.seznam.cz>
+Slack Technologies Inc. <*@slack-corp.com>
 Spotify AB <*@spotify.com>
 Tableau Software <*@tableau.com>
 TeamSpeak Systems GmbH <*@teamspeak.com>
diff --git a/DEPS b/DEPS
index 3815dc8..f5fb7c1 100644
--- a/DEPS
+++ b/DEPS
@@ -126,11 +126,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': '136cd7018a9999f9104758c5dd807fc545f796a4',
+  'skia_revision': '5257816bd3ae9d877293d2b6fe87754a7e08ab5b',
   # 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': '81215ad17e7a74c4909abdbeff989350efa7a3e9',
+  'v8_revision': '17cb18153b15e04ef11d9a474a20f33d78383393',
   # 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.
@@ -142,7 +142,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '9686153413f37c9150e511ee19b6e3fb94d7c98f',
+  'swiftshader_revision': 'd9ce258c174bc7295b92046519ce885613c14608',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -744,7 +744,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '13b2686c57beb5339e22c769da6b98b09da35e24',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'dbbd7b449a7f9aeff25ab388f4ec5002912b2e97',
       'condition': 'checkout_linux',
   },
 
@@ -1252,7 +1252,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'db52df17f0d012983dc281e4864c71485a86bd0e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '1a1c52baf9525b59a54a6f509e5a8253c8c0bfe3',
+    Var('webrtc_git') + '/src.git' + '@' + 'f13c2cd9ee41f4ca572232a4e397b05449474632',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1293,7 +1293,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4d85a1763c27462713fd6cc30f8c10f41e298b0b',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a483882d60579f45dd09ee494d2c68ff222e87e8',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index e8aa2db..fcc8432 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -664,6 +664,7 @@
     'build/android/gyp/create_app_bundle.pydeps',
     'build/android/gyp/create_apk_operations_script.pydeps',
     'build/android/gyp/create_java_binary_script.pydeps',
+    'build/android/gyp/create_size_info_files.pydeps',
     'build/android/gyp/create_stack_script.pydeps',
     'build/android/gyp/create_test_runner_script.pydeps',
     'build/android/gyp/create_tool_wrapper.pydeps',
@@ -681,7 +682,6 @@
     'build/android/gyp/jinja_template.pydeps',
     'build/android/gyp/lint.pydeps',
     'build/android/gyp/main_dex_list.pydeps',
-    'build/android/gyp/merge_jar_info_files.pydeps',
     'build/android/gyp/merge_manifest.pydeps',
     'build/android/gyp/prepare_resources.pydeps',
     'build/android/gyp/proguard.pydeps',
diff --git a/ash/app_list/pagination_model_unittest.cc b/ash/app_list/pagination_model_unittest.cc
index d21dfaa..ae30e42 100644
--- a/ash/app_list/pagination_model_unittest.cc
+++ b/ash/app_list/pagination_model_unittest.cc
@@ -58,7 +58,7 @@
   void AppendSelectedPage(int page) {
     if (selected_pages_.length())
       selected_pages_.append(std::string(" "));
-    selected_pages_.append(base::IntToString(page));
+    selected_pages_.append(base::NumberToString(page));
   }
 
   // PaginationModelObserver overrides:
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index 84fbbf5..f009eb9 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -84,7 +84,7 @@
   void SelectedPageChanged(int old_selected, int new_selected) override {
     if (!selected_pages_.empty())
       selected_pages_ += ',';
-    selected_pages_ += base::IntToString(new_selected);
+    selected_pages_ += base::NumberToString(new_selected);
 
     if (wait_)
       ui_run_loop_->QuitWhenIdle();
@@ -1293,7 +1293,7 @@
     EXPECT_EQ(view_model->view_at(i), test_api_->GetViewAtVisualIndex(
                                           i / GetTilesPerPage(0) /* page */,
                                           i % GetTilesPerPage(0) /* slot */));
-    EXPECT_EQ("Item " + base::IntToString(i),
+    EXPECT_EQ("Item " + base::NumberToString(i),
               view_model->view_at(i)->item()->id());
   }
 
@@ -1301,7 +1301,7 @@
   // two pages. It will only be added after user operations.
   std::string model_content = "Item 0";
   for (int i = 1; i < kApps; ++i)
-    model_content.append(",Item " + base::IntToString(i));
+    model_content.append(",Item " + base::NumberToString(i));
   EXPECT_EQ(model_content, model_->GetModelContent());
 
   // Drag the last item to the first item's left position in previous page.
@@ -1321,14 +1321,14 @@
     EXPECT_EQ(view_model->view_at(i), test_api_->GetViewAtVisualIndex(
                                           i / GetTilesPerPage(0) /* page */,
                                           i % GetTilesPerPage(0) /* slot */));
-    EXPECT_EQ("Item " + base::IntToString((i + kApps - 1) % kApps),
+    EXPECT_EQ("Item " + base::NumberToString((i + kApps - 1) % kApps),
               view_model->view_at(i)->item()->id());
   }
 
   // A "page break" item is added to split the pages.
-  model_content = "Item " + base::IntToString(kApps - 1);
+  model_content = "Item " + base::NumberToString(kApps - 1);
   for (int i = 1; i < kApps; ++i) {
-    model_content.append(",Item " + base::IntToString(i - 1));
+    model_content.append(",Item " + base::NumberToString(i - 1));
     if (i == GetTilesPerPage(0) - 1)
       model_content.append(",PageBreakItem");
   }
@@ -1348,15 +1348,15 @@
     EXPECT_EQ(view_model->view_at(i), test_api_->GetViewAtVisualIndex(
                                           i / GetTilesPerPage(0) /* page */,
                                           i % GetTilesPerPage(0) /* slot */));
-    EXPECT_EQ("Item " + base::IntToString((i + kApps - 2) % kApps),
+    EXPECT_EQ("Item " + base::NumberToString((i + kApps - 2) % kApps),
               view_model->view_at(i)->item()->id());
   }
 
   // A "page break" item still exists.
-  model_content = "Item " + base::IntToString(kApps - 2) + ",Item " +
-                  base::IntToString(kApps - 1);
+  model_content = "Item " + base::NumberToString(kApps - 2) + ",Item " +
+                  base::NumberToString(kApps - 1);
   for (int i = 2; i < kApps; ++i) {
-    model_content.append(",Item " + base::IntToString(i - 2));
+    model_content.append(",Item " + base::NumberToString(i - 2));
     if (i == GetTilesPerPage(0) - 1)
       model_content.append(",PageBreakItem");
   }
diff --git a/ash/app_menu/notification_menu_header_view.cc b/ash/app_menu/notification_menu_header_view.cc
index 32db395..e7a79c7f 100644
--- a/ash/app_menu/notification_menu_header_view.cc
+++ b/ash/app_menu/notification_menu_header_view.cc
@@ -53,7 +53,7 @@
 
   number_of_notifications_ = number_of_notifications;
 
-  counter_->SetText(base::IntToString16(number_of_notifications_));
+  counter_->SetText(base::NumberToString16(number_of_notifications_));
 }
 
 gfx::Size NotificationMenuHeaderView::CalculatePreferredSize() const {
diff --git a/ash/app_menu/notification_menu_view_unittest.cc b/ash/app_menu/notification_menu_view_unittest.cc
index 3098a15..463faa4 100644
--- a/ash/app_menu/notification_menu_view_unittest.cc
+++ b/ash/app_menu/notification_menu_view_unittest.cc
@@ -222,7 +222,7 @@
 
   // The counter should update to 1, and the displayed NotificationItemView
   // should match the notification.
-  EXPECT_EQ(base::IntToString16(1), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(1), test_api()->GetCounterViewContents());
   EXPECT_EQ(1, test_api()->GetItemViewCount());
   CheckDisplayedNotification(notification_0);
 
@@ -231,13 +231,13 @@
   const message_center::Notification notification_1 =
       AddNotification("notification_id_1", base::ASCIIToUTF16("title_1"),
                       base::ASCIIToUTF16("message_1"));
-  EXPECT_EQ(base::IntToString16(2), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(2), test_api()->GetCounterViewContents());
   EXPECT_EQ(2, test_api()->GetItemViewCount());
   CheckDisplayedNotification(notification_1);
 
   // Remove |notification_1|, |notification_0| should be shown.
   notification_menu_view()->OnNotificationRemoved(notification_1.id());
-  EXPECT_EQ(base::IntToString16(1), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(1), test_api()->GetCounterViewContents());
   EXPECT_EQ(1, test_api()->GetItemViewCount());
   CheckDisplayedNotification(notification_0);
 }
@@ -309,7 +309,7 @@
                       base::ASCIIToUTF16("message_1"));
 
   // The latest notification should be shown.
-  EXPECT_EQ(base::IntToString16(2), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(2), test_api()->GetCounterViewContents());
   EXPECT_EQ(2, test_api()->GetItemViewCount());
   CheckDisplayedNotification(notification_1);
 
@@ -317,7 +317,7 @@
   notification_menu_view()->OnNotificationRemoved(notification_0.id());
 
   // The latest notification, |notification_1|, should be shown.
-  EXPECT_EQ(base::IntToString16(1), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(1), test_api()->GetCounterViewContents());
   EXPECT_EQ(1, test_api()->GetItemViewCount());
   CheckDisplayedNotification(notification_1);
 }
@@ -424,7 +424,7 @@
 
   // The displayed notification's contents should have changed to match the
   // updated notification.
-  EXPECT_EQ(base::IntToString16(1), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(1), test_api()->GetCounterViewContents());
   EXPECT_EQ(1, test_api()->GetItemViewCount());
   CheckDisplayedNotification(updated_notification);
 
@@ -433,7 +433,7 @@
                      base::ASCIIToUTF16("Bad Message"));
 
   // Test that the displayed notification has not been changed.
-  EXPECT_EQ(base::IntToString16(1), test_api()->GetCounterViewContents());
+  EXPECT_EQ(base::NumberToString16(1), test_api()->GetCounterViewContents());
   EXPECT_EQ(1, test_api()->GetItemViewCount());
   CheckDisplayedNotification(updated_notification);
 }
diff --git a/ash/app_menu/notification_overflow_view_unittest.cc b/ash/app_menu/notification_overflow_view_unittest.cc
index cc090ca..1d31e70a 100644
--- a/ash/app_menu/notification_overflow_view_unittest.cc
+++ b/ash/app_menu/notification_overflow_view_unittest.cc
@@ -28,7 +28,8 @@
   // Adds a notification and returns the string identifier.
   std::string AddNotification() {
     message_center::ProportionalImageView image_view(gfx::Size(16, 16));
-    std::string notification_id = base::IntToString(notification_identifier_++);
+    std::string notification_id =
+        base::NumberToString(notification_identifier_++);
     notification_overflow_view_->AddIcon(image_view, notification_id);
     return notification_id;
   }
@@ -108,7 +109,7 @@
   EXPECT_TRUE(HasOverflowIcon());
 
   // Remove any notification that was added. The overflow icon should dissapear.
-  notification_overflow_view()->RemoveIcon(base::IntToString(0));
+  notification_overflow_view()->RemoveIcon(base::NumberToString(0));
   CheckNumberOfNotificationIcons(kMaxOverflowIcons);
   EXPECT_FALSE(HasOverflowIcon());
 
diff --git a/ash/display/cros_display_config.cc b/ash/display/cros_display_config.cc
index 70a1eeed..f801f90d 100644
--- a/ash/display/cros_display_config.cc
+++ b/ash/display/cros_display_config.cc
@@ -110,8 +110,8 @@
     if (placement.display_id == display::kInvalidDisplayId)
       continue;
     auto layout = mojom::DisplayLayout::New();
-    layout->id = base::Int64ToString(placement.display_id);
-    layout->parent_id = base::Int64ToString(placement.parent_display_id);
+    layout->id = base::NumberToString(placement.display_id);
+    layout->parent_id = base::NumberToString(placement.parent_display_id);
     layout->position = GetMojomDisplayLayoutPosition(placement.position);
     layout->offset = placement.offset;
     layouts.emplace_back(std::move(layout));
@@ -139,8 +139,8 @@
       const int64_t parent_id = column_index == 0
                                     ? matrix[row_index - 1][column_index]
                                     : row[column_index - 1];
-      layout->id = base::Int64ToString(display_id);
-      layout->parent_id = base::Int64ToString(parent_id);
+      layout->id = base::NumberToString(display_id);
+      layout->parent_id = base::NumberToString(parent_id);
       layout->position = column_index == 0
                              ? mojom::DisplayLayoutPosition::kBottom
                              : mojom::DisplayLayoutPosition::kRight;
@@ -239,7 +239,7 @@
       display_manager->GetDisplayInfo(display.id());
 
   auto info = mojom::DisplayUnitInfo::New();
-  info->id = base::Int64ToString(display.id());
+  info->id = base::NumberToString(display.id());
   info->name = display_manager->GetDisplayNameForId(display.id());
 
   if (!display_info.manufacturer_id().empty() ||
@@ -500,10 +500,10 @@
   } else if (display_manager->IsInMirrorMode()) {
     info->layout_mode = mojom::DisplayLayoutMode::kMirrored;
     info->mirror_source_id =
-        base::Int64ToString(display_manager->mirroring_source_id());
+        base::NumberToString(display_manager->mirroring_source_id());
     info->mirror_destination_ids = std::vector<std::string>();
     for (int64_t id : display_manager->GetMirroringDestinationDisplayIdList())
-      info->mirror_destination_ids->emplace_back(base::Int64ToString(id));
+      info->mirror_destination_ids->emplace_back(base::NumberToString(id));
   } else {
     info->layout_mode = mojom::DisplayLayoutMode::kNormal;
   }
diff --git a/ash/display/cros_display_config_unittest.cc b/ash/display/cros_display_config_unittest.cc
index 1f6e9d2e..8bbd53cb 100644
--- a/ash/display/cros_display_config_unittest.cc
+++ b/ash/display/cros_display_config_unittest.cc
@@ -142,7 +142,7 @@
     mojom::DisplayConfigResult result;
     base::RunLoop run_loop;
     cros_display_config()->OverscanCalibration(
-        base::Int64ToString(id), op, delta,
+        base::NumberToString(id), op, delta,
         base::BindOnce(&SetResult, &result, run_loop.QuitClosure()));
     run_loop.Run();
     return result == mojom::DisplayConfigResult::kSuccess;
@@ -234,12 +234,12 @@
       *display_layout_info->layouts;
   ASSERT_EQ(2u, layouts.size());
 
-  EXPECT_EQ(base::Int64ToString(displays[1].id()), layouts[0]->id);
-  EXPECT_EQ(base::Int64ToString(displays[0].id()), layouts[0]->parent_id);
+  EXPECT_EQ(base::NumberToString(displays[1].id()), layouts[0]->id);
+  EXPECT_EQ(base::NumberToString(displays[0].id()), layouts[0]->parent_id);
   EXPECT_EQ(mojom::DisplayLayoutPosition::kRight, layouts[0]->position);
   EXPECT_EQ(0, layouts[0]->offset);
 
-  EXPECT_EQ(base::Int64ToString(displays[2].id()), layouts[1]->id);
+  EXPECT_EQ(base::NumberToString(displays[2].id()), layouts[1]->id);
   EXPECT_EQ(layouts[0]->id, layouts[1]->parent_id);
   EXPECT_EQ(mojom::DisplayLayoutPosition::kRight, layouts[1]->position);
   EXPECT_EQ(0, layouts[1]->offset);
@@ -303,11 +303,11 @@
 
   auto properties = mojom::DisplayLayoutInfo::New();
   properties->layout_mode = mojom::DisplayLayoutMode::kMirrored;
-  properties->mirror_source_id = base::Int64ToString(displays[0].id());
+  properties->mirror_source_id = base::NumberToString(displays[0].id());
   properties->mirror_destination_ids =
       base::make_optional<std::vector<std::string>>(
-          {base::Int64ToString(displays[1].id()),
-           base::Int64ToString(displays[3].id())});
+          {base::NumberToString(displays[1].id()),
+           base::NumberToString(displays[3].id())});
   mojom::DisplayConfigResult result =
       SetDisplayLayoutInfo(std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
@@ -385,7 +385,7 @@
   auto properties = mojom::DisplayConfigProperties::New();
   properties->set_primary = true;
   mojom::DisplayConfigResult result = SetDisplayProperties(
-      base::Int64ToString(secondary_id), std::move(properties));
+      base::NumberToString(secondary_id), std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
 
   // secondary display should now be primary.
@@ -400,7 +400,7 @@
   auto properties = mojom::DisplayConfigProperties::New();
   properties->overscan = gfx::Insets({199, 20, 51, 130});
   mojom::DisplayConfigResult result = SetDisplayProperties(
-      base::Int64ToString(secondary.id()), std::move(properties));
+      base::NumberToString(secondary.id()), std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("1200,0 150x250", secondary.bounds().ToString());
   const gfx::Insets overscan =
@@ -420,7 +420,7 @@
   auto properties = mojom::DisplayConfigProperties::New();
   properties->rotation =
       mojom::DisplayRotation::New(display::Display::ROTATE_90);
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("1200,0 500x300", secondary.bounds().ToString());
@@ -429,7 +429,7 @@
   properties = mojom::DisplayConfigProperties::New();
   properties->rotation =
       mojom::DisplayRotation::New(display::Display::ROTATE_270);
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("1200,0 500x300", secondary.bounds().ToString());
@@ -440,7 +440,7 @@
   properties->set_primary = true;
   properties->rotation =
       mojom::DisplayRotation::New(display::Display::ROTATE_180);
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   const display::Display& primary =
@@ -458,28 +458,28 @@
 
   auto properties = mojom::DisplayConfigProperties::New();
   properties->bounds_origin = gfx::Point({-520, 50});
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("-520,50 520x400", secondary.bounds().ToString());
 
   properties = mojom::DisplayConfigProperties::New();
   properties->bounds_origin = gfx::Point({1200, 100});
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("1200,100 520x400", secondary.bounds().ToString());
 
   properties = mojom::DisplayConfigProperties::New();
   properties->bounds_origin = gfx::Point({1100, -400});
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("1100,-400 520x400", secondary.bounds().ToString());
 
   properties = mojom::DisplayConfigProperties::New();
   properties->bounds_origin = gfx::Point({-350, 600});
-  result = SetDisplayProperties(base::Int64ToString(secondary.id()),
+  result = SetDisplayProperties(base::NumberToString(secondary.id()),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ("-350,600 520x400", secondary.bounds().ToString());
@@ -507,7 +507,7 @@
   auto properties = mojom::DisplayConfigProperties::New();
   properties->display_zoom_factor = zoom_factor_1;
   mojom::DisplayConfigResult result = SetDisplayProperties(
-      base::Int64ToString(display_id_list[0]), std::move(properties));
+      base::NumberToString(display_id_list[0]), std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ(
       zoom_factor_1,
@@ -519,7 +519,7 @@
   // Set zoom factor for display 1.
   properties = mojom::DisplayConfigProperties::New();
   properties->display_zoom_factor = zoom_factor_2;
-  result = SetDisplayProperties(base::Int64ToString(display_id_list[1]),
+  result = SetDisplayProperties(base::NumberToString(display_id_list[1]),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kSuccess, result);
   EXPECT_EQ(
@@ -533,7 +533,7 @@
   const float invalid_zoom_factor = 0.01f;
   properties = mojom::DisplayConfigProperties::New();
   properties->display_zoom_factor = invalid_zoom_factor;
-  result = SetDisplayProperties(base::Int64ToString(display_id_list[1]),
+  result = SetDisplayProperties(base::NumberToString(display_id_list[1]),
                                 std::move(properties));
   EXPECT_EQ(mojom::DisplayConfigResult::kPropertyValueOutOfRangeError, result);
   EXPECT_EQ(
@@ -610,7 +610,8 @@
 
   InitExternalTouchDevices(internal_display_id);
 
-  EXPECT_FALSE(StartTouchCalibration(base::Int64ToString(internal_display_id)));
+  EXPECT_FALSE(
+      StartTouchCalibration(base::NumberToString(internal_display_id)));
   EXPECT_FALSE(IsTouchCalibrationActive());
 }
 
@@ -635,7 +636,7 @@
                                  : display_id_list[0];
 
   ws::InputDeviceClientTestApi().SetTouchscreenDevices({});
-  std::string id = base::Int64ToString(display_id);
+  std::string id = base::NumberToString(display_id);
 
   // Since no external touch devices are present, the calibration should fail.
   EXPECT_FALSE(StartTouchCalibration(id));
@@ -663,7 +664,7 @@
 
   InitExternalTouchDevices(display_id);
 
-  std::string id = base::Int64ToString(display_id);
+  std::string id = base::NumberToString(display_id);
 
   EXPECT_TRUE(StartTouchCalibration(id));
   mojom::TouchCalibrationPtr calibration = GetDefaultCalibration();
@@ -694,7 +695,7 @@
 
   InitExternalTouchDevices(display_id);
 
-  std::string id = base::Int64ToString(display_id);
+  std::string id = base::NumberToString(display_id);
 
   EXPECT_TRUE(StartTouchCalibration(id));
   EXPECT_TRUE(IsTouchCalibrationActive());
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index d119b222..28ec8e8 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -67,7 +67,7 @@
 namespace {
 
 std::string ToDisplayName(int64_t id) {
-  return "x-" + base::Int64ToString(id);
+  return "x-" + base::NumberToString(id);
 }
 
 }  // namespace
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index f8eb2afe..9ad51b93 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -178,17 +178,17 @@
   std::string str;
   for (std::size_t row = 0; row < touch_calibration_data.point_pairs.size();
        row++) {
-    str +=
-        base::IntToString(touch_calibration_data.point_pairs[row].first.x()) +
-        " ";
-    str +=
-        base::IntToString(touch_calibration_data.point_pairs[row].first.y()) +
-        " ";
-    str +=
-        base::IntToString(touch_calibration_data.point_pairs[row].second.x()) +
-        " ";
-    str +=
-        base::IntToString(touch_calibration_data.point_pairs[row].second.y());
+    str += base::NumberToString(
+               touch_calibration_data.point_pairs[row].first.x()) +
+           " ";
+    str += base::NumberToString(
+               touch_calibration_data.point_pairs[row].first.y()) +
+           " ";
+    str += base::NumberToString(
+               touch_calibration_data.point_pairs[row].second.x()) +
+           " ";
+    str += base::NumberToString(
+        touch_calibration_data.point_pairs[row].second.y());
     if (row != touch_calibration_data.point_pairs.size() - 1)
       str += " ";
   }
@@ -580,7 +580,7 @@
 
     property_value->SetDouble(kDisplayZoom, info.zoom_factor());
 
-    pref_data->Set(base::Int64ToString(id), std::move(property_value));
+    pref_data->Set(base::NumberToString(id), std::move(property_value));
   }
 }
 
@@ -686,7 +686,7 @@
       // display id as key. This is a 1 to 1 mapping of a single entry from
       // AssociationInfoMap to its serialized form.
       association_info_map_value.SetKey(
-          base::Int64ToString(association_info.first),
+          base::NumberToString(association_info.first),
           association_info_value->Clone());
     }
     if (association_info_map_value.empty())
@@ -719,7 +719,7 @@
                                    base::Value(association.first.ToString()));
     association_info_value->SetKey(
         kPortAssociationDisplayId,
-        base::Value(base::Int64ToString(association.second)));
+        base::Value(base::NumberToString(association.second)));
 
     pref_data->SetKey(association.first.SecondaryIdToString(),
                       association_info_value->Clone());
@@ -734,7 +734,7 @@
   const std::set<int64_t>& external_display_mirror_info =
       GetDisplayManager()->external_display_mirror_info();
   for (const auto& id : external_display_mirror_info)
-    pref_data->GetList().emplace_back(base::Value(base::Int64ToString(id)));
+    pref_data->GetList().emplace_back(base::Value(base::NumberToString(id)));
 }
 
 // Stores mixed mirror mode parameters. Clear the preferences if
@@ -751,12 +751,12 @@
     return;
 
   pref_data->SetKey(kMirroringSourceId,
-                    base::Value(base::Int64ToString(mixed_params->source_id)));
+                    base::Value(base::NumberToString(mixed_params->source_id)));
 
   base::ListValue mirroring_destination_ids_value;
   for (const auto& id : mixed_params->destination_ids) {
     mirroring_destination_ids_value.GetList().emplace_back(
-        base::Value(base::Int64ToString(id)));
+        base::Value(base::NumberToString(id)));
   }
   pref_data->SetKey(kMirroringDestinationIds,
                     std::move(mirroring_destination_ids_value));
@@ -961,7 +961,7 @@
   std::unique_ptr<base::DictionaryValue> property_value =
       std::make_unique<base::DictionaryValue>();
   TouchDataToValue(data, property_value.get());
-  pref_data->Set(base::Int64ToString(display_id), std::move(property_value));
+  pref_data->Set(base::NumberToString(display_id), std::move(property_value));
 }
 
 bool DisplayPrefs::ParseTouchCalibrationStringForTest(
diff --git a/ash/display/display_prefs_unittest.cc b/ash/display/display_prefs_unittest.cc
index d60e626f..3c9eded 100644
--- a/ash/display/display_prefs_unittest.cc
+++ b/ash/display/display_prefs_unittest.cc
@@ -200,7 +200,7 @@
 
   void StoreDisplayOverscan(int64_t id, const gfx::Insets& insets) {
     DictionaryPrefUpdate update(local_state(), prefs::kDisplayProperties);
-    const std::string name = base::Int64ToString(id);
+    const std::string name = base::NumberToString(id);
 
     base::DictionaryValue* pref_data = update.Get();
     auto insets_value = std::make_unique<base::DictionaryValue>();
@@ -224,7 +224,7 @@
     base::ListValue* pref_data = update.Get();
     pref_data->Clear();
     for (const auto& id : external_display_mirror_info)
-      pref_data->GetList().emplace_back(base::Value(base::Int64ToString(id)));
+      pref_data->GetList().emplace_back(base::Value(base::NumberToString(id)));
   }
 
   std::string GetRegisteredDisplayPlacementStr(
@@ -387,9 +387,9 @@
   const base::DictionaryValue* displays =
       local_state()->GetDictionary(prefs::kSecondaryDisplays);
   const base::DictionaryValue* layout_value = nullptr;
-  std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
+  std::string key = base::NumberToString(id1) + "," + base::NumberToString(id2);
   std::string dummy_key =
-      base::Int64ToString(id1) + "," + base::Int64ToString(dummy_id);
+      base::NumberToString(id1) + "," + base::NumberToString(dummy_id);
   EXPECT_TRUE(displays->GetDictionary(dummy_key, &layout_value));
 
   display::DisplayLayout stored_layout;
@@ -408,7 +408,7 @@
   const base::DictionaryValue* properties =
       local_state()->GetDictionary(prefs::kDisplayProperties);
   const base::DictionaryValue* property = nullptr;
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id1), &property));
   int ui_scale = 0;
   int rotation = 0;
   EXPECT_TRUE(property->GetInteger("rotation", &rotation));
@@ -460,7 +460,7 @@
 
   std::string touch_str;
 
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id2), &property));
   EXPECT_TRUE(property->GetInteger("rotation", &rotation));
   EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale));
   EXPECT_EQ(0, rotation);
@@ -491,7 +491,7 @@
 
   EXPECT_EQ(id2, display::Screen::GetScreen()->GetPrimaryDisplay().id());
 
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id1), &property));
   width = 0;
   height = 0;
   // Internal display shouldn't store its resolution.
@@ -501,7 +501,7 @@
   // External display's resolution must be stored this time because
   // it's not best.
   int device_scale_factor = 0;
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id2), &property));
   EXPECT_TRUE(property->GetInteger("width", &width));
   EXPECT_TRUE(property->GetInteger("height", &height));
   EXPECT_TRUE(
@@ -528,7 +528,7 @@
 
   std::string primary_id_str;
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
-  EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
+  EXPECT_EQ(base::NumberToString(id2), primary_id_str);
 
   display_manager()->SetLayoutForCurrentDisplays(
       display::test::CreateDisplayLayout(ash::Shell::Get()->display_manager(),
@@ -546,26 +546,26 @@
   EXPECT_EQ(20, offset);
   std::string id;
   EXPECT_TRUE(layout_value->GetString(kPlacementDisplayIdKey, &id));
-  EXPECT_EQ(base::Int64ToString(id1), id);
+  EXPECT_EQ(base::NumberToString(id1), id);
   EXPECT_TRUE(layout_value->GetString(kPlacementParentDisplayIdKey, &id));
-  EXPECT_EQ(base::Int64ToString(id2), id);
+  EXPECT_EQ(base::NumberToString(id2), id);
 
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
-  EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
+  EXPECT_EQ(base::NumberToString(id2), primary_id_str);
 
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id1), &property));
   EXPECT_FALSE(property->GetInteger("width", &width));
   EXPECT_FALSE(property->GetInteger("height", &height));
 
   external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, external_display_mirror_info->GetSize());
-  EXPECT_EQ(base::Int64ToString(id2),
+  EXPECT_EQ(base::NumberToString(id2),
             external_display_mirror_info->GetList()[0].GetString());
 
   // External display's selected resolution must not change
   // by mirroring.
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id2), &property));
   EXPECT_TRUE(property->GetInteger("width", &width));
   EXPECT_TRUE(property->GetInteger("height", &height));
   EXPECT_EQ(300, width);
@@ -580,17 +580,17 @@
 
   // Update key as the 2nd display gets new id.
   id2 = display_manager()->GetSecondaryDisplay().id();
-  key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
+  key = base::NumberToString(id1) + "," + base::NumberToString(id2);
   EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
   EXPECT_TRUE(layout_value->GetString(kPositionKey, &position));
   EXPECT_EQ("right", position);
   EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
   EXPECT_EQ(0, offset);
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
-  EXPECT_EQ(base::Int64ToString(id1), primary_id_str);
+  EXPECT_EQ(base::NumberToString(id1), primary_id_str);
 
   // Best resolution should not be saved.
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id2), &property));
   EXPECT_FALSE(property->GetInteger("width", &width));
   EXPECT_FALSE(property->GetInteger("height", &height));
 
@@ -603,17 +603,17 @@
   UpdateDisplay("200x200*2, 500x400#600x500|500x400%60.0f");
   // Update key as the 2nd display gets new id.
   id2 = display_manager()->GetSecondaryDisplay().id();
-  key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
+  key = base::NumberToString(id1) + "," + base::NumberToString(id2);
   EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
   EXPECT_TRUE(layout_value->GetString(kPositionKey, &position));
   EXPECT_EQ("right", position);
   EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
   EXPECT_EQ(0, offset);
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
-  EXPECT_EQ(base::Int64ToString(id1), primary_id_str);
+  EXPECT_EQ(base::NumberToString(id1), primary_id_str);
 
   // External display's selected resolution must be updated.
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id2), &property));
   EXPECT_TRUE(property->GetInteger("width", &width));
   EXPECT_TRUE(property->GetInteger("height", &height));
   EXPECT_EQ(500, width);
@@ -639,7 +639,7 @@
   const base::DictionaryValue* properties =
       local_state()->GetDictionary(prefs::kDisplayProperties);
   const base::DictionaryValue* property = nullptr;
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id), &property));
   int width = 0, height = 0;
   EXPECT_FALSE(property->GetInteger("width", &width));
   EXPECT_FALSE(property->GetInteger("height", &height));
@@ -654,7 +654,7 @@
   UpdateDisplay("300x200#500x400|400x300|300x200");
 
   property = nullptr;
-  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property));
+  EXPECT_TRUE(properties->GetDictionary(base::NumberToString(id), &property));
   EXPECT_TRUE(property->GetInteger("width", &width));
   EXPECT_TRUE(property->GetInteger("height", &height));
   EXPECT_EQ(300, width);
@@ -671,7 +671,7 @@
   SwapPrimaryDisplay();
   ASSERT_EQ(id1, display_manager()->GetSecondaryDisplay().id());
 
-  std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
+  std::string key = base::NumberToString(id1) + "," + base::NumberToString(id2);
   const base::DictionaryValue* displays =
       local_state()->GetDictionary(prefs::kSecondaryDisplays);
   // Initial saved value is swapped.
@@ -873,7 +873,7 @@
       local_state()->GetDictionary(prefs::kDisplayProperties);
   const base::DictionaryValue* property = nullptr;
   EXPECT_TRUE(properties->GetDictionary(
-      base::Int64ToString(display::Display::InternalDisplayId()), &property));
+      base::NumberToString(display::Display::InternalDisplayId()), &property));
   int rotation = -1;
   EXPECT_TRUE(property->GetInteger("rotation", &rotation));
   EXPECT_EQ(display::Display::ROTATE_0, rotation);
@@ -884,7 +884,7 @@
   properties = local_state()->GetDictionary(prefs::kDisplayProperties);
   property = nullptr;
   EXPECT_TRUE(properties->GetDictionary(
-      base::Int64ToString(display::Display::InternalDisplayId()), &property));
+      base::NumberToString(display::Display::InternalDisplayId()), &property));
   rotation = -1;
   EXPECT_TRUE(property->GetInteger("rotation", &rotation));
   EXPECT_EQ(display::Display::ROTATE_0, rotation);
@@ -1055,7 +1055,7 @@
       local_state()->GetDictionary(prefs::kDisplayProperties);
   int64_t unified_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
   EXPECT_FALSE(
-      displays->GetDictionary(base::Int64ToString(unified_id), &new_value));
+      displays->GetDictionary(base::NumberToString(unified_id), &new_value));
 
   display::test::SetDisplayResolution(display_manager(), unified_id,
                                       gfx::Size(200, 100));
@@ -1063,7 +1063,7 @@
       "200x100",
       display::Screen::GetScreen()->GetPrimaryDisplay().size().ToString());
   EXPECT_FALSE(
-      displays->GetDictionary(base::Int64ToString(unified_id), &new_value));
+      displays->GetDictionary(base::NumberToString(unified_id), &new_value));
 
   // Mirror mode should remember if the default mode was unified.
   display_manager()->SetMirrorMode(display::MirrorMode::kNormal, base::nullopt);
@@ -1107,7 +1107,7 @@
   StoreDisplayBoolPropertyForList(list, "default_unified", true);
   StoreDisplayPropertyForList(
       list, "primary-id",
-      std::make_unique<base::Value>(base::Int64ToString(first_display_id)));
+      std::make_unique<base::Value>(base::NumberToString(first_display_id)));
   LoadDisplayPreferences();
 
   // Should not restore to unified unless unified desktop is enabled.
@@ -1302,7 +1302,7 @@
   const base::ListValue* pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, pref_external_display_mirror_info->GetSize());
-  EXPECT_EQ(base::Int64ToString(first_display_masked_id),
+  EXPECT_EQ(base::NumberToString(first_display_masked_id),
             pref_external_display_mirror_info->GetList()[0].GetString());
 
   // Add first display, mirror mode restores and the external display mirror
@@ -1313,7 +1313,7 @@
   pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, pref_external_display_mirror_info->GetSize());
-  EXPECT_EQ(base::Int64ToString(first_display_masked_id),
+  EXPECT_EQ(base::NumberToString(first_display_masked_id),
             pref_external_display_mirror_info->GetList()[0].GetString());
 
   // Add second display, mirror mode persists and the second display id is added
@@ -1324,9 +1324,9 @@
   pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(2U, pref_external_display_mirror_info->GetSize());
-  EXPECT_EQ(base::Int64ToString(first_display_masked_id),
+  EXPECT_EQ(base::NumberToString(first_display_masked_id),
             pref_external_display_mirror_info->GetList()[0].GetString());
-  EXPECT_EQ(base::Int64ToString(second_display_masked_id),
+  EXPECT_EQ(base::NumberToString(second_display_masked_id),
             pref_external_display_mirror_info->GetList()[1].GetString());
 
   // Disconnect all external displays.
@@ -1342,7 +1342,7 @@
   pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, pref_external_display_mirror_info->GetSize());
-  EXPECT_EQ(base::Int64ToString(second_display_masked_id),
+  EXPECT_EQ(base::NumberToString(second_display_masked_id),
             pref_external_display_mirror_info->GetList()[0].GetString());
 
   // Add first display, mirror mode is off and the external display mirror info
@@ -1353,7 +1353,7 @@
   pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, pref_external_display_mirror_info->GetSize());
-  EXPECT_EQ(base::Int64ToString(second_display_masked_id),
+  EXPECT_EQ(base::NumberToString(second_display_masked_id),
             pref_external_display_mirror_info->GetList()[0].GetString());
 
   // Add second display, mirror mode remains off and the second display id is
@@ -1404,12 +1404,12 @@
   // Check the preferences.
   const base::DictionaryValue* pref_data =
       local_state()->GetDictionary(prefs::kDisplayMixedMirrorModeParams);
-  EXPECT_EQ(base::Int64ToString(internal_display_id),
+  EXPECT_EQ(base::NumberToString(internal_display_id),
             pref_data->FindKey("mirroring_source_id")->GetString());
   const base::Value* destination_ids_value =
       pref_data->FindKey("mirroring_destination_ids");
   EXPECT_EQ(1U, destination_ids_value->GetList().size());
-  EXPECT_EQ(base::Int64ToString(first_display_id),
+  EXPECT_EQ(base::NumberToString(first_display_id),
             destination_ids_value->GetList()[0].GetString());
 
   // Overwrite current mixed mirror mode with a new configuration. (Mirror from
@@ -1429,11 +1429,11 @@
   // Check the preferences.
   pref_data =
       local_state()->GetDictionary(prefs::kDisplayMixedMirrorModeParams);
-  EXPECT_EQ(base::Int64ToString(first_display_id),
+  EXPECT_EQ(base::NumberToString(first_display_id),
             pref_data->FindKey("mirroring_source_id")->GetString());
   destination_ids_value = pref_data->FindKey("mirroring_destination_ids");
   EXPECT_EQ(1U, destination_ids_value->GetList().size());
-  EXPECT_EQ(base::Int64ToString(second_display_id),
+  EXPECT_EQ(base::NumberToString(second_display_id),
             destination_ids_value->GetList()[0].GetString());
 
   // Turn off mirror mode.
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 546e51f..7cf42abe 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -476,7 +476,7 @@
 }
 
 void LoginPasswordView::InsertNumber(int value) {
-  textfield_->InsertOrReplaceText(base::IntToString16(value));
+  textfield_->InsertOrReplaceText(base::NumberToString16(value));
 }
 
 void LoginPasswordView::Backspace() {
diff --git a/ash/public/cpp/shelf_prefs.cc b/ash/public/cpp/shelf_prefs.cc
index 0ff2ccf..82b02c2 100644
--- a/ash/public/cpp/shelf_prefs.cc
+++ b/ash/public/cpp/shelf_prefs.cc
@@ -50,7 +50,7 @@
   if (local_pref->IsManaged())
     return value;
 
-  std::string pref_key = base::Int64ToString(display_id);
+  std::string pref_key = base::NumberToString(display_id);
   bool has_per_display_prefs = false;
   if (!pref_key.empty()) {
     const base::DictionaryValue* shelf_prefs =
@@ -95,7 +95,7 @@
   const base::DictionaryValue* current_shelf_prefs =
       prefs->GetDictionary(prefs::kShelfPreferences);
   DCHECK(current_shelf_prefs);
-  std::string display_key = base::Int64ToString(display_id);
+  std::string display_key = base::NumberToString(display_id);
   const base::DictionaryValue* current_display_prefs = nullptr;
   std::string current_value;
   if (current_shelf_prefs->GetDictionary(display_key, &current_display_prefs) &&
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc
index 55116435..79ac807f 100644
--- a/ash/shelf/shelf_unittest.cc
+++ b/ash/shelf/shelf_unittest.cc
@@ -105,7 +105,7 @@
   item.type = TYPE_APP;
   item.status = STATUS_RUNNING;
   while (!test_api()->IsOverflowButtonVisible()) {
-    item.id = ShelfID(base::IntToString(shelf_model()->item_count()));
+    item.id = ShelfID(base::NumberToString(shelf_model()->item_count()));
     shelf_model()->Add(item);
     ASSERT_LT(shelf_model()->item_count(), 10000);
   }
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index d5d6143..0106777 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -279,7 +279,7 @@
     AshTestBase::TearDown();
   }
 
-  std::string GetNextAppId() { return base::IntToString(id_); }
+  std::string GetNextAppId() { return base::NumberToString(id_); }
 
  protected:
   // Add shelf items of various types, and optionally wait for animations.
@@ -289,7 +289,7 @@
     if (type == TYPE_APP)
       item.status = STATUS_RUNNING;
 
-    item.id = ShelfID(base::IntToString(id_++));
+    item.id = ShelfID(base::NumberToString(id_++));
     model_->Add(item);
     // Set a delegate; some tests require one to select the item.
     model_->SetShelfItemDelegate(item.id,
diff --git a/ash/shell/example_app_list_client.cc b/ash/shell/example_app_list_client.cc
index 2c49b70c..56f339b 100644
--- a/ash/shell/example_app_list_client.cc
+++ b/ash/shell/example_app_list_client.cc
@@ -196,7 +196,7 @@
 void ExampleAppListClient::PopulateApps() {
   for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) {
     WindowTypeShelfItem::Type type = static_cast<WindowTypeShelfItem::Type>(i);
-    const std::string id = base::IntToString(i);
+    const std::string id = base::NumberToString(i);
     auto app = std::make_unique<WindowTypeShelfItem>(id, type);
     controller_->AddItem(app->CloneMetadata());
     apps_.emplace_back(std::move(app));
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc
index 3b37c55..01a4c784 100644
--- a/ash/shell/window_watcher.cc
+++ b/ash/shell/window_watcher.cc
@@ -90,7 +90,7 @@
   ShelfItem item;
   item.type = TYPE_APP;
   static int shelf_id = 0;
-  item.id = ShelfID(base::IntToString(shelf_id++));
+  item.id = ShelfID(base::NumberToString(shelf_id++));
   id_to_window_[item.id] = new_window;
 
   SkBitmap icon_bitmap;
@@ -98,7 +98,7 @@
   constexpr SkColor colors[] = {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE};
   icon_bitmap.eraseColor(colors[shelf_id % 3]);
   item.image = gfx::ImageSkia(gfx::ImageSkiaRep(icon_bitmap, 1.0f));
-  item.title = base::IntToString16(shelf_id);
+  item.title = base::NumberToString16(shelf_id);
   model->Add(item);
 
   model->SetShelfItemDelegate(
diff --git a/ash/system/ime/ime_feature_pod_controller_unittest.cc b/ash/system/ime/ime_feature_pod_controller_unittest.cc
index 2618896..27fc65a 100644
--- a/ash/system/ime/ime_feature_pod_controller_unittest.cc
+++ b/ash/system/ime/ime_feature_pod_controller_unittest.cc
@@ -57,7 +57,7 @@
   void SetActiveIMECount(int count) {
     available_imes_.resize(count);
     for (int i = 0; i < count; ++i)
-      available_imes_[i].id = base::IntToString(i);
+      available_imes_[i].id = base::NumberToString(i);
     RefreshImeController();
   }
 
diff --git a/ash/system/message_center/unified_message_center_view_unittest.cc b/ash/system/message_center/unified_message_center_view_unittest.cc
index 5385537..487ccf5 100644
--- a/ash/system/message_center/unified_message_center_view_unittest.cc
+++ b/ash/system/message_center/unified_message_center_view_unittest.cc
@@ -89,7 +89,7 @@
 
  protected:
   std::string AddNotification() {
-    std::string id = base::IntToString(id_++);
+    std::string id = base::NumberToString(id_++);
     MessageCenter::Get()->AddNotification(std::make_unique<Notification>(
         message_center::NOTIFICATION_TYPE_BASE_FORMAT, id,
         base::UTF8ToUTF16("test title"), base::UTF8ToUTF16("test message"),
diff --git a/ash/system/message_center/unified_message_list_view_unittest.cc b/ash/system/message_center/unified_message_list_view_unittest.cc
index 7b2950c6..5530a06 100644
--- a/ash/system/message_center/unified_message_list_view_unittest.cc
+++ b/ash/system/message_center/unified_message_list_view_unittest.cc
@@ -103,7 +103,7 @@
 
  protected:
   std::string AddNotification(bool pinned = false) {
-    std::string id = base::IntToString(id_++);
+    std::string id = base::NumberToString(id_++);
     auto notification = std::make_unique<Notification>(
         message_center::NOTIFICATION_TYPE_BASE_FORMAT, id,
         base::UTF8ToUTF16("test title"), base::UTF8ToUTF16("test message"),
diff --git a/ash/system/power/power_status.cc b/ash/system/power/power_status.cc
index 4c65256..47a1dcd 100644
--- a/ash/system/power/power_status.cc
+++ b/ash/system/power/power_status.cc
@@ -384,7 +384,7 @@
       IsBatteryCharging()
           ? IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_CHARGING_ACCESSIBLE
           : IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_ACCESSIBLE,
-      base::IntToString16(GetRoundedBatteryPercent()));
+      base::NumberToString16(GetRoundedBatteryPercent()));
   if (!full_description)
     return battery_percentage_accessible;
 
@@ -403,8 +403,8 @@
     int hour = 0, min = 0;
     power_utils::SplitTimeIntoHoursAndMinutes(time, &hour, &min);
     base::string16 minute =
-        min < 10 ? base::ASCIIToUTF16("0") + base::IntToString16(min)
-                 : base::IntToString16(min);
+        min < 10 ? base::ASCIIToUTF16("0") + base::NumberToString16(min)
+                 : base::NumberToString16(min);
     battery_time_accessible = l10n_util::GetStringFUTF16(
         IsBatteryCharging()
             ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_ACCESSIBLE
diff --git a/ash/system/toast/toast_manager_unittest.cc b/ash/system/toast/toast_manager_unittest.cc
index df52f8f..221161e6 100644
--- a/ash/system/toast/toast_manager_unittest.cc
+++ b/ash/system/toast/toast_manager_unittest.cc
@@ -84,7 +84,7 @@
   std::string ShowToast(const std::string& text,
                         int32_t duration,
                         bool visible_on_lock_screen = false) {
-    std::string id = "TOAST_ID_" + base::UintToString(serial_++);
+    std::string id = "TOAST_ID_" + base::NumberToString(serial_++);
     manager()->Show(ToastData(id, base::ASCIIToUTF16(text), duration,
                               base::string16(), visible_on_lock_screen));
     return id;
@@ -98,7 +98,7 @@
     if (dismiss_text.has_value())
       localized_dismiss = base::ASCIIToUTF16(dismiss_text.value());
 
-    std::string id = "TOAST_ID_" + base::UintToString(serial_++);
+    std::string id = "TOAST_ID_" + base::NumberToString(serial_++);
     manager()->Show(
         ToastData(id, base::ASCIIToUTF16(text), duration, localized_dismiss));
     return id;
diff --git a/ash/touch/touch_observer_hud.cc b/ash/touch/touch_observer_hud.cc
index e087e6c..8363f7b 100644
--- a/ash/touch/touch_observer_hud.cc
+++ b/ash/touch/touch_observer_hud.cc
@@ -409,7 +409,7 @@
     if (hud) {
       std::unique_ptr<base::ListValue> list = hud->GetLogAsList();
       if (!list->empty())
-        value->Set(base::Int64ToString(hud->display_id_), std::move(list));
+        value->Set(base::NumberToString(hud->display_id_), std::move(list));
     }
   }
   return value;
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index e57d457..843b0e6 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -761,7 +761,7 @@
   auto wallpaper_info_dict = std::make_unique<base::DictionaryValue>();
   wallpaper_info_dict->SetString(
       kNewWallpaperDateNodeName,
-      base::Int64ToString(info.date.ToInternalValue()));
+      base::NumberToString(info.date.ToInternalValue()));
   wallpaper_info_dict->SetString(kNewWallpaperLocationNodeName, info.location);
   wallpaper_info_dict->SetInteger(kNewWallpaperLayoutNodeName, info.layout);
   wallpaper_info_dict->SetInteger(kNewWallpaperTypeNodeName, info.type);
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index 09bc05d..56d86de 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -225,7 +225,7 @@
     // Window origin should be adjusted for minimum visibility (25px).
     int expected_x = -50 + wm::kMinimumOnScreenArea;
 
-    EXPECT_EQ(base::IntToString(expected_x) + ",10 50x60",
+    EXPECT_EQ(base::NumberToString(expected_x) + ",10 50x60",
               window_->bounds().ToString());
   }
   // Dropping a window that is larger than the destination work area
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 55d556f..dd3f294 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -513,6 +513,7 @@
   // the resize. This can happen, for example, on the transition back to
   // clamshell mode or when a task is minimized during a resize.
   if (is_resizing_) {
+    is_resizing_ = false;
     FinishWindowResizing(left_window_);
     FinishWindowResizing(right_window_);
   }
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index ece9a488..52db25d 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -1834,6 +1834,26 @@
   EXPECT_EQ(0, observer.items_on_last_overview_end());
 }
 
+// Test that resizing ends properly if split view ends during divider dragging.
+TEST_F(SplitViewControllerTest, EndSplitViewWhileDragging) {
+  // Enter split view mode.
+  std::unique_ptr<aura::Window> window = CreateTestWindow();
+  split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
+
+  // Start resizing.
+  gfx::Rect divider_bounds =
+      split_view_divider()->GetDividerBoundsInScreen(false);
+  split_view_controller()->StartResize(divider_bounds.CenterPoint());
+
+  // Verify the setup.
+  ASSERT_TRUE(split_view_controller()->IsSplitViewModeActive());
+  ASSERT_TRUE(split_view_controller()->is_resizing());
+
+  // End split view and check that resizing has ended properly.
+  split_view_controller()->EndSplitView();
+  EXPECT_FALSE(split_view_controller()->is_resizing());
+}
+
 // Test the tab-dragging related functionalities in tablet mode. Tab(s) can be
 // dragged out of a window and then put in split view mode or merge into another
 // window.
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index 7ca86005..cffcd81 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -157,7 +157,7 @@
       if (*i == window_.get() || *i == window2_.get() || *i == window3_.get()) {
         if (!result.empty())
           result += " ";
-        result += base::IntToString((*i)->id());
+        result += base::NumberToString((*i)->id());
       }
     }
     return result;
@@ -631,7 +631,7 @@
     // With the resolution of 500x600 we will hit in this case the 50% screen
     // size setting.
     // TODO(varkha): Insets are updated because of http://crbug.com/292238
-    EXPECT_EQ("250,0 250x" + base::IntToString(bottom),
+    EXPECT_EQ("250,0 250x" + base::NumberToString(bottom),
               window_->bounds().ToString());
     EXPECT_EQ("800,10 400x60",
               window_state->GetRestoreBoundsInScreen().ToString());
@@ -819,7 +819,7 @@
   resizer->Drag(CalculateDragPoint(*resizer, 0, 600), 0);
   int expected_y =
       kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10;
-  EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400",
+  EXPECT_EQ("100," + base::NumberToString(expected_y) + " 300x400",
             window_->bounds().ToString());
 }
 
@@ -849,7 +849,7 @@
     // When the mouse cursor is in the primary display, the window cannot move
     // on non-work area but can get all the way towards the bottom,
     // restricted only by the window height.
-    EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x20",
+    EXPECT_EQ("100," + base::NumberToString(expected_y) + " 300x20",
               window_->bounds().ToString());
     // Revert the drag in order to not remember the restore bounds.
     resizer->RevertDrag();
@@ -868,7 +868,7 @@
         kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10;
     // When the mouse cursor is in the primary display, the window cannot move
     // on non-work area with kMinOnscreenHeight margin.
-    EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400",
+    EXPECT_EQ("100," + base::NumberToString(expected_y) + " 300x400",
               window_->bounds().ToString());
     resizer->CompleteDrag();
   }
@@ -924,8 +924,9 @@
       window_.get(), gfx::Point(pixels_to_left_border, 0), HTRIGHT));
   ASSERT_TRUE(resizer.get());
   resizer->Drag(CalculateDragPoint(*resizer, -window_width, 0), 0);
-  EXPECT_EQ(base::IntToString(window_x) + ",100 " +
-                base::IntToString(wm::kMinimumOnScreenArea - window_x) + "x380",
+  EXPECT_EQ(base::NumberToString(window_x) + ",100 " +
+                base::NumberToString(wm::kMinimumOnScreenArea - window_x) +
+                "x380",
             window_->bounds().ToString());
 }
 
@@ -942,9 +943,9 @@
       CreateResizerForTest(window_.get(), gfx::Point(window_x, 0), HTLEFT));
   ASSERT_TRUE(resizer.get());
   resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
-  EXPECT_EQ(base::IntToString(right - wm::kMinimumOnScreenArea) + ",100 " +
-                base::IntToString(window_width - pixels_to_right_border +
-                                  wm::kMinimumOnScreenArea) +
+  EXPECT_EQ(base::NumberToString(right - wm::kMinimumOnScreenArea) + ",100 " +
+                base::NumberToString(window_width - pixels_to_right_border +
+                                     wm::kMinimumOnScreenArea) +
                 "x380",
             window_->bounds().ToString());
 }
@@ -961,10 +962,10 @@
       window_.get(), gfx::Point(0, bottom - delta_to_bottom), HTTOP));
   ASSERT_TRUE(resizer.get());
   resizer->Drag(CalculateDragPoint(*resizer, 0, bottom), 0);
-  EXPECT_EQ("100," + base::IntToString(bottom - wm::kMinimumOnScreenArea) +
+  EXPECT_EQ("100," + base::NumberToString(bottom - wm::kMinimumOnScreenArea) +
                 " 300x" +
-                base::IntToString(height -
-                                  (delta_to_bottom - wm::kMinimumOnScreenArea)),
+                base::NumberToString(
+                    height - (delta_to_bottom - wm::kMinimumOnScreenArea)),
             window_->bounds().ToString());
 }
 
@@ -985,8 +986,8 @@
       CreateResizerForTest(window_.get(), gfx::Point(window_x, 0), HTCAPTION));
   ASSERT_TRUE(resizer.get());
   resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
-  EXPECT_EQ(base::IntToString(right - wm::kMinimumOnScreenArea) + ",100 " +
-                base::IntToString(window_width) + "x380",
+  EXPECT_EQ(base::NumberToString(right - wm::kMinimumOnScreenArea) + ",100 " +
+                base::NumberToString(window_width) + "x380",
             window_->bounds().ToString());
 
   // With secondary display.  Operation itself is same but doesn't change
@@ -996,8 +997,8 @@
                                          gfx::Insets(0, 0, 50, 0));
   window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
   resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
-  EXPECT_EQ(base::IntToString(window_x + window_width) + ",100 " +
-                base::IntToString(window_width) + "x380",
+  EXPECT_EQ(base::NumberToString(window_x + window_width) + ",100 " +
+                base::NumberToString(window_width) + "x380",
             window_->bounds().ToString());
 }
 
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index 545115a..9db34819 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -725,7 +725,7 @@
 
   // |window1| should be horizontally centered.
   int x_window1 = (desktop_area.width() - 300) / 2;
-  EXPECT_EQ(base::IntToString(x_window1) + ",32 300x300",
+  EXPECT_EQ(base::NumberToString(x_window1) + ",32 300x300",
             window1->bounds().ToString());
 
   // Create a |child| window and make it a transient child of |window1|.
@@ -738,7 +738,7 @@
   wm::ActivateWindow(child.get());
 
   // The |child| should be where it was created.
-  EXPECT_EQ(base::IntToString(x_child) + ",20 200x200",
+  EXPECT_EQ(base::NumberToString(x_child) + ",20 200x200",
             child->bounds().ToString());
 
   // Create and show a second window forcing the first window and its child to
@@ -753,10 +753,12 @@
   // Check that both |window1| and |child| have moved left.
   EXPECT_EQ("0,32 300x300", window1->bounds().ToString());
   int x = x_child - x_window1;
-  EXPECT_EQ(base::IntToString(x) + ",20 200x200", child->bounds().ToString());
+  EXPECT_EQ(base::NumberToString(x) + ",20 200x200",
+            child->bounds().ToString());
   // Check that |window2| has moved right.
   x = desktop_area.width() - window2->bounds().width();
-  EXPECT_EQ(base::IntToString(x) + ",48 250x250", window2->bounds().ToString());
+  EXPECT_EQ(base::NumberToString(x) + ",48 250x250",
+            window2->bounds().ToString());
 }
 
 // Test the basic auto placement of one and or two windows in a "simulated
@@ -798,13 +800,13 @@
   // |window1| should be flush left and |window3| flush right.
   EXPECT_EQ("0,32 640x320", window1->bounds().ToString());
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window3->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window3->bounds().width()) +
           ",48 256x512",
       window3->bounds().ToString());
 
   // After removing |window3|, |window1| should be centered again.
   window3.reset();
-  EXPECT_EQ(base::IntToString(
+  EXPECT_EQ(base::NumberToString(
                 (desktop_area.width() - window1->bounds().width()) / 2) +
                 ",32 640x320",
             window1->bounds().ToString());
@@ -819,7 +821,7 @@
   window4->SetBounds(gfx::Rect(32, 48, 256, 512));
   window1->Show();
   // |window1| should be centered and |window4| untouched.
-  EXPECT_EQ(base::IntToString(
+  EXPECT_EQ(base::NumberToString(
                 (desktop_area.width() - window1->bounds().width()) / 2) +
                 ",32 640x320",
             window1->bounds().ToString());
@@ -832,7 +834,7 @@
   window1->Hide();
   window1->Show();
   // |window1| should be centered.
-  EXPECT_EQ(base::IntToString(
+  EXPECT_EQ(base::NumberToString(
                 (desktop_area.width() - window1->bounds().width()) / 2) +
                 ",32 640x320",
             window1->bounds().ToString());
@@ -871,7 +873,7 @@
   // |window1| should be flush left and |window2| flush right.
   EXPECT_EQ("0,32 640x320", window1->bounds().ToString());
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window2->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window2->bounds().width()) +
           ",48 256x512",
       window2->bounds().ToString());
   // FLag should now be reset.
@@ -956,10 +958,10 @@
   window2->Show();
 
   // |window1| should be flush left and |window2| flush right.
-  EXPECT_EQ("0," + base::IntToString(user_pos.y()) + " 640x320",
+  EXPECT_EQ("0," + base::NumberToString(user_pos.y()) + " 640x320",
             window1->bounds().ToString());
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window2->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window2->bounds().width()) +
           ",48 256x512",
       window2->bounds().ToString());
   window2->Hide();
@@ -1039,7 +1041,7 @@
   // |window2| should be centered now.
   EXPECT_TRUE(window2->IsVisible());
   EXPECT_TRUE(window2_state->IsNormalStateType());
-  EXPECT_EQ(base::IntToString(
+  EXPECT_EQ(base::NumberToString(
                 (desktop_area.width() - window2->bounds().width()) / 2) +
                 ",48 256x512",
             window2->bounds().ToString());
@@ -1047,7 +1049,7 @@
   window1_state->Restore();
   // |window1| should be flush right and |window3| flush left.
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window1->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window1->bounds().width()) +
           ",32 640x320",
       window1->bounds().ToString());
   EXPECT_EQ("0,48 256x512", window2->bounds().ToString());
@@ -1071,7 +1073,7 @@
   // |window2| should be centered now.
   EXPECT_TRUE(window2->IsVisible());
   EXPECT_TRUE(window2_state->IsNormalStateType());
-  EXPECT_EQ(base::IntToString(
+  EXPECT_EQ(base::NumberToString(
                 (desktop_area.width() - window2->bounds().width()) / 2) +
                 ",48 256x512",
             window2->bounds().ToString());
@@ -1096,7 +1098,7 @@
 
   // |window1| should be flush right and |window3| flush left.
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window1->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window1->bounds().width()) +
           ",32 640x320",
       window1->bounds().ToString());
   EXPECT_EQ("0,40 256x512", window2->bounds().ToString());
@@ -1107,7 +1109,7 @@
   // |window2| should be centered now.
   EXPECT_TRUE(window2->IsVisible());
   EXPECT_TRUE(window2_state->IsNormalStateType());
-  EXPECT_EQ(base::IntToString(
+  EXPECT_EQ(base::NumberToString(
                 (desktop_area.width() - window2->bounds().width()) / 2) +
                 ",40 256x512",
             window2->bounds().ToString());
@@ -1131,7 +1133,7 @@
 
   // |window1| should be flush right and |window3| flush left.
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window1->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window1->bounds().width()) +
           ",32 640x320",
       window1->bounds().ToString());
   EXPECT_EQ("0,40 256x512", window2->bounds().ToString());
@@ -1141,7 +1143,7 @@
 
   // |window1| should be flush right and |window2| flush left.
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window1->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window1->bounds().width()) +
           ",32 640x320",
       window1->bounds().ToString());
   EXPECT_EQ("0,40 256x512", window2->bounds().ToString());
@@ -1179,7 +1181,7 @@
   window2->layer()->GetAnimator()->StopAnimating();
   // |window1| should be flush right and |window2| flush left.
   EXPECT_EQ(
-      base::IntToString(desktop_area.width() - window1->bounds().width()) +
+      base::NumberToString(desktop_area.width() - window1->bounds().width()) +
           ",32 640x320",
       window1->bounds().ToString());
   EXPECT_EQ("0,48 256x512", window2->bounds().ToString());
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.cc b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
index 34d6de2..a90a1131 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
@@ -396,20 +396,7 @@
   in_start().initialized = true;
 #endif
 
-  // The initial number of workers is |num_wake_ups_before_start_| + 1 to try to
-  // keep one at least one standby thread at all times (capacity permitting).
-  const int num_initial_workers =
-      std::min(num_wake_ups_before_start_ + 1, static_cast<int>(max_tasks_));
-  workers_.reserve(num_initial_workers);
-
-  for (int index = 0; index < num_initial_workers; ++index) {
-    auto worker = CreateAndRegisterWorkerLockRequired(&executor);
-
-    if (index < num_wake_ups_before_start_)
-      executor.ScheduleWakeUp(std::move(worker));
-    else
-      idle_workers_stack_.Push(worker.get());
-  }
+  EnsureEnoughWorkersLockRequired(&executor);
 }
 
 SchedulerWorkerPoolImpl::~SchedulerWorkerPoolImpl() {
@@ -428,16 +415,25 @@
 
 void SchedulerWorkerPoolImpl::OnCanScheduleSequence(
     SequenceAndTransaction sequence_and_transaction) {
-  PushSequenceToPriorityQueue(std::move(sequence_and_transaction));
-  WakeUpOneWorker();
+  PushSequenceAndWakeUpWorkers(std::move(sequence_and_transaction));
 }
 
-void SchedulerWorkerPoolImpl::PushSequenceToPriorityQueue(
+void SchedulerWorkerPoolImpl::PushSequenceAndWakeUpWorkers(
     SequenceAndTransaction sequence_and_transaction) {
-  DCHECK(sequence_and_transaction.sequence);
-  AutoSchedulerLock auto_lock(lock_);
-  priority_queue_.Push(std::move(sequence_and_transaction.sequence),
-                       sequence_and_transaction.transaction.GetSortKey());
+  bool must_schedule_adjust_max_tasks;
+  SchedulerWorkerActionExecutor executor(tracked_ref_factory_.GetTrackedRef());
+  {
+    AutoSchedulerLock auto_lock(lock_);
+    priority_queue_.Push(std::move(sequence_and_transaction.sequence),
+                         sequence_and_transaction.transaction.GetSortKey());
+    EnsureEnoughWorkersLockRequired(&executor);
+    must_schedule_adjust_max_tasks = MustScheduleAdjustMaxTasksLockRequired();
+    // Terminate the Sequence transaction at the end of this scope to avoid
+    // holding a lock when calling ScheduleAdjustMaxTasks().
+    auto terminate_sequence_transaction = std::move(sequence_and_transaction);
+  }
+  if (must_schedule_adjust_max_tasks)
+    ScheduleAdjustMaxTasks();
 }
 
 void SchedulerWorkerPoolImpl::GetHistograms(
@@ -521,8 +517,7 @@
 
 void SchedulerWorkerPoolImpl::ReEnqueueSequenceChangingPool(
     SequenceAndTransaction sequence_and_transaction) {
-  PushSequenceToPriorityQueue(std::move(sequence_and_transaction));
-  WakeUpOneWorker();
+  PushSequenceAndWakeUpWorkers(std::move(sequence_and_transaction));
 }
 
 size_t SchedulerWorkerPoolImpl::NumberOfWorkersForTesting() const {
@@ -638,27 +633,41 @@
     return nullptr;
   }
 
-  // Enforce that no more than |max_best_effort_tasks_| run concurrently.
-  const TaskPriority priority =
-      outer_->priority_queue_.PeekSortKey().priority();
-  if (priority == TaskPriority::BEST_EFFORT) {
-    if (outer_->num_running_best_effort_tasks_ <
-        outer_->max_best_effort_tasks_) {
-      ++outer_->num_running_best_effort_tasks_;
-      write_worker().is_running_best_effort_task = true;
-    } else {
-      OnWorkerBecomesIdleLockRequired(worker);
-      return nullptr;
-    }
+  // Enforce that no more than |max_best_effort_tasks_| BEST_EFFORT tasks run
+  // concurrently.
+  const bool next_sequence_is_best_effort =
+      outer_->priority_queue_.PeekSortKey().priority() ==
+      TaskPriority::BEST_EFFORT;
+  if (next_sequence_is_best_effort && outer_->num_running_best_effort_tasks_ >=
+                                          outer_->max_best_effort_tasks_) {
+    OnWorkerBecomesIdleLockRequired(worker);
+    return nullptr;
   }
 
   // Replace this worker if it was the last one, capacity permitting.
   outer_->MaintainAtLeastOneIdleWorkerLockRequired(&executor);
 
-  DCHECK(!outer_->idle_workers_stack_.Contains(worker));
+  // Running task bookkeeping.
   worker_only().is_running_task = true;
+  ++outer_->num_running_tasks_;
+  DCHECK(!outer_->idle_workers_stack_.Contains(worker));
 
-  return outer_->priority_queue_.PopSequence();
+  // Running BEST_EFFORT task bookkeeping.
+  if (next_sequence_is_best_effort) {
+    write_worker().is_running_best_effort_task = true;
+    ++outer_->num_running_best_effort_tasks_;
+  }
+
+  // Pop the Sequence from which to run a task from the PriorityQueue.
+  scoped_refptr<Sequence> sequence = outer_->priority_queue_.PopSequence();
+
+  // Sanity check: A worker should not get work if the number of awake workers
+  // is more than the *desired* number of awake workers. It should instead be
+  // added to the idle stack.
+  DCHECK_LE(outer_->GetNumAwakeWorkersLockRequired(),
+            outer_->GetDesiredNumAwakeWorkersLockRequired());
+
+  return sequence;
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::DidRunTask(
@@ -666,46 +675,62 @@
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
   DCHECK(worker_only().is_running_task);
   DCHECK(read_worker().may_block_start_time.is_null());
-  // |may_block_start_time| being null unracily implies
-  // |!incremented_max_tasks_since_blocked_|. Skip check on NaCl to avoid unsafe
-  // reference acquisition warning.
-#if !defined(OS_NACL)
-  DCHECK(!TS_UNCHECKED_READ(incremented_max_tasks_since_blocked_));
-#endif
-
-  // Bookkeeping.
-  worker_only().is_running_task = false;
-
-  if (read_worker().is_running_best_effort_task) {
-    AutoSchedulerLock auto_lock(outer_->lock_);
-    --outer_->num_running_best_effort_tasks_;
-    write_worker().is_running_best_effort_task = false;
-  }
 
   ++worker_only().num_tasks_since_last_wait;
   ++worker_only().num_tasks_since_last_detach;
 
-  if (!sequence)
-    return;
-
-  // A transaction to the Sequence to reenqueue.
-  SequenceAndTransaction sequence_to_reenqueue_and_transaction(
-      SequenceAndTransaction::FromSequence(std::move(sequence)));
-
-  // Decide in which pool the Sequence in
-  // |sequence_to_reenqueue_and_transaction| should be reenqueued.
-  SchedulerWorkerPool* const destination_pool =
-      outer_->delegate_->GetWorkerPoolForTraits(
-          sequence_to_reenqueue_and_transaction.transaction.traits());
-
-  // Reenqueue the Sequence.
-  if (outer_ == destination_pool) {
-    outer_->PushSequenceToPriorityQueue(
-        std::move(sequence_to_reenqueue_and_transaction));
-  } else {
-    destination_pool->ReEnqueueSequenceChangingPool(
-        std::move(sequence_to_reenqueue_and_transaction));
+  // A transaction to the Sequence to reenqueue, if any. Instantiated here as
+  // |Sequence::lock_| is a UniversalPredecessor and must always be acquired
+  // prior to acquiring a second lock
+  Optional<SequenceAndTransaction> sequence_to_reenqueue_and_transaction;
+  if (sequence) {
+    sequence_to_reenqueue_and_transaction.emplace(
+        SequenceAndTransaction::FromSequence(std::move(sequence)));
   }
+
+  // The pool in which to reenqueue the Sequence. Initialized below and used
+  // outside the lock after.
+  SchedulerWorkerPool* destination_pool;
+
+  {
+    AutoSchedulerLock auto_lock(outer_->lock_);
+
+    DCHECK(!incremented_max_tasks_since_blocked_);
+
+    // Running task bookkeeping.
+    DCHECK_GT(outer_->num_running_tasks_, 0U);
+    --outer_->num_running_tasks_;
+    worker_only().is_running_task = false;
+
+    // Running BEST_EFFORT task bookkeeping.
+    if (read_worker().is_running_best_effort_task) {
+      DCHECK_GT(outer_->num_running_best_effort_tasks_, 0U);
+      --outer_->num_running_best_effort_tasks_;
+      write_worker().is_running_best_effort_task = false;
+    }
+
+    if (!sequence_to_reenqueue_and_transaction)
+      return;
+
+    // Decide in which pool the Sequence should be reenqueued.
+    destination_pool = outer_->delegate_->GetWorkerPoolForTraits(
+        sequence_to_reenqueue_and_transaction->transaction.traits());
+
+    // If the Sequence should be reenqueued in the current pool, reenqueue it
+    // *before* releasing the lock. Note: No wake up needed because the current
+    // worker will pop a Sequence from the PriorityQueue after this returns.
+    if (outer_ == destination_pool) {
+      outer_->priority_queue_.Push(
+          std::move(sequence_to_reenqueue_and_transaction->sequence),
+          sequence_to_reenqueue_and_transaction->transaction.GetSortKey());
+      return;
+    }
+  }
+
+  // If the Sequence should be reenqueued in a different pool, reenqueue it
+  // *after* releasing the lock.
+  destination_pool->ReEnqueueSequenceChangingPool(
+      std::move(sequence_to_reenqueue_and_transaction.value()));
 }
 
 TimeDelta
@@ -865,9 +890,9 @@
     // same scope.
     if (!read_worker().may_block_start_time.is_null()) {
       write_worker().may_block_start_time = TimeTicks();
-      --outer_->num_pending_may_block_workers_;
+      --outer_->num_unresolved_may_block_;
       if (read_worker().is_running_best_effort_task)
-        --outer_->num_pending_best_effort_may_block_workers_;
+        --outer_->num_unresolved_best_effort_may_block_;
     }
   }
 
@@ -884,9 +909,9 @@
         read_worker().is_running_best_effort_task);
   } else {
     DCHECK(!read_worker().may_block_start_time.is_null());
-    --outer_->num_pending_may_block_workers_;
+    --outer_->num_unresolved_may_block_;
     if (read_worker().is_running_best_effort_task)
-      --outer_->num_pending_best_effort_may_block_workers_;
+      --outer_->num_unresolved_best_effort_may_block_;
   }
 
   incremented_max_tasks_since_blocked_ = false;
@@ -904,9 +929,9 @@
     DCHECK(!incremented_max_tasks_since_blocked_);
     DCHECK(read_worker().may_block_start_time.is_null());
     write_worker().may_block_start_time = TimeTicks::Now();
-    ++outer_->num_pending_may_block_workers_;
+    ++outer_->num_unresolved_may_block_;
     if (read_worker().is_running_best_effort_task)
-      ++outer_->num_pending_best_effort_may_block_workers_;
+      ++outer_->num_unresolved_best_effort_may_block_;
 
     must_schedule_adjust_max_tasks =
         outer_->MustScheduleAdjustMaxTasksLockRequired();
@@ -927,25 +952,7 @@
   incremented_max_tasks_since_blocked_ = true;
   outer_->IncrementMaxTasksLockRequired(
       read_worker().is_running_best_effort_task);
-
-  // If the number of workers was less than the old max tasks, PostTask would've
-  // handled creating extra workers during WakeUpOneWorker. Therefore, we don't
-  // need to do anything here.
-  if (outer_->workers_.size() < outer_->max_tasks_ - 1)
-    return;
-
-  if (outer_->priority_queue_.IsEmpty()) {
-    outer_->MaintainAtLeastOneIdleWorkerLockRequired(&executor);
-  } else {
-    // TODO(crbug.com/757897): We may create extra workers in this case:
-    // |workers.size()| was equal to the old |max_tasks_|, we had multiple
-    // ScopedBlockingCalls in parallel and we had work on the PQ.
-    outer_->WakeUpOneWorkerLockRequired(&executor);
-  }
-
-  // Entering a WILL_BLOCK ScopedBlockingCall is not expected to require
-  // AdjustMaxTasks() to be scheduled.
-  DCHECK(!outer_->MustScheduleAdjustMaxTasksLockRequired());
+  outer_->EnsureEnoughWorkersLockRequired(&executor);
 }
 
 bool SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
@@ -966,11 +973,10 @@
   }
 
   // Excess workers should not get work, until they are no longer excess (i.e.
-  // max tasks increases or another worker cleans up). This ensures that if we
-  // have excess workers in the pool, they get a chance to no longer be excess
-  // before being cleaned up.
-  if (outer_->NumberOfExcessWorkersLockRequired() >
-      outer_->idle_workers_stack_.Size()) {
+  // max tasks increases). This ensures that if we have excess workers in the
+  // pool, they get a chance to no longer be excess before being cleaned up.
+  if (outer_->GetNumAwakeWorkersLockRequired() >
+      outer_->GetDesiredNumAwakeWorkersLockRequired()) {
     OnWorkerBecomesIdleLockRequired(worker);
     return false;
   }
@@ -986,9 +992,9 @@
           outer_->after_start().may_block_threshold) {
     incremented_max_tasks_since_blocked_ = true;
 
-    --outer_->num_pending_may_block_workers_;
+    --outer_->num_unresolved_may_block_;
     if (read_any().is_running_best_effort_task)
-      --outer_->num_pending_best_effort_may_block_workers_;
+      --outer_->num_unresolved_best_effort_may_block_;
 
     return true;
   }
@@ -1005,37 +1011,6 @@
     idle_workers_stack_cv_for_testing_->Wait();
 }
 
-void SchedulerWorkerPoolImpl::WakeUpOneWorkerLockRequired(
-    SchedulerWorkerActionExecutor* executor) {
-  if (workers_.empty()) {
-    ++num_wake_ups_before_start_;
-    return;
-  }
-
-  // Ensure that there is one worker that can run tasks on top of the idle
-  // stack, capacity permitting.
-  MaintainAtLeastOneIdleWorkerLockRequired(executor);
-
-  // If the worker on top of the idle stack can run tasks, wake it up.
-  if (NumberOfExcessWorkersLockRequired() < idle_workers_stack_.Size()) {
-    SchedulerWorker* worker_to_wakeup = idle_workers_stack_.Pop();
-    DCHECK(worker_to_wakeup);
-    executor->ScheduleWakeUp(worker_to_wakeup);
-  }
-}
-
-void SchedulerWorkerPoolImpl::WakeUpOneWorker() {
-  bool must_schedule_adjust_max_tasks = false;
-  SchedulerWorkerActionExecutor executor(tracked_ref_factory_.GetTrackedRef());
-  {
-    AutoSchedulerLock auto_lock(lock_);
-    WakeUpOneWorkerLockRequired(&executor);
-    must_schedule_adjust_max_tasks = MustScheduleAdjustMaxTasksLockRequired();
-  }
-  if (must_schedule_adjust_max_tasks)
-    ScheduleAdjustMaxTasks();
-}
-
 void SchedulerWorkerPoolImpl::MaintainAtLeastOneIdleWorkerLockRequired(
     SchedulerWorkerActionExecutor* executor) {
   if (workers_.size() == kMaxNumberOfWorkers)
@@ -1059,6 +1034,8 @@
     SchedulerWorkerActionExecutor* executor) {
   DCHECK_LT(workers_.size(), max_tasks_);
   DCHECK_LT(workers_.size(), kMaxNumberOfWorkers);
+  DCHECK(idle_workers_stack_.IsEmpty());
+
   // SchedulerWorker needs |lock_| as a predecessor for its thread lock
   // because in WakeUpOneWorker, |lock_| is first acquired and then
   // the thread lock is acquired when WakeUp is called on the worker.
@@ -1081,8 +1058,55 @@
   return worker;
 }
 
-size_t SchedulerWorkerPoolImpl::NumberOfExcessWorkersLockRequired() const {
-  return std::max<int>(0, workers_.size() - max_tasks_);
+size_t SchedulerWorkerPoolImpl::GetNumAwakeWorkersLockRequired() const {
+  DCHECK_GE(workers_.size(), idle_workers_stack_.Size());
+  size_t num_awake_workers = workers_.size() - idle_workers_stack_.Size();
+  DCHECK_GE(num_awake_workers, num_running_tasks_);
+  return num_awake_workers;
+}
+
+size_t SchedulerWorkerPoolImpl::GetDesiredNumAwakeWorkersLockRequired() const {
+  const size_t num_running_or_queued_best_effort_sequences =
+      num_running_best_effort_tasks_ +
+      priority_queue_.GetNumSequencesWithPriority(TaskPriority::BEST_EFFORT);
+  const size_t num_running_or_queued_foreground_sequences =
+      num_running_tasks_ + priority_queue_.Size() -
+      num_running_or_queued_best_effort_sequences;
+
+  const size_t workers_for_best_effort_sequences = std::min(
+      num_running_or_queued_best_effort_sequences, max_best_effort_tasks_);
+  const size_t workers_for_foreground_sequences =
+      num_running_or_queued_foreground_sequences;
+
+  return std::min(
+      {workers_for_best_effort_sequences + workers_for_foreground_sequences,
+       max_tasks_, kMaxNumberOfWorkers});
+}
+
+void SchedulerWorkerPoolImpl::EnsureEnoughWorkersLockRequired(
+    SchedulerWorkerActionExecutor* executor) {
+  const size_t desired_num_awake_workers =
+      GetDesiredNumAwakeWorkersLockRequired();
+  workers_.reserve(desired_num_awake_workers);
+
+  // Wake up the appropriate number of workers.
+  for (size_t i = GetNumAwakeWorkersLockRequired();
+       i < desired_num_awake_workers; ++i) {
+    MaintainAtLeastOneIdleWorkerLockRequired(executor);
+    SchedulerWorker* worker_to_wakeup = idle_workers_stack_.Pop();
+    DCHECK(worker_to_wakeup);
+    executor->ScheduleWakeUp(worker_to_wakeup);
+  }
+
+  // If no worker is about to call MaintainAtLeastOneIdleWorkerLockRequired(),
+  // call it here. This is useful in the case where the loop above didn't wake
+  // up any worker but a recent increase in |max_tasks| now makes it possible to
+  // keep an idle worker.
+  DCHECK_GE(GetNumAwakeWorkersLockRequired(), num_running_tasks_);
+  const size_t num_awake_workers_not_running_task =
+      GetNumAwakeWorkersLockRequired() - num_running_tasks_;
+  if (num_awake_workers_not_running_task == 0)
+    MaintainAtLeastOneIdleWorkerLockRequired(executor);
 }
 
 void SchedulerWorkerPoolImpl::AdjustMaxTasks() {
@@ -1092,8 +1116,6 @@
   SchedulerWorkerActionExecutor executor(tracked_ref_factory_.GetTrackedRef());
   AutoSchedulerLock auto_lock(lock_);
 
-  const size_t previous_max_tasks = max_tasks_;
-
   // Increment max tasks for each worker that has been within a MAY_BLOCK
   // ScopedBlockingCall for more than may_block_threshold.
   for (scoped_refptr<SchedulerWorker> worker : workers_) {
@@ -1108,18 +1130,8 @@
     }
   }
 
-  // Wake up a worker per pending sequence, capacity permitting.
-  const size_t num_pending_sequences = priority_queue_.Size();
-  const size_t num_wake_ups_needed =
-      std::min(max_tasks_ - previous_max_tasks, num_pending_sequences);
-
-  for (size_t i = 0; i < num_wake_ups_needed; ++i) {
-    // No need to call ScheduleAdjustMaxTasks() as the caller will
-    // take care of that for us.
-    WakeUpOneWorkerLockRequired(&executor);
-  }
-
-  MaintainAtLeastOneIdleWorkerLockRequired(&executor);
+  // Wake up workers according to the updated |max_tasks_|.
+  EnsureEnoughWorkersLockRequired(&executor);
 }
 
 void SchedulerWorkerPoolImpl::ScheduleAdjustMaxTasks() {
@@ -1161,32 +1173,28 @@
 }
 
 bool SchedulerWorkerPoolImpl::ShouldPeriodicallyAdjustMaxTasksLockRequired() {
-  // The maximum number of best-effort tasks that can run concurrently must be
-  // adjusted periodically when (1) the number of best-effort tasks that are
-  // currently running is equal to it and (2) there are workers running
-  // best-effort tasks within the scope of a MAY_BLOCK ScopedBlockingCall but
-  // haven't cause a max best-effort tasks increment yet.
-  // - When (1) is false: A newly posted best-effort task will be allowed to run
-  //   normally. There is no hurry to increase max best-effort tasks.
-  // - When (2) is false: AdjustMaxTasks() wouldn't affect
-  //   |max_best_effort_tasks_|.
-  if (num_running_best_effort_tasks_ >= max_best_effort_tasks_ &&
-      num_pending_best_effort_may_block_workers_ > 0) {
+  // AdjustMaxTasks() should be scheduled to periodically adjust |max_tasks_|
+  // and |max_best_effort_tasks_| when (1) the concurrency limits are not large
+  // enough to accommodate all queued and running sequences and an idle worker
+  // and (2) there are unresolved MAY_BLOCK ScopedBlockingCalls.
+  // - When (1) is false: No worker would be created or woken up if the
+  //   concurrency limits were increased, so there is no hurry to increase them.
+  // - When (2) is false: The concurrency limits could not be increased by
+  //   AdjustMaxTasks().
+
+  const size_t num_running_or_queued_best_effort_sequences =
+      num_running_best_effort_tasks_ +
+      priority_queue_.GetNumSequencesWithPriority(TaskPriority::BEST_EFFORT);
+  if (num_running_or_queued_best_effort_sequences > max_best_effort_tasks_ &&
+      num_unresolved_best_effort_may_block_ > 0) {
     return true;
   }
 
-  // The maximum number of tasks that can run concurrently must be adjusted
-  // periodically when (1) there are no idle workers that can do work (2) there
-  // are workers that are within the scope of a MAY_BLOCK ScopedBlockingCall but
-  // haven't cause a max tasks increment yet.
-  // - When (1) is false: A newly posted task will run on one of the idle
-  //   workers that are allowed to do work. There is no hurry to increase max
-  //   tasks.
-  // - When (2) is false: AdjustMaxTasks() wouldn't affect |max_tasks_|.
-  const int idle_workers_that_can_do_work =
-      idle_workers_stack_.Size() - NumberOfExcessWorkersLockRequired();
-  return idle_workers_that_can_do_work <= 0 &&
-         num_pending_may_block_workers_ > 0;
+  const size_t num_running_or_queued_sequences =
+      num_running_tasks_ + priority_queue_.Size();
+  constexpr size_t kIdleWorker = 1;
+  return num_running_or_queued_sequences + kIdleWorker > max_tasks_ &&
+         num_unresolved_may_block_ > 0;
 }
 
 void SchedulerWorkerPoolImpl::DecrementMaxTasksLockRequired(
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.h b/base/task/task_scheduler/scheduler_worker_pool_impl.h
index 8f0a1b5..38496f9 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.h
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.h
@@ -132,6 +132,10 @@
   // this call will hang.
   void WaitForWorkersIdleForTesting(size_t n);
 
+  // Waits until at least |n| workers are idle.
+  void WaitForWorkersIdleLockRequiredForTesting(size_t n)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
   // Waits until all workers are idle.
   void WaitForAllWorkersIdleForTesting();
 
@@ -176,24 +180,11 @@
   void OnCanScheduleSequence(
       SequenceAndTransaction sequence_and_transaction) override;
 
-  // Pushes the Sequence in |sequence_and_transaction| to |priority_queue_|.
-  void PushSequenceToPriorityQueue(
+  // Pushes the Sequence in |sequence_and_transaction| to |priority_queue_| and
+  // wakes up workers as appropriate.
+  void PushSequenceAndWakeUpWorkers(
       SequenceAndTransaction sequence_and_transaction);
 
-  // Waits until at least |n| workers are idle.
-  void WaitForWorkersIdleLockRequiredForTesting(size_t n)
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
-  // Wakes up the last worker from this worker pool to go idle, if any.
-  // Otherwise, creates and starts a worker, if permitted, and wakes it up.
-  void WakeUpOneWorker();
-
-  // Performs the same action as WakeUpOneWorker(), except:
-  // - Asserts |lock_| is acquired rather than acquires it.
-  // - Uses |executor| to delay waking up and starting the worker.
-  void WakeUpOneWorkerLockRequired(SchedulerWorkerActionExecutor* executor)
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
   // Creates a worker and schedules its start, if needed, to maintain one idle
   // worker, |max_tasks_| permitting.
   void MaintainAtLeastOneIdleWorkerLockRequired(
@@ -207,9 +198,17 @@
   scoped_refptr<SchedulerWorker> CreateAndRegisterWorkerLockRequired(
       SchedulerWorkerActionExecutor* executor) EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
-  // Returns the number of workers in the pool that should not run tasks due to
-  // the pool being over capacity.
-  size_t NumberOfExcessWorkersLockRequired() const
+  // Returns the number of workers that are awake (i.e. not on the idle stack).
+  size_t GetNumAwakeWorkersLockRequired() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  // Returns the desired number of awake workers, given current workload and
+  // concurrency limits.
+  size_t GetDesiredNumAwakeWorkersLockRequired() const
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  // Ensures that there are at least GetDesiredNumAwakeWorkersLockRequired()
+  // awake workers.
+  void EnsureEnoughWorkersLockRequired(SchedulerWorkerActionExecutor* executor)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Examines the list of SchedulerWorkers and increments |max_tasks_| for each
@@ -319,25 +318,21 @@
   // All workers owned by this worker pool.
   std::vector<scoped_refptr<SchedulerWorker>> workers_ GUARDED_BY(lock_);
 
-  // The maximum number of tasks that can run concurrently in this pool. Workers
-  // can be added as needed up until there are |max_tasks_| workers.
+  // Maximum number of tasks of any priority / BEST_EFFORT priority that can run
+  // concurrently in this pool.
   size_t max_tasks_ GUARDED_BY(lock_) = 0;
+  size_t max_best_effort_tasks_ GUARDED_BY(lock_) = 0;
 
-  // The maximum number of best-effort tasks that can run concurrently in this
-  // pool.
-  int max_best_effort_tasks_ GUARDED_BY(lock_) = 0;
+  // Number of tasks of any priority / BEST_EFFORT priority that are currently
+  // running in this pool.
+  size_t num_running_tasks_ GUARDED_BY(lock_) = 0;
+  size_t num_running_best_effort_tasks_ GUARDED_BY(lock_) = 0;
 
-  // The number of best-effort tasks that are currently running in this pool.
-  int num_running_best_effort_tasks_ GUARDED_BY(lock_) = 0;
-
-  // Number of workers that are within the scope of a MAY_BLOCK
-  // ScopedBlockingCall but haven't caused a max task increase yet.
-  int num_pending_may_block_workers_ GUARDED_BY(lock_) = 0;
-
-  // Number of workers that are running a TaskPriority::BEST_EFFORT task and are
-  // within the scope of a MAY_BLOCK ScopedBlockingCall but haven't caused a max
-  // task increase yet.
-  int num_pending_best_effort_may_block_workers_ GUARDED_BY(lock_) = 0;
+  // Number of workers running a task of any priority / BEST_EFFORT priority
+  // that are within the scope of a MAY_BLOCK ScopedBlockingCall but haven't
+  // caused a max tasks increase yet.
+  int num_unresolved_may_block_ GUARDED_BY(lock_) = 0;
+  int num_unresolved_best_effort_may_block_ GUARDED_BY(lock_) = 0;
 
   // Stack of idle workers. Initially, all workers are on this stack. A worker
   // is removed from the stack before its WakeUp() function is called and when
@@ -350,10 +345,6 @@
   std::unique_ptr<ConditionVariable> idle_workers_stack_cv_for_testing_
       GUARDED_BY(lock_);
 
-  // Number of wake ups that occurred before Start(). Never modified after
-  // Start() (i.e. can be read without synchronization after Start()).
-  int num_wake_ups_before_start_ GUARDED_BY(lock_) = 0;
-
   // Stack that contains the timestamps of when workers get cleaned up.
   // Timestamps get popped off the stack as new workers are added.
   base::stack<TimeTicks, std::vector<TimeTicks>> cleanup_timestamps_
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc b/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
index 7f542de..6b0a472 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <atomic>
 #include <memory>
 #include <unordered_set>
 #include <vector>
@@ -29,6 +30,7 @@
 #include "base/task/task_features.h"
 #include "base/task/task_scheduler/delayed_task_manager.h"
 #include "base/task/task_scheduler/scheduler_task_runner_delegate.h"
+#include "base/task/task_scheduler/scheduler_worker_observer.h"
 #include "base/task/task_scheduler/scheduler_worker_pool_params.h"
 #include "base/task/task_scheduler/sequence.h"
 #include "base/task/task_scheduler/sequence_sort_key.h"
@@ -69,6 +71,7 @@
 // is allowed to cleanup.
 constexpr TimeDelta kReclaimTimeForCleanupTests =
     TimeDelta::FromMilliseconds(500);
+constexpr size_t kLargeNumber = 512;
 
 class TaskSchedulerWorkerPoolImplTestBase
     : public SchedulerWorkerPool::Delegate {
@@ -97,23 +100,28 @@
     mock_scheduler_task_runner_delegate_.SetWorkerPool(worker_pool_.get());
   }
 
-  void StartWorkerPool(
-      TimeDelta suggested_reclaim_time,
-      size_t max_tasks,
-      Optional<TimeDelta> may_block_threshold = Optional<TimeDelta>()) {
+  void StartWorkerPool(TimeDelta suggested_reclaim_time,
+                       size_t max_tasks,
+                       Optional<int> max_best_effort_tasks = nullopt,
+                       SchedulerWorkerObserver* worker_observer = nullptr,
+                       Optional<TimeDelta> may_block_threshold = nullopt) {
     ASSERT_TRUE(worker_pool_);
     worker_pool_->Start(
-        SchedulerWorkerPoolParams(max_tasks, suggested_reclaim_time), max_tasks,
-        service_thread_.task_runner(), nullptr,
+        SchedulerWorkerPoolParams(max_tasks, suggested_reclaim_time),
+        max_best_effort_tasks ? max_best_effort_tasks.value() : max_tasks,
+        service_thread_.task_runner(), worker_observer,
         SchedulerWorkerPoolImpl::WorkerEnvironment::NONE, may_block_threshold);
   }
 
   void CreateAndStartWorkerPool(
       TimeDelta suggested_reclaim_time = TimeDelta::Max(),
       size_t max_tasks = kMaxTasks,
-      Optional<TimeDelta> may_block_threshold = Optional<TimeDelta>()) {
+      Optional<int> max_best_effort_tasks = nullopt,
+      SchedulerWorkerObserver* worker_observer = nullptr,
+      Optional<TimeDelta> may_block_threshold = nullopt) {
     CreateWorkerPool();
-    StartWorkerPool(suggested_reclaim_time, max_tasks, may_block_threshold);
+    StartWorkerPool(suggested_reclaim_time, max_tasks, max_best_effort_tasks,
+                    worker_observer, may_block_threshold);
   }
 
   Thread service_thread_;
@@ -1181,6 +1189,7 @@
   threads_continue.Signal();
   task_tracker_.FlushForTesting();
 }
+
 // Verify that workers become idle when the pool is over-capacity and that
 // those workers do no work.
 TEST_P(TaskSchedulerWorkerPoolBlockingTest, WorkersIdleWhenOverCapacity) {
@@ -1259,6 +1268,8 @@
   // ScopedBlockingCall never increases the max tasks.
   CreateAndStartWorkerPool(TimeDelta::Max(),  // |suggested_reclaim_time|
                            kMaxTasks,         // |max_tasks|
+                           nullopt,           // |max_best_effort_tasks|
+                           nullptr,           // |worker_observer|
                            TimeDelta::Max()   // |may_block_threshold|
   );
   ASSERT_EQ(worker_pool_->GetMaxTasksForTesting(), kMaxTasks);
@@ -1544,10 +1555,9 @@
 // is honored.
 TEST_F(TaskSchedulerWorkerPoolImplStartInBodyTest, MaxBestEffortTasks) {
   constexpr int kMaxBestEffortTasks = kMaxTasks / 2;
-  worker_pool_->Start(
-      SchedulerWorkerPoolParams(kMaxTasks, base::TimeDelta::Max()),
-      kMaxBestEffortTasks, service_thread_.task_runner(), nullptr,
-      SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
+  StartWorkerPool(TimeDelta::Max(),      // |suggested_reclaim_time|
+                  kMaxTasks,             // |max_tasks|
+                  kMaxBestEffortTasks);  // |max_best_effort_tasks|
   const scoped_refptr<TaskRunner> foreground_runner =
       test::CreateTaskRunnerWithTraits({MayBlock()},
                                        &mock_scheduler_task_runner_delegate_);
@@ -1594,10 +1604,113 @@
   unblock_best_effort_tasks.Signal();
   extra_best_effort_task_running.Wait();
 
-  // Tear down.
+  // Wait for all tasks to complete before exiting to avoid invalid accesses.
   task_tracker_.FlushForTesting();
 }
 
+// Verify that flooding the pool with BEST_EFFORT tasks doesn't cause the
+// creation of more than |max_best_effort_tasks| + 1 workers.
+TEST_F(TaskSchedulerWorkerPoolImplStartInBodyTest,
+       FloodBestEffortTasksDoesNotCreateTooManyWorkers) {
+  constexpr size_t kMaxBestEffortTasks = kMaxTasks / 2;
+  StartWorkerPool(TimeDelta::Max(),      // |suggested_reclaim_time|
+                  kMaxTasks,             // |max_tasks|
+                  kMaxBestEffortTasks);  // |max_best_effort_tasks|
+
+  const scoped_refptr<TaskRunner> runner =
+      test::CreateTaskRunnerWithTraits({TaskPriority::BEST_EFFORT, MayBlock()},
+                                       &mock_scheduler_task_runner_delegate_);
+
+  for (size_t i = 0; i < kLargeNumber; ++i) {
+    runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
+                       EXPECT_LE(worker_pool_->NumberOfWorkersForTesting(),
+                                 kMaxBestEffortTasks + 1);
+                     }));
+  }
+
+  // Wait for all tasks to complete before exiting to avoid invalid accesses.
+  task_tracker_.FlushForTesting();
+}
+
+namespace {
+
+// A SchedulerWorkerObserver that lets one worker start, then waits until
+// UnblockWorkers() is called before letting any other workers start.
+class HoldWorkersObserver : public SchedulerWorkerObserver {
+ public:
+  HoldWorkersObserver() = default;
+
+  void UnblockWorkers() { unblock_workers_.Signal(); }
+
+  // SchedulerWorkerObserver:
+  void OnSchedulerWorkerMainEntry() override {
+    bool expected = false;
+    if (allowed_first_worker_.compare_exchange_strong(expected, true))
+      return;
+    test::WaitWithoutBlockingObserver(&unblock_workers_);
+  }
+  void OnSchedulerWorkerMainExit() override {}
+
+ private:
+  std::atomic_bool allowed_first_worker_{false};
+  WaitableEvent unblock_workers_;
+
+  DISALLOW_COPY_AND_ASSIGN(HoldWorkersObserver);
+};
+
+}  // namespace
+
+// Previously, a WILL_BLOCK ScopedBlockingCall unconditionally woke up a worker
+// if the priority queue was non-empty. Sometimes, that caused multiple workers
+// to be woken up for the same sequence. This test verifies that it is no longer
+// the case:
+// 1. Post task A that blocks until an event is signaled.
+// 2. Post task B. It can't be scheduled because the 1st worker is busy and
+//    the 2nd worker is blocked by HoldWorkersObserver.
+// 3. Signal the event so that task A enters a first WILL_BLOCK
+//    ScopedBlockingCall. This should no-op because there are already enough
+//    workers (previously, a worker would be woken up because the priority
+//    queue isn't empty).
+// 4. Task A enters a second WILL_BLOCK ScopedBlockingCall. This should no-op
+//    because there are already enough workers.
+// 5. Unblock HoldWorkersObserver and wait for all tasks to complete.
+TEST_F(TaskSchedulerWorkerPoolImplStartInBodyTest,
+       RepeatedWillBlockDoesNotCreateTooManyWorkers) {
+  constexpr size_t kNumWorkers = 2U;
+  HoldWorkersObserver worker_observer;
+  StartWorkerPool(TimeDelta::Max(),   // |suggested_reclaim_time|
+                  kNumWorkers,        // |max_tasks|
+                  nullopt,            // |max_best_effort_tasks|
+                  &worker_observer);  // |worker_observer|
+  const scoped_refptr<TaskRunner> runner = test::CreateTaskRunnerWithTraits(
+      {MayBlock()}, &mock_scheduler_task_runner_delegate_);
+
+  WaitableEvent hold_will_block_task;
+  runner->PostTask(
+      FROM_HERE, BindLambdaForTesting([&]() {
+        test::WaitWithoutBlockingObserver(&hold_will_block_task);
+        for (size_t i = 0; i < kLargeNumber; ++i) {
+          // Number of workers should not increase when there is enough capacity
+          // to accommodate queued and running sequences.
+          ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
+          EXPECT_EQ(kNumWorkers, worker_pool_->NumberOfWorkersForTesting());
+        }
+
+        worker_observer.UnblockWorkers();
+      }));
+
+  runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
+                     EXPECT_LE(worker_pool_->NumberOfWorkersForTesting(),
+                               kNumWorkers);
+                   }));
+  hold_will_block_task.Signal();
+
+  // Join the pool to avoid invalid accesses to |worker_observer|.
+  task_tracker_.FlushForTesting();
+  worker_pool_->JoinForTesting();
+  worker_pool_.reset();
+}
+
 namespace {
 
 class TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index 01e2135f..f6125dd4 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -338,6 +338,7 @@
     "sync/0x?/model_type/PRIORITY_PREFERENCE",
     "sync/0x?/model_type/READING_LIST",
     "sync/0x?/model_type/SEARCH_ENGINE",
+    "sync/0x?/model_type/SECURITY_EVENT",
     "sync/0x?/model_type/SEND_TAB_TO_SELF",
     "sync/0x?/model_type/SESSION",
     "sync/0x?/model_type/SYNCED_NOTIFICATION",
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
index ddbfa14..9ffb137e 100755
--- a/build/android/gyp/apkbuilder.py
+++ b/build/android/gyp/apkbuilder.py
@@ -30,19 +30,18 @@
 def _ParseArgs(args):
   parser = argparse.ArgumentParser()
   build_utils.AddDepfileOption(parser)
-  parser.add_argument('--assets',
-                      help='GYP-list of files to add as assets in the form '
-                           '"srcPath:zipPath", where ":zipPath" is optional.',
-                      default='[]')
-  parser.add_argument('--java-resources',
-                      help='GYP-list of java_resources JARs to include.',
-                      default='[]')
+  parser.add_argument(
+      '--assets',
+      help='GYP-list of files to add as assets in the form '
+      '"srcPath:zipPath", where ":zipPath" is optional.')
+  parser.add_argument(
+      '--java-resources', help='GYP-list of java_resources JARs to include.')
   parser.add_argument('--write-asset-list',
                       action='store_true',
                       help='Whether to create an assets/assets_list file.')
-  parser.add_argument('--uncompressed-assets',
-                      help='Same as --assets, except disables compression.',
-                      default='[]')
+  parser.add_argument(
+      '--uncompressed-assets',
+      help='Same as --assets, except disables compression.')
   parser.add_argument('--resource-apk',
                       help='An .ap_ file built using aapt',
                       required=True)
@@ -51,10 +50,6 @@
                       required=True)
   parser.add_argument('--format', choices=['apk', 'bundle-module'],
                       default='apk', help='Specify output format.')
-  parser.add_argument('--apk-pak-info-path',
-                      help='Path to the *.apk.pak.info file')
-  parser.add_argument('--apk-res-info-path',
-                      help='Path to the *.apk.res.info file')
   parser.add_argument('--dex-file',
                       help='Path to the classes.dex to use')
   parser.add_argument('--uncompress-dex', action='store_true',
@@ -74,13 +69,13 @@
   parser.add_argument('--secondary-android-abi',
                       help='The secondary Android architecture to use for'
                            'secondary native libraries')
-  parser.add_argument('--native-lib-placeholders',
-                      help='GYP-list of native library placeholders to add.',
-                      default='[]')
-  parser.add_argument('--secondary-native-lib-placeholders',
-                      help='GYP-list of native library placeholders to add '
-                           'for the secondary ABI',
-                      default='[]')
+  parser.add_argument(
+      '--native-lib-placeholders',
+      help='GYP-list of native library placeholders to add.')
+  parser.add_argument(
+      '--secondary-native-lib-placeholders',
+      help='GYP-list of native library placeholders to add '
+      'for the secondary ABI')
   parser.add_argument('--uncompress-shared-libraries', default='False',
       choices=['true', 'True', 'false', 'False'],
       help='Whether to uncompress native shared libraries. Argument must be '
@@ -226,24 +221,6 @@
                                  compress=compress)
 
 
-def _MergeResInfoFiles(res_info_path, resource_apk):
-  resource_apk_info_path = resource_apk + '.info'
-  shutil.copy(resource_apk_info_path, res_info_path)
-
-
-def _FilterPakInfoPaths(assets):
-  return [f.split(':')[0] + '.info' for f in assets if f.endswith('.pak')]
-
-
-def _MergePakInfoFiles(merged_path, pak_infos):
-  info_lines = set()
-  for pak_info_path in pak_infos:
-    with open(pak_info_path, 'r') as src_info_file:
-      info_lines.update(src_info_file.readlines())
-  with open(merged_path, 'w') as merged_info_file:
-    merged_info_file.writelines(sorted(info_lines))
-
-
 def main(args):
   args = build_utils.ExpandFileArgs(args)
   options = _ParseArgs(args)
@@ -266,11 +243,6 @@
   assets = _ExpandPaths(options.assets)
   uncompressed_assets = _ExpandPaths(options.uncompressed_assets)
 
-  if options.apk_pak_info_path:
-    pak_infos = _FilterPakInfoPaths(
-        options.assets + options.uncompressed_assets)
-    depfile_deps.extend(pak_infos)
-
   # Included via .build_config, so need to write it to depfile.
   depfile_deps.extend(x[0] for x in assets)
   depfile_deps.extend(x[0] for x in uncompressed_assets)
@@ -388,11 +360,6 @@
                 apk_root_dir + apk_path,
                 data=java_resource_jar.read(apk_path))
 
-      if options.apk_pak_info_path:
-        _MergePakInfoFiles(options.apk_pak_info_path, pak_infos)
-      if options.apk_res_info_path:
-        _MergeResInfoFiles(options.apk_res_info_path, options.resource_apk)
-
     if options.format == 'apk':
       finalize_apk.FinalizeApk(options.apksigner_path, options.zipalign_path,
                                f.name, f.name, options.key_path,
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index 1cc1878..a3601747 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -646,7 +646,7 @@
         lines.update(zip_info_file.readlines())
   for dest, source in renamed_paths.iteritems():
     lines.add('Rename:{},{}\n'.format(dest, source))
-  with open(apk_info_path, 'w') as info_file:
+  with build_utils.AtomicOutput(apk_info_path) as info_file:
     info_file.writelines(sorted(lines))
 
 
diff --git a/build/android/gyp/create_size_info_files.py b/build/android/gyp/create_size_info_files.py
new file mode 100755
index 0000000..5b248e4
--- /dev/null
+++ b/build/android/gyp/create_size_info_files.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Creates size-info/*.info files used by SuperSize."""
+
+import argparse
+import os
+import sys
+import zipfile
+
+from util import build_utils
+from util import jar_info_utils
+from util import md5_check
+
+
+def _MergeResInfoFiles(res_info_path, info_paths):
+  # Concatenate them all.
+  # only_if_changed=False since no build rules depend on this as an input.
+  with build_utils.AtomicOutput(res_info_path, only_if_changed=False) as dst:
+    for p in info_paths:
+      with open(p) as src:
+        dst.write(src.read())
+
+
+def _PakInfoPathsForAssets(assets):
+  return [f.split(':')[0] + '.info' for f in assets if f.endswith('.pak')]
+
+
+def _MergePakInfoFiles(merged_path, pak_infos):
+  info_lines = set()
+  for pak_info_path in pak_infos:
+    with open(pak_info_path, 'r') as src_info_file:
+      info_lines.update(src_info_file.readlines())
+  # only_if_changed=False since no build rules depend on this as an input.
+  with build_utils.AtomicOutput(merged_path, only_if_changed=False) as f:
+    f.writelines(sorted(info_lines))
+
+
+def _FullJavaNameFromClassFilePath(path):
+  # Input:  base/android/java/src/org/chromium/Foo.class
+  # Output: base.android.java.src.org.chromium.Foo
+  if not path.endswith('.class'):
+    return ''
+  path = os.path.splitext(path)[0]
+  parts = []
+  while path:
+    # Use split to be platform independent.
+    head, tail = os.path.split(path)
+    path = head
+    parts.append(tail)
+  parts.reverse()  # Package comes first
+  return '.'.join(parts)
+
+
+def _MergeJarInfoFiles(output, inputs):
+  """Merge several .jar.info files to generate an .apk.jar.info.
+
+  Args:
+    output: output file path.
+    inputs: List of .info.jar or .jar files.
+  """
+  info_data = dict()
+  for path in inputs:
+    # android_java_prebuilt adds jar files in the src directory (relative to
+    #     the output directory, usually ../../third_party/example.jar).
+    # android_aar_prebuilt collects jar files in the aar file and uses the
+    #     java_prebuilt rule to generate gen/example/classes.jar files.
+    # We scan these prebuilt jars to parse each class path for the FQN. This
+    #     allows us to later map these classes back to their respective src
+    #     directories.
+    # TODO(agrieve): This should probably also check that the mtime of the .info
+    #     is newer than that of the .jar, or change prebuilts to always output
+    #     .info files so that they always exist (and change the depfile to
+    #     depend directly on them).
+    if path.endswith('.info'):
+      info_data.update(jar_info_utils.ParseJarInfoFile(path))
+    else:
+      with zipfile.ZipFile(path) as zip_info:
+        for name in zip_info.namelist():
+          fully_qualified_name = _FullJavaNameFromClassFilePath(name)
+          if fully_qualified_name:
+            info_data[fully_qualified_name] = '{}/{}'.format(path, name)
+
+  # only_if_changed=False since no build rules depend on this as an input.
+  with build_utils.AtomicOutput(output, only_if_changed=False) as f:
+    jar_info_utils.WriteJarInfoFile(f, info_data)
+
+
+def _FindJarInputs(jar_paths):
+  ret = []
+  for jar_path in jar_paths:
+    jar_info_path = jar_path + '.info'
+    if os.path.exists(jar_info_path):
+      ret.append(jar_info_path)
+    else:
+      ret.append(jar_path)
+  return ret
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = argparse.ArgumentParser(description=__doc__)
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument(
+      '--jar-info-path', required=True, help='Output .jar.info file')
+  parser.add_argument(
+      '--pak-info-path', required=True, help='Output .pak.info file')
+  parser.add_argument(
+      '--res-info-path', required=True, help='Output .res.info file')
+  parser.add_argument(
+      '--jar-files',
+      required=True,
+      action='append',
+      help='GN-list of .jar file paths')
+  parser.add_argument(
+      '--assets',
+      required=True,
+      action='append',
+      help='GN-list of files to add as assets in the form '
+      '"srcPath:zipPath", where ":zipPath" is optional.')
+  parser.add_argument(
+      '--uncompressed-assets',
+      required=True,
+      action='append',
+      help='Same as --assets, except disables compression.')
+  parser.add_argument(
+      '--resource-apk',
+      dest='resource_apks',
+      required=True,
+      action='append',
+      help='An .ap_ file built using aapt')
+
+  options = parser.parse_args(args)
+
+  options.jar_files = build_utils.ParseGnList(options.jar_files)
+  options.assets = build_utils.ParseGnList(options.assets)
+  options.uncompressed_assets = build_utils.ParseGnList(
+      options.uncompressed_assets)
+
+  jar_inputs = _FindJarInputs(set(options.jar_files))
+  pak_inputs = _PakInfoPathsForAssets(options.assets +
+                                      options.uncompressed_assets)
+  res_inputs = [p + '.info' for p in options.resource_apks]
+
+  # Don't bother re-running if no .info files have changed (saves ~250ms).
+  md5_check.CallAndRecordIfStale(
+      lambda: _MergeJarInfoFiles(options.jar_info_path, jar_inputs),
+      input_paths=jar_inputs,
+      output_paths=[options.jar_info_path])
+
+  # Always recreate these (just as fast as md5 checking them).
+  _MergePakInfoFiles(options.pak_info_path, pak_inputs)
+  _MergeResInfoFiles(options.res_info_path, res_inputs)
+
+  all_inputs = jar_inputs + pak_inputs + res_inputs
+  build_utils.WriteDepfile(
+      options.depfile,
+      options.jar_info_path,
+      inputs=all_inputs,
+      add_pydeps=False)
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/build/android/gyp/merge_jar_info_files.pydeps b/build/android/gyp/create_size_info_files.pydeps
similarity index 61%
rename from build/android/gyp/merge_jar_info_files.pydeps
rename to build/android/gyp/create_size_info_files.pydeps
index 710091c..4ab7f94 100644
--- a/build/android/gyp/merge_jar_info_files.pydeps
+++ b/build/android/gyp/create_size_info_files.pydeps
@@ -1,7 +1,7 @@
 # Generated by running:
-#   build/print_python_deps.py --root build/android/gyp --output build/android/gyp/merge_jar_info_files.pydeps build/android/gyp/merge_jar_info_files.py
+#   build/print_python_deps.py --root build/android/gyp --output build/android/gyp/create_size_info_files.pydeps build/android/gyp/create_size_info_files.py
 ../../gn_helpers.py
-merge_jar_info_files.py
+create_size_info_files.py
 util/__init__.py
 util/build_utils.py
 util/jar_info_utils.py
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index 61e577af..20ffbaa 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -21,7 +21,8 @@
 
 import jar
 
-sys.path.append(
+sys.path.insert(
+    0,
     os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 'colorama', 'src'))
 import colorama
 
@@ -468,13 +469,6 @@
     logging.info('Completed all steps in _OnStaleMd5')
 
 
-def _ParseAndFlattenGnLists(gn_lists):
-  ret = []
-  for arg in gn_lists:
-    ret.extend(build_utils.ParseGnList(arg))
-  return ret
-
-
 def _ParseOptions(argv):
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
@@ -558,13 +552,13 @@
   options, args = parser.parse_args(argv)
   build_utils.CheckOptions(options, parser, required=('jar_path',))
 
-  options.bootclasspath = _ParseAndFlattenGnLists(options.bootclasspath)
-  options.full_classpath = _ParseAndFlattenGnLists(options.full_classpath)
-  options.interface_classpath = _ParseAndFlattenGnLists(
+  options.bootclasspath = build_utils.ParseGnList(options.bootclasspath)
+  options.full_classpath = build_utils.ParseGnList(options.full_classpath)
+  options.interface_classpath = build_utils.ParseGnList(
       options.interface_classpath)
-  options.processorpath = _ParseAndFlattenGnLists(options.processorpath)
-  options.processors = _ParseAndFlattenGnLists(options.processors)
-  options.java_srcjars = _ParseAndFlattenGnLists(options.java_srcjars)
+  options.processorpath = build_utils.ParseGnList(options.processorpath)
+  options.processors = build_utils.ParseGnList(options.processors)
+  options.java_srcjars = build_utils.ParseGnList(options.java_srcjars)
 
   if options.java_version == '1.8' and options.bootclasspath:
     # Android's boot jar doesn't contain all java 8 classes.
diff --git a/build/android/gyp/merge_jar_info_files.py b/build/android/gyp/merge_jar_info_files.py
deleted file mode 100755
index 2c3da27..0000000
--- a/build/android/gyp/merge_jar_info_files.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Merges .jar.info files into one for APKs."""
-
-import argparse
-import os
-import sys
-import zipfile
-
-from util import build_utils
-from util import jar_info_utils
-
-
-def _FullJavaNameFromClassFilePath(path):
-  # Input:  base/android/java/src/org/chromium/Foo.class
-  # Output: base.android.java.src.org.chromium.Foo
-  if not path.endswith('.class'):
-    return ''
-  path = os.path.splitext(path)[0]
-  parts = []
-  while path:
-    # Use split to be platform independent.
-    head, tail = os.path.split(path)
-    path = head
-    parts.append(tail)
-  parts.reverse()  # Package comes first
-  return '.'.join(parts)
-
-
-def _MergeInfoFiles(output, inputs):
-  """Merge several .jar.info files to generate an .apk.jar.info.
-
-  Args:
-    output: output file path.
-    inputs: List of .info.jar or .jar files.
-  """
-  info_data = dict()
-  for path in inputs:
-    # android_java_prebuilt adds jar files in the src directory (relative to
-    #     the output directory, usually ../../third_party/example.jar).
-    # android_aar_prebuilt collects jar files in the aar file and uses the
-    #     java_prebuilt rule to generate gen/example/classes.jar files.
-    # We scan these prebuilt jars to parse each class path for the FQN. This
-    #     allows us to later map these classes back to their respective src
-    #     directories.
-    # TODO(agrieve): This should probably also check that the mtime of the .info
-    #     is newer than that of the .jar, or change prebuilts to always output
-    #     .info files so that they always exist (and change the depfile to
-    #     depend directly on them).
-    if path.endswith('.info'):
-      info_data.update(jar_info_utils.ParseJarInfoFile(path))
-    else:
-      with zipfile.ZipFile(path) as zip_info:
-        for name in zip_info.namelist():
-          fully_qualified_name = _FullJavaNameFromClassFilePath(name)
-          if fully_qualified_name:
-            info_data[fully_qualified_name] = '{}/{}'.format(path, name)
-
-  with build_utils.AtomicOutput(output) as f:
-    jar_info_utils.WriteJarInfoFile(f, info_data)
-
-
-def _FindInputs(jar_paths):
-  ret = []
-  for jar_path in jar_paths:
-    jar_info_path = jar_path + '.info'
-    if os.path.exists(jar_info_path):
-      ret.append(jar_info_path)
-    else:
-      ret.append(jar_path)
-  return ret
-
-
-def main(args):
-  args = build_utils.ExpandFileArgs(args)
-  parser = argparse.ArgumentParser(description=__doc__)
-  build_utils.AddDepfileOption(parser)
-  parser.add_argument('--output', required=True, help='Output .jar.info file')
-  parser.add_argument(
-      '--apk-jar-file', help='Path to main .jar file (for APKs).')
-  parser.add_argument('--dep-jar-files', required=True,
-                      help='GN-list of dependent .jar file paths')
-
-  options = parser.parse_args(args)
-  options.dep_jar_files = build_utils.ParseGnList(options.dep_jar_files)
-  jar_files = list(options.dep_jar_files)
-  if options.apk_jar_file:
-    jar_files.append(options.apk_jar_file)
-  inputs = _FindInputs(jar_files)
-
-  def _OnStaleMd5():
-    _MergeInfoFiles(options.output, inputs)
-
-  # Don't bother re-running if no .info files have changed.
-  build_utils.CallAndWriteDepfileIfStale(
-      _OnStaleMd5,
-      options,
-      input_paths=inputs,
-      output_paths=[options.output],
-      depfile_deps=inputs,
-      add_pydeps=False)
-
-
-if __name__ == '__main__':
-  main(sys.argv[1:])
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index b5fd17a..ad26224 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -83,24 +83,33 @@
     return dict(l.rstrip().split('=', 1) for l in f)
 
 
-def ParseGnList(gn_string):
-  """Converts a command-line parameter into a list.
+def ParseGnList(value):
+  """Converts a "GN-list" command-line parameter into a list.
 
-  If the input starts with a '[' it is assumed to be a GN-formatted list and
-  it will be parsed accordingly. When empty an empty list will be returned.
-  Otherwise, the parameter will be treated as a single raw string (not
-  GN-formatted in that it's not assumed to have literal quotes that must be
-  removed) and a list will be returned containing that string.
+  Conversions handled:
+    * None -> []
+    * '' -> []
+    * 'asdf' -> ['asdf']
+    * '["a", "b"]' -> ['a', 'b']
+    * ['["a", "b"]', 'c'] -> ['a', 'b', 'c']  (flattened list)
 
   The common use for this behavior is in the Android build where things can
   take lists of @FileArg references that are expanded via ExpandFileArgs.
   """
-  if gn_string.startswith('['):
-    parser = gn_helpers.GNValueParser(gn_string)
-    return parser.ParseList()
-  if len(gn_string):
-    return [ gn_string ]
-  return []
+  # Convert None to [].
+  if not value:
+    return []
+  # Convert a list of GN lists to a flattened list.
+  if isinstance(value, list):
+    ret = []
+    for arg in value:
+      ret.extend(ParseGnList(arg))
+    return ret
+  # Convert normal GN list.
+  if value.startswith('['):
+    return gn_helpers.GNValueParser(value).ParseList()
+  # Convert a single string value to a list.
+  return [value]
 
 
 def CheckOptions(options, parser, required=None):
diff --git a/build/android/gyp/util/jar_info_utils.py b/build/android/gyp/util/jar_info_utils.py
index 389d71b..677e4e42 100644
--- a/build/android/gyp/util/jar_info_utils.py
+++ b/build/android/gyp/util/jar_info_utils.py
@@ -43,7 +43,7 @@
       path of Java source files that where extracted from an .srcjar into a
       temporary location.
   """
-  for fully_qualified_name, path in info_data.iteritems():
+  for fully_qualified_name, path in sorted(info_data.iteritems()):
     if source_file_map and path in source_file_map:
       path = source_file_map[path]
       assert not path.startswith('/tmp'), (
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index a516ba92..f3001ac 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -230,7 +230,7 @@
     check_android_configuration = false
 
     # Enables instantiation of 64-bit browser targets.
-    enable_64_bit_browser = false
+    enable_64_bit_browser = true
   }
 
   assert(!(check_android_configuration && is_java_debug),
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 0f47c47..d7782ab9 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2340,37 +2340,63 @@
   # Variables:
   #   build_config: Path to APK's build config file. Used to extract the
   #       list of input .jar files from its dependencies.
-  #   output: Output file path.
+  #   name: Name of the apk or app bundle (e.g. "Foo.apk").
+  #   packaged_resources_path: Path to .ap_ file.
   #
-  template("create_final_jar_info") {
-    _output = invoker.output
-    _build_config = invoker.build_config
-    _rebased_build_config = rebase_path(_build_config, root_build_dir)
+  template("create_size_info_files") {
     action_with_pydeps(target_name) {
       forward_variables_from(invoker,
                              [
                                "testonly",
                                "deps",
                              ])
-      script = "//build/android/gyp/merge_jar_info_files.py"
-      inputs = [
-        _build_config,
-      ]
+      script = "//build/android/gyp/create_size_info_files.py"
+      _jar_info_path = "$root_build_dir/size-info/${invoker.name}.jar.info"
+      _pak_info_path = "$root_build_dir/size-info/${invoker.name}.pak.info"
+      _res_info_path = "$root_build_dir/size-info/${invoker.name}.res.info"
       outputs = [
-        _output,
+        _jar_info_path,
+        _pak_info_path,
+        _res_info_path,
       ]
       depfile = "$target_gen_dir/$target_name.d"
       args = [
         "--depfile",
         rebase_path(depfile, root_build_dir),
-        "--output",
-        rebase_path(_output, root_build_dir),
-        "--dep-jar-files=@FileArg(" +
-            "$_rebased_build_config:deps_info:javac_full_classpath)",
+        "--jar-info-path",
+        rebase_path(_jar_info_path, root_build_dir),
+        "--pak-info-path",
+        rebase_path(_pak_info_path, root_build_dir),
+        "--res-info-path",
+        rebase_path(_res_info_path, root_build_dir),
       ]
-      if (!invoker.is_bundle) {
+      _is_bundle = defined(invoker.module_build_configs)
+      if (_is_bundle) {
+        inputs = invoker.module_build_configs
+        foreach(_build_config, invoker.module_build_configs) {
+          _rebased_build_config = rebase_path(_build_config, root_build_dir)
+          args += [
+            "--jar-files=@FileArg($_rebased_build_config:deps_info:unprocessed_jar_path)",
+            "--jar-files=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)",
+            "--resource-apk=@FileArg($_rebased_build_config:deps_info:proto_resources_path)",
+            "--assets=@FileArg($_rebased_build_config:assets)",
+            "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)",
+          ]
+        }
+      } else {
+        inputs = [
+          invoker.build_config,
+          invoker.packaged_resources_path,
+        ]
+        _rebased_build_config =
+            rebase_path(invoker.build_config, root_build_dir)
         args += [
-          "--apk-jar-file=@FileArg($_rebased_build_config:deps_info:jar_path)",
+          "--jar-files=@FileArg($_rebased_build_config:deps_info:jar_path)",
+          "--jar-files=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)",
+          "--resource-apk",
+          rebase_path(invoker.packaged_resources_path, root_build_dir),
+          "--assets=@FileArg($_rebased_build_config:assets)",
+          "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)",
         ]
       }
     }
@@ -2482,22 +2508,6 @@
         # TODO(mlopatkin) We are relying on the fact that assets_build_config is
         # an APK build_config.
         args += [ "--java-resources=@FileArg($_rebased_build_config:java_resources_jars)" ]
-
-        if (defined(invoker.apk_name)) {
-          # The supersize tool will search in this directory for each apk.
-          _apk_pak_info_path = "size-info/${invoker.apk_name}.apk.pak.info"
-          _apk_res_info_path = "size-info/${invoker.apk_name}.apk.res.info"
-          args += [
-            "--apk-pak-info-path",
-            _apk_pak_info_path,
-            "--apk-res-info-path",
-            _apk_res_info_path,
-          ]
-          outputs += [
-            "$root_build_dir/$_apk_pak_info_path",
-            "$root_build_dir/$_apk_res_info_path",
-          ]
-        }
       }
       if (defined(invoker.write_asset_list) && invoker.write_asset_list) {
         args += [ "--write-asset-list" ]
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 4743b20..bff3882 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2664,18 +2664,25 @@
 
     if (!_is_bundle_module) {
       # Generate size-info/*.jar.info files.
-      if (defined(invoker.name) && _proguard_enabled) {
-        _jar_info_target = "${target_name}__jar_size_info"
-        create_final_jar_info(_jar_info_target) {
-          is_bundle = false
-          output = "$root_build_dir/size-info/${invoker.name}.apk.jar.info"
-          build_config = _build_config
-          deps = [
-            ":$_build_config_target",
-            ":$_java_target",
-          ]
+      if (defined(invoker.name)) {
+        # Create size info files for targets that care about size
+        # (have proguard enabled).
+        if (_proguard_enabled) {
+          _size_info_target = "${target_name}__size_info"
+          create_size_info_files(_size_info_target) {
+            name = "${invoker.name}.apk"
+            build_config = _build_config
+            packaged_resources_path = _packaged_resources_path
+            deps = _deps + [
+                     ":$_build_config_target",
+                     ":$_compile_resources_target",
+                     ":$_java_target",
+                   ]
+          }
+          _final_deps += [ ":$_size_info_target" ]
+        } else {
+          not_needed(invoker, [ "name" ])
         }
-        _final_deps += [ ":$_jar_info_target" ]
       }
 
       _keystore_path = android_keystore_path
@@ -2706,9 +2713,6 @@
         dex_path = _final_dex_path
         load_library_from_apk = _load_library_from_apk
 
-        # This is used to generate *.apk.pak.info files.
-        apk_name = invoker.name
-
         keystore_name = _keystore_name
         keystore_path = _keystore_path
         keystore_password = _keystore_password
@@ -3988,14 +3992,6 @@
           ":${_unsplit_dex_target}",
         ]
       }
-
-      _jar_info_target = "${target_name}__jar_size_info"
-      create_final_jar_info(_jar_info_target) {
-        is_bundle = true
-        output = "$root_build_dir/size-info/$_bundle_name.aab.jar.info"
-        build_config = _build_config
-        deps = _module_targets + [ ":$_build_config_target" ]
-      }
     }
 
     _all_create_module_targets = []
@@ -4121,6 +4117,17 @@
       }
     }
 
+    # Create size info files for targets that care about size
+    # (have proguard enabled).
+    if (_proguard_enabled) {
+      _size_info_target = "${target_name}__size_info"
+      create_size_info_files(_size_info_target) {
+        name = "$_bundle_name.aab"
+        deps = _module_targets + [ ":$_build_config_target" ]
+        module_build_configs = _all_module_build_configs
+      }
+    }
+
     # Generate a wrapper script for the bundle.
     _android_aapt2_path = android_sdk_tools_bundle_aapt2
 
@@ -4177,8 +4184,8 @@
         ":${target_name}__bundle",
         ":${target_name}__wrapper_script",
       ]
-      if (defined(_jar_info_target)) {
-        public_deps += [ ":$_jar_info_target" ]
+      if (defined(_size_info_target)) {
+        public_deps += [ ":$_size_info_target" ]
       }
     }
   }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 56fd3bb..37c431f 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -744,6 +744,7 @@
 
   data = [
     "//chrome/test/data/android/",
+    "//chrome/test/data/autofill/",
     "//chrome/test/data/banners/",
     "//chrome/test/data/browsing_data/",
     "//chrome/test/data/encoding_tests/auto_detect/Big5_with_no_encoding_specified.html",
@@ -1935,7 +1936,11 @@
       base_module_target = ":$_base_module_target_name"
       version_code = monochrome_version_code
       version_name = chrome_version_name
-      forward_variables_from(invoker, [ "is_64_bit_browser" ])
+      forward_variables_from(invoker,
+                             [
+                               "is_64_bit_browser",
+                               "include_32_bit_webview",
+                             ])
     }
   }
 
diff --git a/chrome/android/java/res/drawable-sw600dp/bg_white_dialog.xml b/chrome/android/java/res/drawable-sw600dp/bg_white_dialog.xml
deleted file mode 100644
index 6640b3a..0000000
--- a/chrome/android/java/res/drawable-sw600dp/bg_white_dialog.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/popup_bg_tinted" />
diff --git a/chrome/android/java/res/drawable/ic_arrow_back_24dp.xml b/chrome/android/java/res/drawable/ic_arrow_back_24dp.xml
index ac26f0e..8f9174b 100644
--- a/chrome/android/java/res/drawable/ic_arrow_back_24dp.xml
+++ b/chrome/android/java/res/drawable/ic_arrow_back_24dp.xml
@@ -10,6 +10,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
+        android:autoMirrored="true"
         android:tint="?attr/colorControlNormal">
   <path
       android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"
diff --git a/chrome/android/java/res/layout/keyboard_accessory_modern.xml b/chrome/android/java/res/layout/keyboard_accessory_modern.xml
index 236ce961..c691f06 100644
--- a/chrome/android/java/res/layout/keyboard_accessory_modern.xml
+++ b/chrome/android/java/res/layout/keyboard_accessory_modern.xml
@@ -49,6 +49,16 @@
             android:contentDescription="@string/keyboard_accessory_sheet_hide"
             android:background="?attr/selectableItemBackground"/>
 
+        <TextView
+            android:id="@+id/sheet_title"
+            android:minHeight="48dp"
+            android:gravity="center_vertical|start"
+            android:textAppearance="@style/TextAppearance.BlackTitle1"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:background="?android:attr/selectableItemBackground"
+            android:visibility="gone"/>
+
         <android.support.v7.widget.RecyclerView
             android:id="@+id/bar_items_view"
             android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_legacy_title.xml b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_legacy_title.xml
new file mode 100644
index 0000000..8ad2dcb
--- /dev/null
+++ b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_legacy_title.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:gravity="center_vertical|start"
+    android:fillViewport="true"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:padding="0dp"
+    android:orientation="vertical">
+
+    <View style="@style/HorizontalDivider"
+        android:layout_marginTop="0dp"
+        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding" />
+
+    <org.chromium.ui.widget.TextViewWithLeading
+        android:id="@+id/tab_title"
+        android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
+        android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
+        android:paddingTop="@dimen/keyboard_accessory_suggestion_offset"
+        android:paddingBottom="@dimen/keyboard_accessory_suggestion_offset"
+        android:gravity="center_vertical|start"
+        android:textAppearance="@style/TextAppearance.BlackHint1"
+        android:minHeight="@dimen/keyboard_accessory_height"
+        app:leading="@dimen/text_size_large_leading"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"/>
+
+    <View style="@style/HorizontalDivider"
+        android:id="@+id/title_divider"
+        android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding"
+        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
+        android:layout_marginStart="@dimen/keyboard_accessory_suggestion_padding"
+        android:layout_marginEnd="@dimen/keyboard_accessory_suggestion_padding" />
+
+</LinearLayout>
diff --git a/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml
index 6b0dfe6d..3354928 100644
--- a/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml
+++ b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml
@@ -11,6 +11,8 @@
     android:layout_width="match_parent"
     android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
     android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
+    android:layout_marginTop="@dimen/keyboard_accessory_sheet_top_margin"
+    android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
     android:orientation="vertical">
 
 
@@ -53,10 +55,4 @@
         android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
         style="@style/InputChip" />
 
-    <View style="@style/HorizontalDivider"
-        android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding"
-        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
-        android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
-        android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding" />
-
 </org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessoryInfoView>
diff --git a/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_title.xml b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_title.xml
index 8ad2dcb..ec49c05 100644
--- a/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_title.xml
+++ b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_title.xml
@@ -10,15 +10,11 @@
     android:fillViewport="true"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
-    android:padding="0dp"
     android:orientation="vertical">
 
-    <View style="@style/HorizontalDivider"
-        android:layout_marginTop="0dp"
-        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding" />
-
     <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/tab_title"
+        android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding"
         android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
         android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
         android:paddingTop="@dimen/keyboard_accessory_suggestion_offset"
@@ -30,11 +26,4 @@
         android:layout_height="wrap_content"
         android:layout_width="match_parent"/>
 
-    <View style="@style/HorizontalDivider"
-        android:id="@+id/title_divider"
-        android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding"
-        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
-        android:layout_marginStart="@dimen/keyboard_accessory_suggestion_padding"
-        android:layout_marginEnd="@dimen/keyboard_accessory_suggestion_padding" />
-
 </LinearLayout>
diff --git a/chrome/android/java/res/values-sw600dp/drawables.xml b/chrome/android/java/res/values-sw600dp/drawables.xml
new file mode 100644
index 0000000..98e341d3
--- /dev/null
+++ b/chrome/android/java/res/values-sw600dp/drawables.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<resources>
+    <drawable name="bg_white_dialog">@drawable/popup_bg_tinted</drawable>
+</resources>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 1fd973d5..3c05032 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -138,6 +138,7 @@
     <dimen name="keyboard_accessory_shadow">5dp</dimen>
     <dimen name="keyboard_accessory_sheet_height">330dp</dimen>
     <dimen name="keyboard_accessory_sheet_padding">8dp</dimen>
+    <dimen name="keyboard_accessory_sheet_top_margin">16dp</dimen>
     <dimen name="keyboard_accessory_suggestion_padding">16dp</dimen>
     <dimen name="keyboard_accessory_suggestion_top_bottom_margin">8dp</dimen>
     <dimen name="keyboard_accessory_suggestion_offset">12dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java
index 3bd9df9..354392e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java
@@ -22,6 +22,7 @@
 
     /**
      * Creates a keyboard accessory sheet tab coordinator.
+     * @param title A {@link String} permanently displayed in the bar above the keyboard.
      * @param icon The icon that represents this sheet in the keyboard accessory tab switcher.
      * @param contentDescription A description for this sheet used in the tab switcher.
      * @param openingAnnouncement The announced string when opening this sheet.
@@ -29,11 +30,11 @@
      * @param tabType The type of this tab as used in histograms.
      * @param scrollListener An optional listener that will be bound to an inflated recycler view.
      */
-    public AccessorySheetTabCoordinator(Drawable icon, String contentDescription,
+    public AccessorySheetTabCoordinator(String title, Drawable icon, String contentDescription,
             String openingAnnouncement, @LayoutRes int layout, @AccessoryTabType int tabType,
             @Nullable RecyclerView.OnScrollListener scrollListener) {
         mTab = new KeyboardAccessoryData.Tab(
-                icon, contentDescription, openingAnnouncement, layout, tabType, this);
+                title, icon, contentDescription, openingAnnouncement, layout, tabType, this);
         mScrollListener = scrollListener;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java
index 370578e..a480da1a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
+import android.support.annotation.LayoutRes;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -60,7 +61,11 @@
      */
     static class TitleViewHolder extends ElementViewHolder<String, LinearLayout> {
         TitleViewHolder(ViewGroup parent) {
-            super(parent, R.layout.keyboard_accessory_sheet_tab_title);
+            this(parent, R.layout.keyboard_accessory_sheet_tab_legacy_title);
+        }
+
+        TitleViewHolder(ViewGroup parent, @LayoutRes int layout) {
+            super(parent, layout);
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/CreditCardAccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/CreditCardAccessorySheetCoordinator.java
index c1cfc52..8baf29b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/CreditCardAccessorySheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/CreditCardAccessorySheetCoordinator.java
@@ -23,8 +23,9 @@
      */
     public CreditCardAccessorySheetCoordinator(
             Context context, @Nullable RecyclerView.OnScrollListener scrollListener) {
-        super( // TODO(crbug.com/926365): Add an appropriate icon, and restructure this class to use
-               // an Icon Provider with a static instance of the resource.
+        super( // TODO(crbug.com/926365): Add an appropriate title, icon, and restructure this class
+               // to use an Icon Provider with a static instance of the resource.
+                context.getString(R.string.autofill_payment_methods),
                 AppCompatResources.getDrawable(context, R.drawable.ic_info_outline_grey),
                 // TODO(crbug.com/926365): Add strings and resources properly.
                 "Open credit card sheet", "Credit card sheet is open",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
index 77e41e5..3987bd3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
@@ -7,6 +7,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHEET_TITLE;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
@@ -122,7 +123,7 @@
         PropertyModel model =
                 new PropertyModel
                         .Builder(BAR_ITEMS, VISIBLE, BOTTOM_OFFSET_PX, TAB_LAYOUT_ITEM,
-                                KEYBOARD_TOGGLE_VISIBLE, SHOW_KEYBOARD_CALLBACK)
+                                KEYBOARD_TOGGLE_VISIBLE, SHEET_TITLE, SHOW_KEYBOARD_CALLBACK)
                         .with(BAR_ITEMS, new ListModel<>())
                         .with(VISIBLE, false)
                         .with(KEYBOARD_TOGGLE_VISIBLE, false)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
index 35ec610f..d69dc98f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
@@ -59,6 +59,7 @@
      * accessory. Typically, a tab is responsible to change the accessory sheet below the accessory.
      */
     public final static class Tab {
+        private final String mTitle;
         private final Drawable mIcon;
         private final @Nullable String mOpeningAnnouncement;
         private final String mContentDescription;
@@ -82,14 +83,15 @@
             void onTabShown();
         }
 
-        public Tab(Drawable icon, String contentDescription, @LayoutRes int tabLayout,
+        public Tab(String title, Drawable icon, String contentDescription, @LayoutRes int tabLayout,
                 @AccessoryTabType int recordingType, @Nullable Listener listener) {
-            this(icon, contentDescription, null, tabLayout, recordingType, listener);
+            this(title, icon, contentDescription, null, tabLayout, recordingType, listener);
         }
 
-        public Tab(Drawable icon, String contentDescription, @Nullable String openingAnnouncement,
-                @LayoutRes int tabLayout, @AccessoryTabType int recordingType,
-                @Nullable Listener listener) {
+        public Tab(String title, Drawable icon, String contentDescription,
+                @Nullable String openingAnnouncement, @LayoutRes int tabLayout,
+                @AccessoryTabType int recordingType, @Nullable Listener listener) {
+            mTitle = title;
             mIcon = icon;
             mContentDescription = contentDescription;
             mOpeningAnnouncement = openingAnnouncement;
@@ -99,6 +101,14 @@
         }
 
         /**
+         * Returns the title describing the source of the tab's content.
+         * @return A {@link String}
+         */
+        public String getTitle() {
+            return mTitle;
+        }
+
+        /**
          * Provides the icon that will be displayed in the {@link KeyboardAccessoryCoordinator}.
          * @return The small icon that identifies this tab uniquely.
          */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
index 8485d57..8318d58 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
@@ -8,6 +8,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHEET_TITLE;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
@@ -218,8 +219,13 @@
             }
             return;
         }
+        if (propertyKey == KEYBOARD_TOGGLE_VISIBLE) {
+            KeyboardAccessoryData.Tab activeTab = mTabSwitcher.getActiveTab();
+            if (activeTab != null) mModel.set(SHEET_TITLE, activeTab.getTitle());
+            return;
+        }
         if (propertyKey == BOTTOM_OFFSET_PX || propertyKey == SHOW_KEYBOARD_CALLBACK
-                || propertyKey == KEYBOARD_TOGGLE_VISIBLE || propertyKey == TAB_LAYOUT_ITEM) {
+                || propertyKey == TAB_LAYOUT_ITEM || propertyKey == SHEET_TITLE) {
             return;
         }
         assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
index b87f89c..bcfd2f1de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
@@ -85,6 +85,7 @@
             }
             if (propertyKey == KeyboardAccessoryProperties.BOTTOM_OFFSET_PX
                     || propertyKey == KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE
+                    || propertyKey == KeyboardAccessoryProperties.SHEET_TITLE
                     || propertyKey == KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK) {
                 return;
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
index 7d5b8d4..fd2b26c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
@@ -12,6 +12,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.TextView;
 
 import org.chromium.chrome.R;
 
@@ -21,6 +22,7 @@
  */
 class KeyboardAccessoryModernView extends KeyboardAccessoryView {
     private ImageView mKeyboardToggle;
+    private TextView mSheetTitle;
 
     /**
      * This decoration ensures that the last item is right-aligned.
@@ -99,6 +101,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mSheetTitle = findViewById(R.id.sheet_title);
         mKeyboardToggle = findViewById(R.id.show_keyboard);
         mKeyboardToggle.setImageDrawable(
                 AppCompatResources.getDrawable(getContext(), R.drawable.ic_arrow_back_24dp));
@@ -111,9 +114,14 @@
 
     void setKeyboardToggleVisibility(boolean hasActiveTab) {
         mKeyboardToggle.setVisibility(hasActiveTab ? VISIBLE : GONE);
+        mSheetTitle.setVisibility(hasActiveTab ? VISIBLE : GONE);
         mBarItemsView.setVisibility(hasActiveTab ? GONE : VISIBLE);
     }
 
+    void setSheetTitle(String title) {
+        mSheetTitle.setText(title);
+    }
+
     void setShowKeyboardCallback(Runnable showKeyboardCallback) {
         mKeyboardToggle.setOnClickListener(
                 showKeyboardCallback == null ? null : view -> showKeyboardCallback.run());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java
index f8e1c05d..e830e0a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHEET_TITLE;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM;
 
@@ -90,6 +91,8 @@
             modernView.setKeyboardToggleVisibility(model.get(KEYBOARD_TOGGLE_VISIBLE));
         } else if (propertyKey == SHOW_KEYBOARD_CALLBACK) {
             modernView.setShowKeyboardCallback(model.get(SHOW_KEYBOARD_CALLBACK));
+        } else if (propertyKey == SHEET_TITLE) {
+            modernView.setSheetTitle(model.get(SHEET_TITLE));
         } else if (propertyKey == TAB_LAYOUT_ITEM) {
             // No binding required.
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java
index 2b4ede2..bef7a38 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java
@@ -31,6 +31,8 @@
             new ReadableObjectPropertyKey<>("bar_items");
     static final WritableBooleanPropertyKey VISIBLE = new WritableBooleanPropertyKey("visible");
     static final WritableIntPropertyKey BOTTOM_OFFSET_PX = new WritableIntPropertyKey("offset");
+    static final WritableObjectPropertyKey<String> SHEET_TITLE =
+            new WritableObjectPropertyKey<>("sheet_title");
     static final WritableBooleanPropertyKey KEYBOARD_TOGGLE_VISIBLE =
             new WritableBooleanPropertyKey("toggle_visible");
     static final WritableObjectPropertyKey<TabLayoutBarItem> TAB_LAYOUT_ITEM =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
index 8b7125a..868e07d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
@@ -90,6 +90,7 @@
     }
 
     void setVisible(boolean visible) {
+        if (!visible || getVisibility() != VISIBLE) mBarItemsView.scrollToPosition(0);
         if (visible) {
             show();
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
index 119a7ce..d41fcab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
@@ -7,6 +7,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHEET_TITLE;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
@@ -109,6 +110,8 @@
             // No binding required.
         } else if (propertyKey == KEYBOARD_TOGGLE_VISIBLE) {
             // No binding required.
+        } else if (propertyKey == SHEET_TITLE) {
+            // No binding required.
         } else if (propertyKey == TAB_LAYOUT_ITEM) {
             // No binding required.
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
index 0b9b7f2..d21b66e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
@@ -63,7 +63,8 @@
      */
     public PasswordAccessorySheetCoordinator(
             Context context, @Nullable RecyclerView.OnScrollListener scrollListener) {
-        super(IconProvider.getInstance().getIcon(context),
+        super(context.getString(R.string.prefs_saved_passwords_title),
+                IconProvider.getInstance().getIcon(context),
                 context.getString(R.string.password_accessory_sheet_toggle),
                 context.getString(R.string.password_accessory_sheet_opened),
                 R.layout.password_accessory_sheet, AccessoryTabType.PASSWORDS, scrollListener);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java
index 9e66cef..81dff31c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
@@ -41,7 +42,9 @@
         if (accessorySheetData == null) return new AccessorySheetDataPiece[0];
 
         List<AccessorySheetDataPiece> items = new ArrayList<>();
-        items.add(new AccessorySheetDataPiece(accessorySheetData.getTitle(), Type.TITLE));
+        if (shouldShowTitle(accessorySheetData.getUserInfoList())) {
+            items.add(new AccessorySheetDataPiece(accessorySheetData.getTitle(), Type.TITLE));
+        }
         for (UserInfo userInfo : accessorySheetData.getUserInfoList()) {
             items.add(new AccessorySheetDataPiece(userInfo, Type.PASSWORD_INFO));
         }
@@ -51,4 +54,9 @@
 
         return items.toArray(new AccessorySheetDataPiece[0]);
     }
+
+    private boolean shouldShowTitle(List<UserInfo> userInfoList) {
+        return !ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)
+                || userInfoList.isEmpty();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewBinder.java
index 55ad0a5..1f7e72f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewBinder.java
@@ -23,8 +23,10 @@
         switch (viewType) {
             case AccessorySheetDataPiece.Type.PASSWORD_INFO:
                 return new PasswordInfoViewHolder(parent);
-            case AccessorySheetDataPiece.Type.TITLE: // Intentional fallthrough.
-            case AccessorySheetDataPiece.Type.FOOTER_COMMAND: // Intentional fallthrough.
+            case AccessorySheetDataPiece.Type.TITLE:
+                return new AccessorySheetTabViewBinder.TitleViewHolder(
+                        parent, R.layout.keyboard_accessory_sheet_tab_title);
+            case AccessorySheetDataPiece.Type.FOOTER_COMMAND:
                 return AccessorySheetTabViewBinder.create(parent, viewType);
         }
         assert false : "Unhandled type of data piece: " + viewType;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcher.java
index 13743d4..7c56e3b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcher.java
@@ -4,9 +4,11 @@
 
 package org.chromium.chrome.browser.init;
 
+import android.content.Intent;
 import android.os.Bundle;
 
 import org.chromium.base.ObserverList;
+import org.chromium.chrome.browser.lifecycle.ActivityResultWithNativeObserver;
 import org.chromium.chrome.browser.lifecycle.Destroyable;
 import org.chromium.chrome.browser.lifecycle.InflationObserver;
 import org.chromium.chrome.browser.lifecycle.LifecycleObserver;
@@ -32,6 +34,8 @@
             new ObserverList<>();
     private final ObserverList<WindowFocusChangedObserver> mWindowFocusChangesObservers =
             new ObserverList<>();
+    private final ObserverList<ActivityResultWithNativeObserver>
+            mActivityResultWithNativeObservers = new ObserverList<>();
 
     /**
      * Registers an observer.
@@ -60,6 +64,10 @@
         if (observer instanceof WindowFocusChangedObserver) {
             mWindowFocusChangesObservers.addObserver((WindowFocusChangedObserver) observer);
         }
+        if (observer instanceof ActivityResultWithNativeObserver) {
+            mActivityResultWithNativeObservers.addObserver(
+                    (ActivityResultWithNativeObserver) observer);
+        }
     }
 
     /**
@@ -87,6 +95,10 @@
         if (observer instanceof WindowFocusChangedObserver) {
             mWindowFocusChangesObservers.removeObserver((WindowFocusChangedObserver) observer);
         }
+        if (observer instanceof ActivityResultWithNativeObserver) {
+            mActivityResultWithNativeObservers.removeObserver(
+                    (ActivityResultWithNativeObserver) observer);
+        }
     }
 
     void dispatchPreInflationStartup() {
@@ -148,4 +160,10 @@
             observer.onWindowFocusChanged(hasFocus);
         }
     }
+
+    void dispatchOnActivityResultWithNative(int requestCode, int resultCode, Intent data) {
+        for (ActivityResultWithNativeObserver observer : mActivityResultWithNativeObservers) {
+            observer.onActivityResultWithNative(requestCode, resultCode, data);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 9dce86c..5894e43 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -609,6 +609,7 @@
                 && mWindowAndroid.onActivityResult(requestCode, resultCode, intent)) {
             return true;
         }
+        mLifecycleDispatcher.dispatchOnActivityResultWithNative(requestCode, resultCode, intent);
         super.onActivityResult(requestCode, resultCode, intent);
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java
new file mode 100644
index 0000000..78deb16
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.lifecycle;
+
+import android.content.Intent;
+
+import org.chromium.chrome.browser.init.ActivityLifecycleDispatcher;
+import org.chromium.chrome.browser.init.AsyncInitializationActivity;
+
+/**
+ * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive
+ * activity result methods.
+ */
+public interface ActivityResultWithNativeObserver extends LifecycleObserver {
+    /**
+     * Called when {@link AsyncInitializationActivity#onActivityResult(int, int, Intent)} is called.
+     */
+    void onActivityResultWithNative(int requestCode, int resultCode, Intent data);
+}
\ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index f772612f..306f8d5 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -878,6 +878,7 @@
   "java/src/org/chromium/chrome/browser/jsdialog/JavascriptModalDialog.java",
   "java/src/org/chromium/chrome/browser/jsdialog/JavascriptTabModalDialog.java",
   "java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java",
+  "java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java",
   "java/src/org/chromium/chrome/browser/lifecycle/Destroyable.java",
   "java/src/org/chromium/chrome/browser/lifecycle/InflationObserver.java",
   "java/src/org/chromium/chrome/browser/lifecycle/LifecycleObserver.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryIntegrationTest.java
index ad15136..c98a460 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryIntegrationTest.java
@@ -4,96 +4,49 @@
 
 package org.chromium.chrome.browser.autofill;
 
-import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
-
 import android.support.test.filters.MediumTest;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
 
-import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.RetryOnFailure;
-import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Integration tests for autofill keyboard accessory.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @RetryOnFailure
-@EnableFeatures({ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY})
+@EnableFeatures({ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY,
+        ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY})
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class AutofillKeyboardAccessoryIntegrationTest {
     @Rule
-    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
-            new ChromeActivityTestRule<>(ChromeActivity.class);
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
-    private final AtomicReference<WebContents> mWebContentsRef = new AtomicReference<>();
-    private final AtomicReference<ViewGroup> mContainerRef = new AtomicReference<>();
+    private ManualFillingTestHelper mHelper = new ManualFillingTestHelper(mActivityTestRule);
 
-    private void loadTestPage(boolean isRtl)
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mActivityTestRule.startMainActivityWithURL(UrlUtils.encodeHtmlDataUri("<html"
-                + (isRtl ? " dir=\"rtl\"" : "") + "><head>"
-                + "<meta name=\"viewport\""
-                + "content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>"
-                + "<body><form method=\"POST\">"
-                + "<input type=\"text\" id=\"fn\" autocomplete=\"given-name\" autofocus/><br>"
-                + "<input type=\"text\" id=\"ln\" autocomplete=\"family-name\" /><br>"
-                + "<textarea id=\"sa\" autocomplete=\"street-address\"></textarea><br>"
-                + "<input type=\"text\" id=\"a1\" autocomplete=\"address-line1\" /><br>"
-                + "<input type=\"text\" id=\"a2\" autocomplete=\"address-line2\" /><br>"
-                + "<input type=\"text\" id=\"ct\" autocomplete=\"address-level2\" /><br>"
-                + "<input type=\"text\" id=\"zc\" autocomplete=\"postal-code\" /><br>"
-                + "<input type=\"text\" id=\"em\" autocomplete=\"email\" /><br>"
-                + "<input type=\"text\" id=\"ph\" autocomplete=\"tel\" /><br>"
-                + "<input type=\"text\" id=\"fx\" autocomplete=\"fax\" /><br>"
-                + "<select id=\"co\" autocomplete=\"country\"><br>"
-                + "<option value=\"BR\">Brazil</option>"
-                + "<option value=\"US\">United States</option>"
-                + "</select>"
-                + "<input type=\"submit\" />"
-                + "</form></body></html>"));
-        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://www.example.com",
-                "Johnathan Smithonian-Jackson", "Acme Inc", "1 Main\nApt A", "CA", "San Francisco",
-                "", "94102", "", "US", "(415) 888-9999", "john.sj@acme-mail.inc", "en"));
-        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://www.example.com",
-                "Jane Erika Donovanova", "Acme Inc", "1 Main\nApt A", "CA", "San Francisco", "",
-                "94102", "", "US", "(415) 999-0000", "donovanova.j@acme-mail.inc", "en"));
-        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://www.example.com",
-                "Marcus McSpartangregor", "Acme Inc", "1 Main\nApt A", "CA", "San Francisco", "",
-                "94102", "", "US", "(415) 999-0000", "marc@acme-mail.inc", "en"));
-        setRtlForTesting(isRtl);
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            Tab tab = mActivityTestRule.getActivity().getActivityTab();
-            mWebContentsRef.set(tab.getWebContents());
-            mContainerRef.set(tab.getContentView());
-        });
-        DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), "fn");
+    private void loadTestPage() throws InterruptedException, ExecutionException, TimeoutException {
+        mHelper.loadTestPage("/chrome/test/data/autofill/autofill_test_form.html", false, false);
+        ManualFillingTestHelper.createAutofillTestProfiles();
+        DOMUtils.waitForNonZeroNodeBounds(mHelper.getWebContents(), "NAME_FIRST");
     }
 
     /**
@@ -101,11 +54,13 @@
      */
     @Test
     @MediumTest
-    @EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY})
     public void testAutofocusedFieldDoesNotShowKeyboardAccessory()
             throws ExecutionException, InterruptedException, TimeoutException {
-        loadTestPage(false);
-        Assert.assertTrue("Keyboard accessory should be hidden.", isAccessoryGone());
+        loadTestPage();
+        CriteriaHelper.pollUiThread(() -> {
+            View accessory = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
+            return accessory == null || !accessory.isShown();
+        });
     }
 
     /**
@@ -113,18 +68,11 @@
      */
     @Test
     @MediumTest
-    @EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY})
-    @DisabledTest(message = "crbug.com/854224")
     public void testTapInputFieldShowsKeyboardAccessory()
             throws ExecutionException, InterruptedException, TimeoutException {
-        loadTestPage(false);
-        DOMUtils.clickNode(mWebContentsRef.get(), "fn");
-
-        CriteriaHelper.pollUiThread(Criteria.equals(true,
-                ()
-                        -> mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
-                                mActivityTestRule.getActivity(), mContainerRef.get())));
-        Assert.assertTrue("Keyboard accessory should be showing.", isAccessoryVisible());
+        loadTestPage();
+        mHelper.clickNodeAndShowKeyboard("NAME_FIRST");
+        mHelper.waitForKeyboardAccessoryToBeShown();
     }
 
     /**
@@ -132,24 +80,23 @@
      */
     @Test
     @MediumTest
-    @EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY})
-    @DisabledTest(message = "crbug.com/836027")
     public void testSwitchFieldsRescrollsKeyboardAccessory()
             throws ExecutionException, InterruptedException, TimeoutException {
-        loadTestPage(false);
-        DOMUtils.clickNode(mWebContentsRef.get(), "em");
+        loadTestPage();
+        mHelper.clickNodeAndShowKeyboard("EMAIL_ADDRESS");
+        mHelper.waitForKeyboardAccessoryToBeShown();
 
-        CriteriaHelper.pollUiThread(Criteria.equals(true,
-                ()
-                        -> mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
-                                mActivityTestRule.getActivity(), mContainerRef.get())));
-
+        // Scroll to the second position and check it actually happened.
         ThreadUtils.runOnUiThreadBlocking(() -> getSuggestionsComponent().scrollToPosition(2));
+        CriteriaHelper.pollUiThread(() -> {
+            return getSuggestionsComponent().computeHorizontalScrollOffset() > 0;
+        }, "Should keep the manual scroll position.");
 
-        assertSuggestionsScrollState(false, "Should keep the manual scroll position.");
-
-        DOMUtils.clickNode(mWebContentsRef.get(), "ln");
-        assertSuggestionsScrollState(true, "Should be scrolled back to position 0.");
+        // Clicking any other node should now scroll the items back to the initial position.
+        mHelper.clickNodeAndShowKeyboard("NAME_LAST");
+        CriteriaHelper.pollUiThread(() -> {
+            return getSuggestionsComponent().computeHorizontalScrollOffset() == 0;
+        }, "Should be scrolled back to position 0.");
     }
 
     /**
@@ -158,70 +105,26 @@
      */
     @Test
     @MediumTest
-    @EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY})
-    @DisabledTest(message = "crbug.com/847959")
     public void testSelectSuggestionHidesKeyboardAccessory()
             throws ExecutionException, InterruptedException, TimeoutException {
-        loadTestPage(false);
-        DOMUtils.clickNode(mWebContentsRef.get(), "fn");
+        loadTestPage();
+        mHelper.clickNodeAndShowKeyboard("NAME_FIRST");
+        mHelper.waitForKeyboardAccessoryToBeShown();
 
-        CriteriaHelper.pollUiThread(Criteria.equals(true,
-                ()
-                        -> mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
-                                mActivityTestRule.getActivity(), mContainerRef.get())));
-        Assert.assertTrue("Keyboard accessory should be visible.", isAccessoryVisible());
-
-        ThreadUtils.runOnUiThreadBlocking(() -> getSuggestionAt(0).performClick());
-
-        CriteriaHelper.pollUiThread(Criteria.equals(false,
-                ()
-                        -> mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
-                                mActivityTestRule.getActivity(), mContainerRef.get())));
-        Assert.assertTrue("Keyboard accessory should be hidden.", isAccessoryGone());
-    }
-
-    private void assertSuggestionsScrollState(boolean isScrollingReset, String failureReason) {
-        CriteriaHelper.pollUiThread(new Criteria(failureReason) {
-            @Override
-            public boolean isSatisfied() {
-                return isScrollingReset
-                        ? getSuggestionsComponent().computeHorizontalScrollOffset() <= 0
-                        : getSuggestionsComponent().computeHorizontalScrollOffset() > 0;
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(() -> getFirstSuggestion().performClick());
+        mHelper.waitForKeyboardAccessoryToDisappear();
     }
 
     private RecyclerView getSuggestionsComponent() {
         final ViewGroup keyboardAccessory = ThreadUtils.runOnUiThreadBlockingNoException(
                 () -> mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory));
-        if (keyboardAccessory == null) return null; // It might still be loading, so don't assert!
-
-        final View recyclerView = keyboardAccessory.findViewById(R.id.bar_items_view);
-        if (recyclerView == null) return null; // It might still be loading, so don't assert!
-
-        return (RecyclerView) recyclerView;
+        assert keyboardAccessory != null;
+        return (RecyclerView) keyboardAccessory.findViewById(R.id.bar_items_view);
     }
 
-    private View getSuggestionAt(int index) {
+    private View getFirstSuggestion() {
         ViewGroup recyclerView = getSuggestionsComponent();
-        if (recyclerView == null) return null; // It might still be loading, so don't assert!
-
-        return recyclerView.getChildAt(index);
-    }
-
-    private boolean isAccessoryVisible() throws ExecutionException {
-        return ThreadUtils.runOnUiThreadBlocking(() -> {
-            LinearLayout keyboard =
-                    mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
-            return keyboard != null && keyboard.getVisibility() == View.VISIBLE;
-        });
-    }
-
-    private boolean isAccessoryGone() throws ExecutionException {
-        return ThreadUtils.runOnUiThreadBlocking(() -> {
-            LinearLayout keyboard =
-                    mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
-            return keyboard == null || keyboard.getVisibility() == View.GONE;
-        });
+        assert recyclerView != null;
+        return recyclerView.getChildAt(0);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewTest.java
index b934fe6..954f65f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewTest.java
@@ -68,7 +68,7 @@
                             mActivityTestRule.getActivity().findViewById(
                                     R.id.keyboard_accessory_sheet_stub)));
             accessorySheet.addTab(new KeyboardAccessoryData.Tab(
-                    null, null, layout, AccessoryTabType.ALL, listener));
+                    "Passwords", null, null, layout, AccessoryTabType.ALL, listener));
             accessorySheet.setHeight(
                     mActivityTestRule.getActivity().getResources().getDimensionPixelSize(
                             R.dimen.keyboard_accessory_sheet_height));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java
index ebf7c45..f31395e4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java
@@ -116,7 +116,7 @@
     @MediumTest
     public void testAddingTabToModelRendersTabsView() throws InterruptedException {
         final String kSampleAction = "Some Action";
-        mModel.get(TABS).add(new Tab(null, null, R.layout.empty_accessory_sheet,
+        mModel.get(TABS).add(new Tab("Passwords", null, null, R.layout.empty_accessory_sheet,
                 AccessoryTabType.PASSWORDS, new Tab.Listener() {
                     @Override
                     public void onTabCreated(ViewGroup view) {
@@ -221,8 +221,8 @@
     }
 
     private Tab createTestTabWithTextView(String textViewCaption) {
-        return new Tab(null, null, R.layout.empty_accessory_sheet, AccessoryTabType.PASSWORDS,
-                new Tab.Listener() {
+        return new Tab("Passwords", null, null, R.layout.empty_accessory_sheet,
+                AccessoryTabType.PASSWORDS, new Tab.Listener() {
                     @Override
                     public void onTabCreated(ViewGroup view) {
                         TextView sampleTextView = new TextView(mActivityTestRule.getActivity());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutViewTest.java
index 78b57b4..1f6d95d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutViewTest.java
@@ -58,7 +58,7 @@
             new ChromeActivityTestRule<>(ChromeTabbedActivity.class);
 
     private KeyboardAccessoryData.Tab createTestTab(String contentDescription) {
-        return new KeyboardAccessoryData.Tab(
+        return new KeyboardAccessoryData.Tab("Passwords",
                 mActivityTestRule.getActivity().getResources().getDrawable(
                         android.R.drawable.ic_lock_lock), // Unused.
                 contentDescription,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
index 065e2ae..b99f679 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -37,7 +37,6 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -68,9 +67,7 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY,
-        ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY,
-        // TODO(crbug.com/894428): Remove and use the embedded test server instead of data urls.
-        ChromeFeatureList.AUTOFILL_ALLOW_NON_HTTP_ACTIVATION})
+        ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY})
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class ManualFillingIntegrationTest {
     @Rule
@@ -263,7 +260,6 @@
 
     @Test
     @SmallTest
-    @DisabledTest(message = "https://crbug.com/919988")
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
     public void testInvokingTabSwitcherHidesAccessory()
             throws InterruptedException, TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
index 8498aa5..09f19680 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
@@ -39,6 +39,8 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.ChromeWindow;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Provider;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -54,6 +56,7 @@
 import org.chromium.ui.DropdownItem;
 import org.chromium.ui.DropdownPopupWindowInterface;
 
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -77,7 +80,7 @@
         return (FakeKeyboard) mActivityTestRule.getKeyboardDelegate();
     }
 
-    ManualFillingTestHelper(ChromeTabbedActivityTestRule activityTestRule) {
+    public ManualFillingTestHelper(ChromeTabbedActivityTestRule activityTestRule) {
         mActivityTestRule = activityTestRule;
     }
 
@@ -86,6 +89,11 @@
     }
 
     public void loadTestPage(String url, boolean isRtl) throws InterruptedException {
+        loadTestPage(url, isRtl, false);
+    }
+
+    public void loadTestPage(String url, boolean isRtl, boolean waitForNode)
+            throws InterruptedException {
         mEmbeddedTestServer = EmbeddedTestServer.createAndStartServer(
                 InstrumentationRegistry.getInstrumentation().getContext());
         ChromeWindow.setKeyboardVisibilityDelegateFactory(FakeKeyboard::new);
@@ -108,7 +116,7 @@
             activity.getManualFillingController().registerPasswordProvider(
                     mSheetSuggestionsProvider);
         });
-        DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), PASSWORD_NODE_ID);
+        if (waitForNode) DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), PASSWORD_NODE_ID);
         cacheCredentials(new String[0], new String[0]); // This caches the empty state.
     }
 
@@ -121,6 +129,10 @@
     // Helpers interacting with the web page.
     // --------------------------------------
 
+    public WebContents getWebContents() {
+        return mWebContentsRef.get();
+    }
+
     public void focusPasswordField() throws TimeoutException, InterruptedException {
         DOMUtils.focusNode(mActivityTestRule.getWebContents(), PASSWORD_NODE_ID);
         ThreadUtils.runOnUiThreadBlocking(
@@ -143,7 +155,13 @@
                         .getMediatorForTesting()
                         .showWhenKeyboardIsVisible();
             });
-        };
+        }
+        getKeyboard().showKeyboard(mActivityTestRule.getActivity().getCurrentFocus());
+    }
+
+    public void clickNodeAndShowKeyboard(String node)
+            throws TimeoutException, InterruptedException {
+        DOMUtils.clickNode(mWebContentsRef.get(), node);
         getKeyboard().showKeyboard(mActivityTestRule.getActivity().getCurrentFocus());
     }
 
@@ -262,6 +280,19 @@
         });
     }
 
+    public static void createAutofillTestProfiles()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://www.example.com",
+                "Johnathan Smithonian-Jackson", "Acme Inc", "1 Main\nApt A", "CA", "San Francisco",
+                "", "94102", "", "US", "(415) 888-9999", "john.sj@acme-mail.inc", "en"));
+        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://www.example.com",
+                "Jane Erika Donovanova", "Acme Inc", "1 Main\nApt A", "CA", "San Francisco", "",
+                "94102", "", "US", "(415) 999-0000", "donovanova.j@acme-mail.inc", "en"));
+        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://www.example.com",
+                "Marcus McSpartangregor", "Acme Inc", "1 Main\nApt A", "CA", "San Francisco", "",
+                "94102", "", "US", "(415) 999-0000", "marc@acme-mail.inc", "en"));
+    }
+
     // --------------------------------------------------
     // Generic helpers to match, check or wait for views.
     // TODO(fhorschig): Consider Moving to ViewUtils.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingUiCaptureTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingUiCaptureTest.java
index 796a67c..6b6f70b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingUiCaptureTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingUiCaptureTest.java
@@ -37,6 +37,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.RecyclerViewTestUtils;
 
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -124,13 +125,13 @@
     @EnableFeatures(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)
     @Feature({"KeyboardAccessoryModern", "LTR", "UiCatalogue"})
     public void testCaptureKeyboardAccessoryV2WithPasswords()
-            throws InterruptedException, TimeoutException {
+            throws InterruptedException, TimeoutException, ExecutionException {
         mHelper.loadTestPage(false);
+        ManualFillingTestHelper.createAutofillTestProfiles();
         mHelper.cacheTestCredentials();
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
         mHelper.addGenerationButton();
-        mHelper.addAutofillChips();
 
         waitForActionsInAccessory();
         waitForUnrelatedChromeUi();
@@ -156,13 +157,13 @@
     @EnableFeatures(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)
     @Feature({"KeyboardAccessoryModern", "RTL", "UiCatalogue"})
     public void testCaptureKeyboardAccessoryV2WithPasswordsRTL()
-            throws InterruptedException, TimeoutException {
+            throws InterruptedException, TimeoutException, ExecutionException {
         mHelper.loadTestPage(true);
+        ManualFillingTestHelper.createAutofillTestProfiles();
         mHelper.cacheTestCredentials();
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
         mHelper.addGenerationButton();
-        mHelper.addAutofillChips();
 
         waitForActionsInAccessory();
         waitForUnrelatedChromeUi();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewTest.java
index 8ede5d97..717055d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewTest.java
@@ -63,8 +63,9 @@
                             mActivityTestRule.getActivity().findViewById(
                                     R.id.keyboard_accessory_sheet_stub)));
             accessorySheet.addTab(
-                    new KeyboardAccessoryData.Tab(null, null, R.layout.password_accessory_sheet,
-                            AccessoryTabType.ALL, new KeyboardAccessoryData.Tab.Listener() {
+                    new KeyboardAccessoryData.Tab("Passwords", null, null,
+                            R.layout.password_accessory_sheet, AccessoryTabType.ALL,
+                            new KeyboardAccessoryData.Tab.Listener() {
                                 @Override
                                 public void onTabCreated(ViewGroup view) {
                                     mView.set((RecyclerView) view);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
index b251616..80b1d3f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
@@ -67,9 +67,8 @@
                     new DeferredViewStubInflationProvider<>(
                             mActivityTestRule.getActivity().findViewById(
                                     R.id.keyboard_accessory_sheet_stub)));
-            accessorySheet.addTab(
-                    new KeyboardAccessoryData.Tab(null, null, layout, AccessoryTabType.ALL,
-                            listener));
+            accessorySheet.addTab(new KeyboardAccessoryData.Tab(
+                    "Passwords", null, null, layout, AccessoryTabType.ALL, listener));
             accessorySheet.setHeight(
                     mActivityTestRule.getActivity().getResources().getDimensionPixelSize(
                             R.dimen.keyboard_accessory_sheet_height));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetControllerTest.java
index 12114a6..08c73a10 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetControllerTest.java
@@ -56,9 +56,10 @@
     @Mock
     private RecyclerView mMockRecyclerView;
 
-    private final Tab[] mTabs =
-            new Tab[] {new Tab(null, null, 0, 0, null), new Tab(null, null, 0, 0, null),
-                    new Tab(null, null, 0, 0, null), new Tab(null, null, 0, 0, null)};
+    private final Tab[] mTabs = new Tab[] {new Tab("Passwords", null, null, 0, 0, null),
+            new Tab("Passwords", null, null, 0, 0, null),
+            new Tab("Passwords", null, null, 0, 0, null),
+            new Tab("Passwords", null, null, 0, 0, null)};
 
     private AccessorySheetCoordinator mCoordinator;
     private AccessorySheetMediator mMediator;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java
index 3d12e95..43952fd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java
@@ -17,7 +17,9 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction.AUTOFILL_SUGGESTION;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BAR_ITEMS;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHEET_TITLE;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryTabLayoutProperties.ACTIVE_TAB;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -66,7 +68,7 @@
     private AutofillDelegate mMockAutofillDelegate;
 
     private final KeyboardAccessoryData.Tab mTestTab =
-            new KeyboardAccessoryData.Tab(null, null, 0, 0, null);
+            new KeyboardAccessoryData.Tab("Passwords", null, null, 0, 0, null);
 
     private KeyboardAccessoryCoordinator mCoordinator;
     private PropertyModel mModel;
@@ -117,8 +119,8 @@
     @Test
     public void testModelNotifiesAboutActionsChangedByProvider() {
         // Set a default tab to prevent visibility changes to trigger now:
-        mCoordinator.setTabs(new KeyboardAccessoryData.Tab[] {
-                new KeyboardAccessoryData.Tab(null, null, 0, AccessoryTabType.PASSWORDS, null)});
+        mCoordinator.setTabs(new KeyboardAccessoryData.Tab[] {new KeyboardAccessoryData.Tab(
+                "Passwords", null, null, 0, AccessoryTabType.PASSWORDS, null)});
         mModel.get(BAR_ITEMS).addObserver(mMockActionListObserver);
 
         PropertyProvider<Action[]> testProvider =
@@ -154,8 +156,8 @@
     public void testModelNotifiesAboutActionsChangedByProviderForRedesign() {
         setAutofillFeature(true);
         // Set a default tab to prevent visibility changes to trigger now:
-        mCoordinator.setTabs(new KeyboardAccessoryData.Tab[] {
-                new KeyboardAccessoryData.Tab(null, null, 0, AccessoryTabType.PASSWORDS, null)});
+        mCoordinator.setTabs(new KeyboardAccessoryData.Tab[] {new KeyboardAccessoryData.Tab(
+                "Passwords", null, null, 0, AccessoryTabType.PASSWORDS, null)});
         mModel.get(BAR_ITEMS).addObserver(mMockActionListObserver);
 
         PropertyProvider<Action[]> testProvider =
@@ -380,6 +382,20 @@
     }
 
     @Test
+    public void testShowsTitleForActiveTabs() {
+        // Add an inactive tab and ensure the sheet title isn't already set.
+        mCoordinator.requestShowing();
+        mCoordinator.addTab(mTestTab);
+        mModel.set(SHEET_TITLE, "");
+        assertThat(mCoordinator.hasActiveTab(), is(false));
+
+        // Changing the active tab should also change the title.
+        mCoordinator.getTabLayoutForTesting().getModelForTesting().set(ACTIVE_TAB, 0);
+        assertThat(mModel.get(SHEET_TITLE), equalTo("Passwords"));
+        assertThat(mCoordinator.hasActiveTab(), is(true));
+    }
+
+    @Test
     public void testRecordsOneImpressionForEveryInitialContentOnVisibilityChange() {
         assertThat(RecordHistogram.getHistogramTotalCountForTesting(
                            KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_BAR_SHOWN),
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutControllerTest.java
index 66ae971..8937107 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryTabLayoutControllerTest.java
@@ -50,7 +50,7 @@
     private KeyboardAccessoryTabLayoutView mMockView;
 
     private final KeyboardAccessoryData.Tab mTestTab =
-            new KeyboardAccessoryData.Tab(null, null, 0, 0, null);
+            new KeyboardAccessoryData.Tab("Passwords", null, null, 0, 0, null);
 
     private KeyboardAccessoryTabLayoutCoordinator mCoordinator;
     private PropertyModel mModel;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
index aea3b25..d06b1db 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -161,7 +161,7 @@
         assertThat(accessorySheetModel.get(AccessorySheetProperties.TABS).size(), is(0));
 
         mController.getMediatorForTesting().addTab(
-                new KeyboardAccessoryData.Tab(null, null, 0, 0, null));
+                new KeyboardAccessoryData.Tab("Passwords", null, null, 0, 0, null));
 
         verify(mMockTabListObserver)
                 .onItemRangeInserted(getTabLayout().getModelForTesting().get(TABS), 0, 1);
@@ -458,7 +458,7 @@
 
         // Show the accessory bar to make sure it would be dismissed.
         getTabLayout().getTabSwitchingDelegate().addTab(
-                new KeyboardAccessoryData.Tab(null, null, 0, 0, null));
+                new KeyboardAccessoryData.Tab("Passwords", null, null, 0, 0, null));
         mediator.getKeyboardAccessory().requestShowing();
         assertThat(mediator.getKeyboardAccessory().isShown(), is(true));
 
@@ -478,7 +478,7 @@
 
         // Show the accessory bar for the default dimensions (300x80@2.f).
         getTabLayout().getTabSwitchingDelegate().addTab(
-                new KeyboardAccessoryData.Tab(null, null, 0, 0, null));
+                new KeyboardAccessoryData.Tab("Passwords", null, null, 0, 0, null));
         mediator.showWhenKeyboardIsVisible();
         assertThat(mediator.getKeyboardAccessory().isShown(), is(true));
 
@@ -518,7 +518,7 @@
                 mController.getMediatorForTesting().getKeyboardAccessory();
         addTab(mController.getMediatorForTesting(), 1234, null);
         mController.getMediatorForTesting().addTab(
-                new KeyboardAccessoryData.Tab(null, null, 0, 0, null));
+                new KeyboardAccessoryData.Tab("Passwords", null, null, 0, 0, null));
         accessory.requestShowing();
         assertThat(mController.isFillingViewShown(null), is(false));
 
@@ -640,12 +640,10 @@
         PasswordAccessorySheetCoordinator passwordSheet = mediator.getPasswordAccessorySheet();
         assert passwordSheet != null;
         assert passwordSheet.getSheetDataPiecesForTesting() != null;
-        assert passwordSheet.getSheetDataPiecesForTesting().size() > 1;
-        assert getType(passwordSheet.getSheetDataPiecesForTesting().get(1)) == PASSWORD_INFO;
-        // The 1st element is a title, the 2nd the password info.
+        assert passwordSheet.getSheetDataPiecesForTesting().size() > 0;
+        assert getType(passwordSheet.getSheetDataPiecesForTesting().get(0)) == PASSWORD_INFO;
         UserInfo info =
-                (UserInfo) passwordSheet.getSheetDataPiecesForTesting().get(1).getDataPiece();
-        // The 1st field is the name, the 2nd the password.
+                (UserInfo) passwordSheet.getSheetDataPiecesForTesting().get(0).getDataPiece();
         assert info.getFields().size() > 1;
         return info.getFields().get(1).getDisplayText();
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java
index 74041ea..1b4f2bd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java
@@ -32,12 +32,15 @@
 import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.task.test.CustomShadowAsyncTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.PropertyProvider;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo;
 import org.chromium.ui.modelutil.ListObservable;
 
+import java.util.HashMap;
+
 /**
  * Controller tests for the password accessory sheet.
  */
@@ -109,6 +112,7 @@
 
     @Test
     public void testSplitsTabDataToList() {
+        setAutofillFeature(false);
         final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>();
         final AccessorySheetData testData = new AccessorySheetData("Passwords for this site");
         testData.getUserInfoList().add(new UserInfo(null));
@@ -130,6 +134,34 @@
     }
 
     @Test
+    public void testUsesTabTitleOnlyForEmptyListsForModernDesign() {
+        setAutofillFeature(true);
+        final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>();
+        final AccessorySheetData testData = new AccessorySheetData("No passwords for this");
+        mCoordinator.registerDataProvider(testProvider);
+
+        // Providing only FooterCommands and no User Info shows the title as empty state:
+        testData.getFooterCommands().add(new FooterCommand("Manage passwords", result -> {}));
+        testProvider.notifyObservers(testData);
+
+        assertThat(mSheetDataPieces.size(), is(2));
+        assertThat(getType(mSheetDataPieces.get(0)), is(TITLE));
+        assertThat(getType(mSheetDataPieces.get(1)), is(FOOTER_COMMAND));
+        assertThat(mSheetDataPieces.get(0).getDataPiece(), is(equalTo("No passwords for this")));
+
+        // As soon UserInfo is available, discard the title.
+        testData.getUserInfoList().add(new UserInfo(null));
+        testData.getUserInfoList().get(0).addField(new UserInfo.Field("Name", "Name", false, null));
+        testData.getUserInfoList().get(0).addField(
+                new UserInfo.Field("Password", "Password for Name", true, field -> {}));
+        testProvider.notifyObservers(testData);
+
+        assertThat(mSheetDataPieces.size(), is(2));
+        assertThat(getType(mSheetDataPieces.get(0)), is(PASSWORD_INFO));
+        assertThat(getType(mSheetDataPieces.get(1)), is(FOOTER_COMMAND));
+    }
+
+    @Test
     public void testRecordsActionImpressionsWhenShown() {
         assertThat(getActionImpressions(AccessoryAction.MANAGE_PASSWORDS), is(0));
 
@@ -192,4 +224,10 @@
                         type),
                 sample);
     }
+
+    private void setAutofillFeature(boolean enabled) {
+        HashMap<String, Boolean> features = new HashMap<>();
+        features.put(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY, enabled);
+        ChromeFeatureList.setTestFeatures(features);
+    }
 }
diff --git a/chrome/android/modules/ar/ar_module_tmpl.gni b/chrome/android/modules/ar/ar_module_tmpl.gni
index 0a2e3a21..f05d4ca 100644
--- a/chrome/android/modules/ar/ar_module_tmpl.gni
+++ b/chrome/android/modules/ar/ar_module_tmpl.gni
@@ -48,7 +48,9 @@
         loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/arm64-v8a/libarcore_sdk_c.so" ]
 
         # TODO(cjgrant): Make this a dummy lib, if SplitCompat properly opens the 64-bit library.
-        secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/arm64-v8a/libarcore_sdk_c.so" ]
+        if (build_apk_secondary_abi && invoker.include_32_bit_webview) {
+          secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/arm64-v8a/libarcore_sdk_c.so" ]
+        }
       } else {
         if (build_apk_secondary_abi) {
           secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index ddaa5464..b37b27d 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-74.0.3701.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-74.0.3702.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index dc2ef89..ffc6953 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -337,7 +337,7 @@
 }
 
 void SigninManagerAndroid::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   DCHECK(thread_checker_.CalledOnValidThread());
   Java_SigninManager_onNativeSignOut(base::android::AttachCurrentThread(),
                                      java_signin_manager_);
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index 5512aee..cc3e66b 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -82,7 +82,7 @@
 
   // identity::IdentityManager::Observer implementation.
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
  private:
   friend class SigninManagerAndroidTest;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 1f52504..6308143 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -462,8 +462,10 @@
       <include name="IDR_POLICY_COMMON_CSS" file="resources\policy_common.css" type="BINDATA" compress="gzip" />
       <if expr="not is_android">
         <include name="IDR_MANAGEMENT_HTML" file="resources\management\management.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
-        <include name="IDR_MANAGEMENT_JS" file="resources\management\management.js" type="BINDATA" compress="gzip" />
-        <include name="IDR_MANAGEMENT_CSS" file="resources\management\management.css" type="BINDATA" compress="gzip" />
+        <include name="IDR_MANAGEMENT_UI_HTML" file="resources\management\management_ui.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
+        <include name="IDR_MANAGEMENT_UI_JS" file="resources\management\management_ui.js" type="BINDATA" compress="gzip" preprocess="true" />
+        <include name="IDR_MANAGEMENT_BROWSER_PROXY_HTML" file="resources\management\management_browser_proxy.html" allowexternalscript="true" type="BINDATA" compress="gzip" />
+        <include name="IDR_MANAGEMENT_BROWSER_PROXY_JS" file="resources\management\management_browser_proxy.js" type="BINDATA" compress="gzip" preprocess="true" />
         <include name="IDR_POLICY_TOOL_HTML" file="resources\policy_tool.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
         <include name="IDR_POLICY_TOOL_CSS" file="resources\policy_tool.css" type="BINDATA" compress="gzip" />
         <include name="IDR_POLICY_TOOL_JS" file="resources\policy_tool.js" type="BINDATA" compress="gzip" />
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 8d828c2..bb3f8208 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -396,9 +396,9 @@
     if (history_service) {
       // TODO(dmurph): Support all backends with filter (crbug.com/113621).
       base::RecordAction(UserMetricsAction("ClearBrowsingData_History"));
-      history_service->ExpireLocalAndRemoteHistoryBetween(
-          WebHistoryServiceFactory::GetForProfile(profile_), std::set<GURL>(),
-          delete_begin_, delete_end_, /*user_initiated*/ true,
+      history_service->DeleteLocalAndRemoteHistoryBetween(
+          WebHistoryServiceFactory::GetForProfile(profile_), delete_begin_,
+          delete_end_,
           base::AdaptCallbackForRepeating(CreatePendingTaskCompletionClosure()),
           &history_task_tracker_);
     }
diff --git a/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc b/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc
index 3a6a5bc5..985ab47 100644
--- a/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc
+++ b/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc
@@ -54,12 +54,7 @@
   }
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)) {
-    // TODO(http://crbug.com/890796): Migrate this part once sync_ui_util has
-    // been migrated to the IdentityManager.
-    sync_ui_util::MessageType sync_status = sync_ui_util::GetStatus(
-        profile, ProfileSyncServiceFactory::GetSyncServiceForProfile(profile),
-        IdentityManagerFactory::GetForProfile(profile));
-    return sync_status == sync_ui_util::SYNCED;
+    return sync_ui_util::GetStatus(profile) == sync_ui_util::SYNCED;
   }
 #endif
   return false;
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index 3ad70d2..d95f1fd 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -76,6 +76,9 @@
 
   void TearDownOnMainThread() override {
     AccessibilityManager::SetBrailleControllerForTest(nullptr);
+    // Unload the ChromeVox extension so the browser doesn't try to respond to
+    // in-flight requests during test shutdown. https://crbug.com/923090
+    AccessibilityManager::Get()->EnableSpokenFeedback(false);
     AutomationManagerAura::GetInstance()->Disable();
   }
 
@@ -247,15 +250,8 @@
   EXPECT_EQ("Not pressed", speech_monitor_.GetNextUtterance());
 }
 
-#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
-// Flaky in debug & asan: http://crbug.com/923090
-#define MAYBE_KeyboardShortcutViewer DISABLED_KeyboardShortcutViewer
-#else
-#define MAYBE_KeyboardShortcutViewer KeyboardShortcutViewer
-#endif
 // Tests the keyboard shortcut viewer, which is an out-of-process mojo app.
-IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest,
-                       MAYBE_KeyboardShortcutViewer) {
+IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, KeyboardShortcutViewer) {
   EnableChromeVox();
   keyboard_shortcut_viewer_util::ToggleKeyboardShortcutViewer();
 
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc
index 4175763..a90e276 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/guid.h"
 #include "base/optional.h"
+#include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h"
@@ -36,7 +37,12 @@
     return;
   }
   processing_image_ = true;
-  download_service_->StartDownload(GetDownloadParams());
+  GURL url = GetPluginVmImageDownloadUrl();
+  if (url.is_empty()) {
+    OnDownloadFailed();
+    return;
+  }
+  download_service_->StartDownload(GetDownloadParams(url));
 }
 
 void PluginVmImageManager::CancelDownload() {
@@ -89,6 +95,8 @@
 }
 
 void PluginVmImageManager::OnDownloadCompleted(base::FilePath file_path) {
+  // TODO(https://crbug.com/928816): Call OnDownloadFailed() in case download
+  // verification using hashes fails.
   downloaded_plugin_vm_image_archive_ = file_path;
   current_download_guid_.clear();
   if (observer_)
@@ -131,7 +139,20 @@
       weak_ptr_factory_(this) {}
 PluginVmImageManager::~PluginVmImageManager() = default;
 
-download::DownloadParams PluginVmImageManager::GetDownloadParams() {
+GURL PluginVmImageManager::GetPluginVmImageDownloadUrl() {
+  const base::Value* url_ptr =
+      profile_->GetPrefs()
+          ->GetDictionary(plugin_vm::prefs::kPluginVmImage)
+          ->FindKey("url");
+  if (!url_ptr) {
+    LOG(ERROR) << "Url to PluginVm image is not specified";
+    return GURL();
+  }
+  return GURL(url_ptr->GetString());
+}
+
+download::DownloadParams PluginVmImageManager::GetDownloadParams(
+    const GURL& url) {
   download::DownloadParams params;
 
   // DownloadParams
@@ -144,11 +165,8 @@
       net::MutableNetworkTrafficAnnotationTag(NO_TRAFFIC_ANNOTATION_YET);
 
   // RequestParams
-  std::string url;
-  profile_->GetPrefs()
-      ->GetDictionary(plugin_vm::prefs::kPluginVmImage)
-      ->GetString("url", &url);
-  params.request_params.url = GURL(url);
+
+  params.request_params.url = url;
   params.request_params.method = "GET";
 
   // SchedulingParams
@@ -176,6 +194,21 @@
   return !current_download_guid_.empty();
 }
 
+bool PluginVmImageManager::VerifyDownload(std::string downloaded_archive_hash) {
+  const base::Value* plugin_vm_image_hash_ptr =
+      profile_->GetPrefs()
+          ->GetDictionary(plugin_vm::prefs::kPluginVmImage)
+          ->FindKey("hash");
+  if (!plugin_vm_image_hash_ptr) {
+    LOG(ERROR) << "Hash of PluginVm image is not specified";
+    return false;
+  }
+  std::string plugin_vm_image_hash = plugin_vm_image_hash_ptr->GetString();
+
+  return base::EqualsCaseInsensitiveASCII(plugin_vm_image_hash,
+                                          downloaded_archive_hash);
+}
+
 bool PluginVmImageManager::UnzipDownloadedPluginVmImageArchive() {
   base::File file(downloaded_plugin_vm_image_archive_,
                   base::File::FLAG_OPEN | base::File::FLAG_READ);
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.h
index 61453c7f..36edcb6 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.h
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.h
@@ -124,11 +124,15 @@
 
   ~PluginVmImageManager() override;
 
-  download::DownloadParams GetDownloadParams();
+  GURL GetPluginVmImageDownloadUrl();
+  download::DownloadParams GetDownloadParams(const GURL& url);
 
   void OnStartDownload(const std::string& download_guid,
                        download::DownloadParams::StartResult start_result);
   bool IsDownloading();
+  // Returns true in case downloaded PluginVm image archive passes verification
+  // and false otherwise.
+  bool VerifyDownload(std::string downloaded_archive_hash);
 
   bool UnzipDownloadedPluginVmImageArchive();
   bool IsUnzippingCancelled();
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc
index 1aad9331..b09cce6f 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc
@@ -275,6 +275,8 @@
 }
 
 TEST_F(PluginVmImageManagerTest, CancelUnzippingTest) {
+  EXPECT_CALL(*download_observer_, OnUnzippingFailed());
+
   // Faking downloaded file for testing.
   manager_->SetDownloadedPluginVmImageArchiveForTesting(
       fake_downloaded_plugin_vm_image_archive_);
@@ -291,4 +293,13 @@
   EXPECT_FALSE(base::DirectoryExists(plugin_vm_image_unzipped));
 }
 
+TEST_F(PluginVmImageManagerTest, EmptyPluginVmImageUrlTest) {
+  SetPluginVmImagePref("", kHash);
+
+  EXPECT_CALL(*download_observer_, OnDownloadFailed());
+
+  manager_->StartDownload();
+  test_browser_thread_bundle_.RunUntilIdle();
+}
+
 }  // namespace plugin_vm
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
index 1580ce0..3d7ca79 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
@@ -149,13 +149,7 @@
 
 // Returns true if Sync is currently running (i.e. enabled and not in error).
 bool IsSyncRunning(Profile* profile) {
-  syncer::SyncService* sync_service =
-      ProfileSyncServiceFactory::GetSyncServiceForProfile(profile);
-  identity::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(profile);
-  sync_ui_util::MessageType sync_status =
-      sync_ui_util::GetStatus(profile, sync_service, identity_manager);
-  return sync_status == sync_ui_util::SYNCED;
+  return sync_ui_util::GetStatus(profile) == sync_ui_util::SYNCED;
 }
 }  // namespace
 
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
index 1c91cf19..951fe3bd 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
@@ -422,9 +422,7 @@
       ProfileSyncServiceFactory::GetForProfile(profile);
   sync_service->GetUserSettings()->SetFirstSetupComplete();
 
-  sync_ui_util::MessageType sync_status =
-      sync_ui_util::GetStatus(profile, sync_service, identity_manager);
-  ASSERT_EQ(sync_ui_util::SYNCED, sync_status);
+  ASSERT_EQ(sync_ui_util::SYNCED, sync_ui_util::GetStatus(profile));
   // Clear browsing data.
   auto function = base::MakeRefCounted<BrowsingDataRemoveFunction>();
   EXPECT_EQ(NULL, RunFunctionAndReturnSingleResult(
@@ -459,10 +457,7 @@
               CREDENTIALS_REJECTED_BY_SERVER));
 
   // Sync is not running.
-  sync_ui_util::MessageType sync_status = sync_ui_util::GetStatus(
-      profile, ProfileSyncServiceFactory::GetForProfile(profile),
-      identity_manager);
-  ASSERT_NE(sync_ui_util::SYNCED, sync_status);
+  ASSERT_NE(sync_ui_util::SYNCED, sync_ui_util::GetStatus(profile));
   // Clear browsing data.
   auto function = base::MakeRefCounted<BrowsingDataRemoveFunction>();
   EXPECT_EQ(NULL, RunFunctionAndReturnSingleResult(
diff --git a/chrome/browser/extensions/api/history/history_api.cc b/chrome/browser/extensions/api/history/history_api.cc
index 8bbeeff6..133a5caa 100644
--- a/chrome/browser/extensions/api/history/history_api.cc
+++ b/chrome/browser/extensions/api/history/history_api.cc
@@ -24,6 +24,7 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/history/web_history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/history.h"
@@ -359,7 +360,9 @@
 
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       GetProfile(), ServiceAccessType::EXPLICIT_ACCESS);
-  hs->DeleteURL(url);
+  history::WebHistoryService* web_history =
+      WebHistoryServiceFactory::GetForProfile(GetProfile());
+  hs->DeleteLocalAndRemoteUrl(web_history, url);
 
   // Also clean out from the activity log. If the activity log testing flag is
   // set then don't clean so testers can see what potentially malicious
@@ -386,12 +389,12 @@
   base::Time start_time = GetTime(params->range.start_time);
   base::Time end_time = GetTime(params->range.end_time);
 
-  std::set<GURL> restrict_urls;
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       GetProfile(), ServiceAccessType::EXPLICIT_ACCESS);
-  hs->ExpireHistoryBetween(
-      restrict_urls, start_time, end_time,
-      /*user_initiated*/ true,
+  history::WebHistoryService* web_history =
+      WebHistoryServiceFactory::GetForProfile(GetProfile());
+  hs->DeleteLocalAndRemoteHistoryBetween(
+      web_history, start_time, end_time,
       base::BindOnce(&HistoryDeleteRangeFunction::DeleteComplete,
                      base::Unretained(this)),
       &task_tracker_);
@@ -401,7 +404,7 @@
           ::switches::kEnableExtensionActivityLogTesting)) {
     ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
     DCHECK(activity_log);
-    activity_log->RemoveURLs(restrict_urls);
+    activity_log->RemoveURLs(/*restrict_urls=*/std::vector<GURL>());
   }
 
   AddRef();               // Balanced in DeleteComplete().
@@ -421,12 +424,12 @@
   std::set<GURL> restrict_urls;
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       GetProfile(), ServiceAccessType::EXPLICIT_ACCESS);
-  // Uninitialized base::Time() means unbounded.
-  hs->ExpireHistoryBetween(
-      restrict_urls,
+  history::WebHistoryService* web_history =
+      WebHistoryServiceFactory::GetForProfile(GetProfile());
+  hs->DeleteLocalAndRemoteHistoryBetween(
+      web_history,
       /*begin_time*/ base::Time(),
-      /*end_time*/ base::Time(),
-      /*user_initiated*/ true,
+      /*end_time*/ base::Time::Max(),
       base::BindOnce(&HistoryDeleteAllFunction::DeleteComplete,
                      base::Unretained(this)),
       &task_tracker_);
@@ -436,7 +439,7 @@
           ::switches::kEnableExtensionActivityLogTesting)) {
     ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
     DCHECK(activity_log);
-    activity_log->RemoveURLs(restrict_urls);
+    activity_log->RemoveURLs(/*restrict_urls=*/std::vector<GURL>());
   }
 
   AddRef();               // Balanced in DeleteComplete().
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index d9b850eb..0c5f59e 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -1315,7 +1315,7 @@
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id3,
                                                                      false);
-};
+}
 
 namespace {
 
diff --git a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
index 3b41f1f..f1dc07f 100644
--- a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
@@ -135,8 +135,16 @@
   EXPECT_EQ(result, test_config_.cursor);
 }
 
+// Flaky on CrOS, Windows and Linux. https://crbug.com/930471
+#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_GetDisplayMediaVideoAndAudioWithFakeUI \
+  DISABLED_GetDisplayMediaVideoAndAudioWithFakeUI
+#else
+#define MAYBE_GetDisplayMediaVideoAndAudioWithFakeUI \
+  GetDisplayMediaVideoAndAudioWithFakeUI
+#endif  // defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
 IN_PROC_BROWSER_TEST_P(WebRtcGetDisplayMediaBrowserTestWithFakeUI,
-                       GetDisplayMediaVideoAndAudio) {
+                       MAYBE_GetDisplayMediaVideoAndAudioWithFakeUI) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
diff --git a/chrome/browser/password_manager/password_store_signin_notifier_impl.cc b/chrome/browser/password_manager/password_store_signin_notifier_impl.cc
index 1d8eca33..5a4027c 100644
--- a/chrome/browser/password_manager/password_store_signin_notifier_impl.cc
+++ b/chrome/browser/password_manager/password_store_signin_notifier_impl.cc
@@ -29,7 +29,7 @@
 }
 
 void PasswordStoreSigninNotifierImpl::OnPrimaryAccountCleared(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   NotifySignedOut(account_info.email, /* primary_account= */ true);
 }
 
diff --git a/chrome/browser/password_manager/password_store_signin_notifier_impl.h b/chrome/browser/password_manager/password_store_signin_notifier_impl.h
index 7b32a1d..c3ea13f 100644
--- a/chrome/browser/password_manager/password_store_signin_notifier_impl.h
+++ b/chrome/browser/password_manager/password_store_signin_notifier_impl.h
@@ -28,7 +28,7 @@
   void UnsubscribeFromSigninEvents() override;
 
   // IdentityManager::Observer implementations.
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override;
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
   void OnAccountRemovedWithInfo(const AccountInfo& info) override;
 
  private:
diff --git a/chrome/browser/password_manager/password_store_x.cc b/chrome/browser/password_manager/password_store_x.cc
index 5ee353a..ed8e313 100644
--- a/chrome/browser/password_manager/password_store_x.cc
+++ b/chrome/browser/password_manager/password_store_x.cc
@@ -522,7 +522,16 @@
   for (auto& form : forms) {
     PasswordStoreChangeList changes = login_db->AddLogin(*form);
     if (changes.empty() || changes.back().type() != PasswordStoreChange::ADD) {
-      return FAILED_WRITE_TO_ENCRYPTED;
+      // AddLogin() would fail if the form has empty |origin|, empty
+      // |signon_realm|, is a duplicate blacklisting or there was an IO error.
+      // All of these cases are not supported and can be dropped.
+      if (form->signon_realm.empty() || form->origin.is_empty() ||
+          form->blacklisted_by_user) {
+        LOG(WARNING) << "Dropped a credential during migration away from the "
+                        "native backend";
+      } else {
+        return FAILED_WRITE_TO_ENCRYPTED;
+      }
     }
   }
 
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 243dd38e..11c767e 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -835,6 +835,69 @@
       "PasswordManager.LinuxBackendMigration.AttemptResult", 0);
 }
 
+TEST_P(PasswordStoreXTest, MigrationToEncryption_DropIllegalEntries) {
+  if (GetParam() != WORKING_BACKEND)
+    return;
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      password_manager::features::kMigrateLinuxToLoginDB);
+  IntegerPrefMember migration_step_pref_;
+  migration_step_pref_.Init(password_manager::prefs::kMigrationToLoginDBStep,
+                            &fake_pref_service_);
+
+  EXPECT_EQ(PasswordStoreX::NOT_ATTEMPTED, migration_step_pref_.GetValue());
+
+  // Add existing credentials into the backend.
+  std::vector<std::unique_ptr<PasswordForm>> old_credentials;
+  InitExpectedForms(true, 4, &old_credentials);
+  // Create illegal entries.
+  old_credentials[1]->origin = GURL();
+  old_credentials[3]->signon_realm.clear();
+
+  std::unique_ptr<PasswordStoreX::NativeBackend> backend =
+      GetBackend(GetParam());
+  std::vector<PasswordForm> native_backend_last_state;
+  static_cast<MockBackend*>(backend.get())
+      ->SaveFormsOnDestruct(&native_backend_last_state);
+  for (int i = 0; i < 3; i++)
+    backend->AddLogin(*old_credentials[i]);
+
+  auto login_db = std::make_unique<password_manager::LoginDatabase>(
+      test_login_db_file_path());
+  scoped_refptr<PasswordStoreX> store(
+      new PasswordStoreX(std::move(login_db), test_login_db_file_path(),
+                         test_encrypted_login_db_file_path(),
+                         std::move(backend), &fake_pref_service_));
+  store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+
+  MockPasswordStoreConsumer consumer;
+  // The store has the native backend data, minus the illegal entries.
+  // The call to GetAutofillableLogins() both triggers the opportunistic
+  // migration and returns the data for the test.
+  EXPECT_CALL(consumer,
+              OnGetPasswordStoreResultsConstRef(UnorderedElementsAre(
+                  Pointee(*old_credentials[0]), Pointee(*old_credentials[2]))));
+  store->GetAutofillableLogins(&consumer);
+
+  WaitForPasswordStore();
+  store->ShutdownOnUIThread();
+  store.reset();
+  WaitForPasswordStore();
+
+  // Verify that the login database contains all the values, now encrypted.
+  std::vector<std::unique_ptr<PasswordForm>> stored_forms =
+      ReadLoginDB(test_login_db_file_path(), true);
+  EXPECT_EQ(2u, stored_forms.size());
+  EXPECT_THAT(stored_forms, UnorderedElementsAre(Pointee(*old_credentials[0]),
+                                                 Pointee(*old_credentials[2])));
+  EXPECT_EQ(PasswordStoreX::LOGIN_DB_REPLACED, migration_step_pref_.GetValue());
+
+  histogram_tester_.ExpectBucketCount(
+      "PasswordManager.LinuxBackendMigration.AttemptResult",
+      LinuxBackendMigrationStatus::kLoginDBReplaced, 1);
+}
+
 INSTANTIATE_TEST_CASE_P(NoBackend,
                         PasswordStoreXTest,
                         testing::Values(NO_BACKEND));
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
index dd801c26..2343ecd 100644
--- a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
@@ -42,10 +42,10 @@
 #endif
 
 using content::BrowserThread;
+using testing::_;
 using testing::AnyNumber;
 using testing::InvokeWithoutArgs;
 using testing::Mock;
-using testing::_;
 
 namespace em = enterprise_management;
 
@@ -164,9 +164,6 @@
 
     test_url_loader_factory_ =
         std::make_unique<network::TestURLLoaderFactory>();
-    test_shared_loader_factory_ =
-        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            test_url_loader_factory_.get());
 
     BrowserPolicyConnector* connector =
         g_browser_process->browser_policy_connector();
@@ -174,7 +171,7 @@
 
 #if defined(OS_CHROMEOS)
     policy_manager()->core()->client()->SetURLLoaderFactoryForTesting(
-        test_shared_loader_factory_);
+        test_url_loader_factory_->GetSafeWeakWrapper());
 #else
     // Mock a signed-in user. This is used by the UserCloudPolicyStore to pass
     // the username to the UserCloudPolicyValidator.
@@ -183,18 +180,15 @@
     identity::SetPrimaryAccount(identity_manager, "user@example.com");
 
     ASSERT_TRUE(policy_manager());
-    policy_manager()->Connect(g_browser_process->local_state(),
-                              UserCloudPolicyManager::CreateCloudPolicyClient(
-                                  connector->device_management_service(),
-                                  test_shared_loader_factory_));
+    policy_manager()->Connect(
+        g_browser_process->local_state(),
+        UserCloudPolicyManager::CreateCloudPolicyClient(
+            connector->device_management_service(),
+            test_url_loader_factory_->GetSafeWeakWrapper()));
 #endif
   }
 
   void TearDownOnMainThread() override {
-    // Need to detach since |test_url_loader_factory_| will go away after this
-    // destructor, but other code might be referencing
-    // |test_shared_loader_factory_|.
-    test_shared_loader_factory_->Detach();
     // Verify that all the expected requests were handled.
     EXPECT_EQ(0, test_url_loader_factory_->NumPending());
   }
@@ -247,24 +241,21 @@
   }
 
   std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory_;
-  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
-      test_shared_loader_factory_;
 };
 
 IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, Register) {
-  // Accept one register request. The initial request should not include the
-  // reregister flag.
-  em::DeviceRegisterRequest::Type expected_type =
-#if defined(OS_CHROMEOS)
-      em::DeviceRegisterRequest::USER;
-#else
-      em::DeviceRegisterRequest::BROWSER;
-#endif
-  const bool expect_reregister = false;
   test_url_loader_factory_->SetInterceptor(
       base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
-        RespondToRegisterWithSuccess(expected_type, expect_reregister, request,
-                                     test_url_loader_factory_.get());
+        // Accept one register request. The initial request should not include
+        // the reregister flag.
+        em::DeviceRegisterRequest::Type expected_type =
+#if defined(OS_CHROMEOS)
+            em::DeviceRegisterRequest::USER;
+#else
+            em::DeviceRegisterRequest::BROWSER;
+#endif
+        RespondToRegisterWithSuccess(expected_type, /*expect_reregister=*/false,
+                                     request, test_url_loader_factory_.get());
       }));
 
   EXPECT_FALSE(policy_manager()->core()->client()->is_registered());
@@ -305,19 +296,18 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, RegisterWithRetry) {
-  em::DeviceRegisterRequest::Type expected_type =
-#if defined(OS_CHROMEOS)
-      em::DeviceRegisterRequest::USER;
-#else
-      em::DeviceRegisterRequest::BROWSER;
-#endif
-  const bool expect_reregister = true;
-
-  // Accept one register request after failing once. The retry request should
-  // set the reregister flag.
-  bool gave_error = false;
   test_url_loader_factory_->SetInterceptor(
       base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
+        em::DeviceRegisterRequest::Type expected_type =
+#if defined(OS_CHROMEOS)
+            em::DeviceRegisterRequest::USER;
+#else
+            em::DeviceRegisterRequest::BROWSER;
+#endif
+
+        // Accept one register request after failing once. The retry request
+        // should set the reregister flag.
+        static bool gave_error = false;
         if (!gave_error) {
           gave_error = true;
           network::URLLoaderCompletionStatus status(net::ERR_NETWORK_CHANGED);
@@ -327,8 +317,8 @@
           return;
         }
 
-        RespondToRegisterWithSuccess(expected_type, expect_reregister, request,
-                                     test_url_loader_factory_.get());
+        RespondToRegisterWithSuccess(expected_type, /*expect_reregister=*/true,
+                                     request, test_url_loader_factory_.get());
       }));
 
   EXPECT_FALSE(policy_manager()->core()->client()->is_registered());
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index 73e177ec..c60dedb 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -76,7 +76,7 @@
 }
 
 void UserPolicySigninServiceBase::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   ShutdownUserCloudPolicyManager();
 }
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.h b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
index e411a725..bfd825b 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
@@ -86,7 +86,7 @@
 
   // identity::IdentityManager::Observer implementation:
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   // content::NotificationObserver implementation:
   void Observe(int type,
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index ba759ef7..82b771f8 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -220,6 +220,6 @@
 }
 
 void GAIAInfoUpdateService::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   OnUsernameChanged(std::string());
 }
diff --git a/chrome/browser/profiles/gaia_info_update_service.h b/chrome/browser/profiles/gaia_info_update_service.h
index 79f0b08..c7f6e6b 100644
--- a/chrome/browser/profiles/gaia_info_update_service.h
+++ b/chrome/browser/profiles/gaia_info_update_service.h
@@ -58,7 +58,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   Profile* profile_;
   std::unique_ptr<ProfileDownloader> profile_image_downloader_;
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index b1971c4..5a4a96c 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -9,6 +9,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -53,7 +54,6 @@
 #include "chrome/browser/sessions/session_service_factory.h"
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
 #include "chrome/browser/signin/account_reconcilor_factory.h"
-#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -82,7 +82,6 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/search_engines/default_search_manager.h"
 #include "components/signin/core/browser/account_fetcher_service.h"
-#include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/sync/base/stop_source.h"
 #include "components/sync/driver/sync_service.h"
@@ -1344,7 +1343,7 @@
       base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}),
       profile->GetPath());
 
-  GaiaCookieManagerServiceFactory::GetForProfile(profile)->InitCookieListener();
+  IdentityManagerFactory::GetForProfile(profile)->StartObservingCookieChanges();
   AccountFetcherServiceFactory::GetForProfile(profile)->OnProfileLoaded();
   AccountReconcilorFactory::GetForProfile(profile);
 
diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
index 4a387bb..9dd4252 100644
--- a/chrome/browser/profiles/renderer_updater.cc
+++ b/chrome/browser/profiles/renderer_updater.cc
@@ -202,7 +202,8 @@
   UpdateAllRenderers();
 }
 
-void RendererUpdater::OnPrimaryAccountCleared(const AccountInfo& account_info) {
+void RendererUpdater::OnPrimaryAccountCleared(
+    const CoreAccountInfo& account_info) {
   UpdateAllRenderers();
 }
 
diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
index 0d7c3c8..bb856ac 100644
--- a/chrome/browser/profiles/renderer_updater.h
+++ b/chrome/browser/profiles/renderer_updater.h
@@ -61,7 +61,7 @@
 
   // IdentityManager::Observer:
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override;
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
 
   // VariationsHttpHeaderProvider::Observer:
   void VariationIdsHeaderUpdated(
diff --git a/chrome/browser/resources/app_management/actions.js b/chrome/browser/resources/app_management/actions.js
index 79a41f6..efa4e9a 100644
--- a/chrome/browser/resources/app_management/actions.js
+++ b/chrome/browser/resources/app_management/actions.js
@@ -48,10 +48,6 @@
           'Tried to load app detail page without providing an app id.');
     }
 
-    if (PageType == PageType.SEARCH) {
-      console.warn('This should not be invoked');
-    }
-
     return {
       name: 'change-page',
       pageType: pageType,
diff --git a/chrome/browser/resources/app_management/app.html b/chrome/browser/resources/app_management/app.html
index c8c1ac4..8fe97d0f 100644
--- a/chrome/browser/resources/app_management/app.html
+++ b/chrome/browser/resources/app_management/app.html
@@ -34,7 +34,7 @@
         on-search-changed="onSearchChanged_">
     </cr-toolbar>
     <app-management-dom-switch id="view-selector"
-        route="[[selectedRouteId_(currentPage_)]]">
+        route="[[selectedRouteId_(currentPage_, searchTerm_)]]">
       <template>
         <app-management-main-view route-id="main-view">
         </app-management-main-view>
diff --git a/chrome/browser/resources/app_management/app.js b/chrome/browser/resources/app_management/app.js
index 9791928..39a44ca 100644
--- a/chrome/browser/resources/app_management/app.js
+++ b/chrome/browser/resources/app_management/app.js
@@ -47,36 +47,40 @@
 
   /**
    * @param {Page} currentPage
+   * @param {String} searchTerm
    * @private
    */
-  selectedRouteId_: function(currentPage) {
-    switch (currentPage.pageType) {
-      case (PageType.MAIN):
-        return 'main-view';
+  selectedRouteId_: function(currentPage, searchTerm) {
+    if (searchTerm) {
+      return 'search-view';
+    }
+    // This is to prevent console error caused by currentPage being undefined.
+    if (currentPage) {
+      switch (currentPage.pageType) {
+        case (PageType.MAIN):
+          return 'main-view';
 
-      case (PageType.NOTIFICATIONS):
-        return 'notifications-view';
+        case (PageType.NOTIFICATIONS):
+          return 'notifications-view';
 
-      case (PageType.SEARCH):
-        return 'search-view';
+        case (PageType.DETAIL):
+          const state = this.getState();
+          const selectedAppType =
+              state.apps[assert(state.currentPage.selectedAppId)].type;
+          switch (selectedAppType) {
+            case (AppType.kWeb):
+              return 'pwa-permission-view';
+            case (AppType.kExtension):
+              return 'chrome-app-permission-view';
+            case (AppType.kArc):
+              return 'arc-permission-view';
+            default:
+              assertNotReached();
+          }
 
-      case (PageType.DETAIL):
-        const state = this.getState();
-        const selectedAppType =
-            state.apps[assert(state.currentPage.selectedAppId)].type;
-        switch (selectedAppType) {
-          case (AppType.kWeb):
-            return 'pwa-permission-view';
-          case (AppType.kExtension):
-            return 'chrome-app-permission-view';
-          case (AppType.kArc):
-            return 'arc-permission-view';
-          default:
-            assertNotReached();
-        }
-
-      default:
-        assertNotReached();
+        default:
+          assertNotReached();
+      }
     }
   },
 });
diff --git a/chrome/browser/resources/app_management/constants.js b/chrome/browser/resources/app_management/constants.js
index c742c12..89f99d8 100644
--- a/chrome/browser/resources/app_management/constants.js
+++ b/chrome/browser/resources/app_management/constants.js
@@ -23,7 +23,6 @@
   MAIN: 0,
   DETAIL: 1,
   NOTIFICATIONS: 2,
-  SEARCH: 3,
 };
 
 /**
diff --git a/chrome/browser/resources/app_management/reducers.js b/chrome/browser/resources/app_management/reducers.js
index ce1512e..a81e36c 100644
--- a/chrome/browser/resources/app_management/reducers.js
+++ b/chrome/browser/resources/app_management/reducers.js
@@ -94,25 +94,7 @@
     }
   };
 
-  /**
-   * TODO(ceciliani) Delete search page type and navigate router by calculating
-   * if there is search.term.
-   * @param {Object} action
-   * @return {Page}
-   */
-  CurrentPageState.changeForSearch = function(action) {
-    if (action.term) {
-      return {
-        pageType: PageType.SEARCH,
-        selectedAppId: null,
-      };
-    } else {
-      return {
-        pageType: PageType.MAIN,
-        selectedAppId: null,
-      };
-    }
-  };
+
   /**
    * @param {Page} currentPage
    * @param {Object} action
@@ -138,10 +120,6 @@
    */
   CurrentPageState.updateCurrentPage = function(apps, currentPage, action) {
     switch (action.name) {
-      case 'start-search':
-        return CurrentPageState.changeForSearch(action);
-      case 'clear-search':
-        return CurrentPageState.changeForSearch(action);
       case 'change-page':
         return CurrentPageState.changePage(apps, action);
       case 'remove-app':
diff --git a/chrome/browser/resources/management/BUILD.gn b/chrome/browser/resources/management/BUILD.gn
index 7b9f371..eb78fea 100644
--- a/chrome/browser/resources/management/BUILD.gn
+++ b/chrome/browser/resources/management/BUILD.gn
@@ -6,15 +6,20 @@
 
 js_type_check("closure_compile") {
   deps = [
-    ":management",
+    ":management_browser_proxy",
+    ":management_ui",
   ]
 }
 
-js_library("management") {
+js_library("management_ui") {
   deps = [
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:load_time_data",
-    "//ui/webui/resources/js:promise_resolver",
-    "//ui/webui/resources/js:util",
+  ]
+}
+
+js_library("management_browser_proxy") {
+  deps = [
+    "//ui/webui/resources/js:cr",
   ]
 }
diff --git a/chrome/browser/resources/management/management.css b/chrome/browser/resources/management/management.css
deleted file mode 100644
index 425e65bf..0000000
--- a/chrome/browser/resources/management/management.css
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright 2018 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-body {
-  margin-inline-start: 23px;
-}
-
-body > .page {
-  margin-inline-end: 0;
-  padding-inline-end: 24px;
-}
-
-body header {
-  left: 23px;
-  max-width: none;
-}
-
-html[dir='rtl'] body header {
-  right: 23px;
-}
-
-body section {
-  max-width: none;
-}
-
-#main-section {
-  padding-inline-start: 0;
-}
-
-#extensions-table {
-  border: 0;
-}
-
-#extensions-table li {
-  padding: 2px;
-}
-
-#extensions-table ul {
-  list-style: none;
-  padding: 0;
-}
-
-#extensions-table th {
-  border: 0;
-  color: grey;
-  padding: 7px;
-  text-align: start;
-}
-
-#extensions-table td {
-  border: 0;
-  padding: 0 5px 0;
-}
-
-#reporting-info-list li {
-  padding: 2px;
-}
-
-.section-title {
-  font-weight: bold;
-}
diff --git a/chrome/browser/resources/management/management.html b/chrome/browser/resources/management/management.html
index b6bedf3..1b3ab84 100644
--- a/chrome/browser/resources/management/management.html
+++ b/chrome/browser/resources/management/management.html
@@ -1,70 +1,34 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<html dir="$i18n{textdirection}" lang="$i18n{language}" class="loading">
 <head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, user-scalable=no">
-<title>$i18n{title}</title>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, user-scalable=no">
+  <title>$i18n{managementTitle}</title>
 
-<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
-<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<link rel="stylesheet" href="management.css">
+  <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+  <style>
+    html {
+      --toolbar-height: 56px;
+      background: var(--md-background-color);
+      height: 100%;
+      overflow: hidden;
+    }
 
-<script src="chrome://resources/js/assert.js"></script>
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/load_time_data.js"></script>
-<script src="chrome://resources/js/promise_resolver.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="strings.js"></script>
-<script src="management.js"></script>
+    html.loading {
+      border-top: var(--toolbar-height) solid var(--md-toolbar-color);
+    }
+
+    body {
+      height: 100%;
+      margin: 0;
+    }
+  </style>
+
+  <link rel="import" href="management_ui.html">
+  <script src="strings.js"></script>
 </head>
-
 <body>
-  <div class="page">
-    <header>
-      <h1>$i18n{title}</h1>
-    </header>
-    <section id="main-section">
-      <!--  This is where page content gets dynamically added. -->
-      <section id="management-status" hidden>
-        <p></p>
-      </section>
-
-      <section id="policies" hidden>
-        <h2 class="section-title">$i18n{deviceReporting}</h2>
-        <div id="device-configuration">
-          $i18n{deviceConfiguration}
-        </div>
-        <ul id="reporting-info-list"></ul>
-      </section>
-
-      <section id="browser-policies" hidden>
-        <h2 class="section-title">$i18n{browserReporting}</h2>
-        <ul id="browser-reporting-info-list"></ul>
-      </section>
-
-      <section id="extensions" hidden>
-        <h2 class="section-title">$i18n{extensionReporting}</h2>
-        <div id="extensions-installed">
-          $i18n{extensionsInstalled}
-        </div>
-        <table id="extensions-table">
-          <tr>
-            <th>$i18n{extensionName}</th>
-            <th>$i18n{extensionPermissions}</th>
-          </tr>
-        </table>
-      </section>
-
-      <section id="trust-roots" hidden>
-        <h2 class="section-title">$i18n{localTrustRoots}</h2>
-        <div id="trust-roots-configuration"></div>
-      </section>
-<if expr="not chromeos">
-      <section>
-        <div>$i18n{managementDesktopMonitoringNotice}</div>
-      </section>
-</if>
-    </section>
-  </div>
+  <management-ui></management-ui>
 </body>
 </html>
diff --git a/chrome/browser/resources/management/management.js b/chrome/browser/resources/management/management.js
deleted file mode 100644
index f4e8f0a..0000000
--- a/chrome/browser/resources/management/management.js
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @typedef {{
- *    name: string,
- *    permissions: !Array<string>
- * }}
- */
-let Extension;
-
-cr.define('management', function() {
-  /**
-   * A singleton object that handles communication between browser and WebUI.
-   */
-  class Page {
-    constructor() {
-      /** @private {!ManagementBrowserProxy} */
-      this.browserProxy_ = ManagementBrowserProxyImpl.getInstance();
-    }
-
-    /**
-     * Main initialization function. Called by the browser on page load.
-     */
-    initialize() {
-      // Notify the browser that the page has loaded, causing it to send the
-      // management data.
-
-      // Show whether device is managed or not, and the management domain in the
-      // former case.
-      this.browserProxy_.getDeviceManagementStatus()
-          .then(function(managedString) {
-            $('management-status').hidden = false;
-            document.body.querySelector('#management-status > p').textContent =
-                managedString;
-          })
-          .catch(
-              // On Chrome desktop, the behavior is to show nothing (device
-              // management is outside of Chrome's control), so
-              // RejectJavascriptCallback is used, which throws an error. The
-              // intended handling in this case is to do nothing.
-              () => {});
-
-      // Show descriptions of the types of reporting in the |reportingSources|
-      // list.
-      this.browserProxy_.getReportingInfo().then(function(reportingSources) {
-        if (reportingSources.length == 0) {
-          return;
-        }
-
-        $('policies').hidden = false;
-
-        for (const id of reportingSources) {
-          const element = document.createElement('li');
-          element.textContent = loadTimeData.getString(id);
-          $('reporting-info-list').appendChild(element);
-        }
-      });
-      // Show descriptions of the types of reporting in the |reportingSources|
-      // list.
-      this.browserProxy_.getBrowserReportingInfo().then(function(
-          reportingSources) {
-        if (reportingSources.length == 0) {
-          return;
-        }
-
-        $('browser-policies').hidden = false;
-
-        for (const id of reportingSources) {
-          const element = document.createElement('li');
-          element.textContent = loadTimeData.getString(id);
-          $('browser-reporting-info-list').appendChild(element);
-        }
-      });
-
-      // Show names and permissions of |extensions| in a table.
-      this.browserProxy_.getExtensions().then(function(extensions) {
-        if (extensions.length == 0) {
-          return;
-        }
-
-        const table = $('extensions-table');
-
-        for (const /** Extension */ extension of extensions) {
-          assert(
-              extension.hasOwnProperty('permissions'),
-              'Each extension must have the permissions field');
-          assert(
-              extension.hasOwnProperty('name'),
-              'Each extension must have the name field');
-
-          const permissionsList = document.createElement('ul');
-          for (const perm of extension.permissions) {
-            const permissionElement = document.createElement('li');
-            permissionElement.textContent = perm;
-            permissionsList.appendChild(permissionElement);
-          }
-
-          const row = table.insertRow();
-          const nameCell = row.insertCell();
-          // insertCell(-1) inserts at the last position.
-          const permissionsCell = row.insertCell(-1);
-          nameCell.textContent = extension.name;
-          permissionsCell.appendChild(permissionsList);
-        }
-
-        $('extensions').hidden = false;
-      });
-
-      this.browserProxy_.getLocalTrustRootsInfo().then(function(
-          trustRootsConfigured) {
-        if (trustRootsConfigured) {
-          $('trust-roots-configuration').textContent =
-              loadTimeData.getString('managementTrustRootsConfigured');
-        } else {
-          $('trust-roots-configuration').textContent =
-              loadTimeData.getString('managementTrustRootsNotConfigured');
-        }
-        $('trust-roots').hidden = false;
-      });
-    }
-  }
-
-  /** @interface */
-  class ManagementBrowserProxy {
-    /**
-     * @return {!Promise<string>} Message stating if device is enterprise
-     * managed and by whom.
-     */
-    getDeviceManagementStatus() {}
-
-    /**
-     * @return {!Promise<!Array<string>>} Types of device reporting.
-     */
-    getReportingInfo() {}
-
-    /**
-     * @return {!Promise<!Array<string>>} List of reporting info.
-     */
-    getBrowserReportingInfo() {}
-
-    /**
-     * Each extension has a name and a list of permission messages.
-     * @return {!Promise<!Array<!Extension>>} List of extensions.
-     */
-    getExtensions() {}
-
-    /**
-     * @return {!Promise<string>} Message describing trust root configuration
-     * status.
-     */
-    getLocalTrustRootsInfo() {}
-  }
-
-  /**
-   * @implements {ManagementBrowserProxy}
-   */
-  class ManagementBrowserProxyImpl {
-    /** @override */
-    getDeviceManagementStatus() {
-      return cr.sendWithPromise('getDeviceManagementStatus');
-    }
-
-    /** @override */
-    getReportingInfo() {
-      return cr.sendWithPromise('getReportingInfo');
-    }
-
-    /** @override */
-    getBrowserReportingInfo() {
-      return cr.sendWithPromise('getBrowserReportingInfo');
-    }
-
-    /** @override */
-    getExtensions() {
-      return cr.sendWithPromise('getExtensions');
-    }
-
-    /** @override */
-    getLocalTrustRootsInfo() {
-      return cr.sendWithPromise('getLocalTrustRootsInfo');
-    }
-  }
-
-  // Make Page a singleton.
-  cr.addSingletonGetter(Page);
-  cr.addSingletonGetter(ManagementBrowserProxyImpl);
-
-  return {Page: Page};
-});
-
-// Have the main initialization function be called when the page finishes
-// loading.
-document.addEventListener(
-    'DOMContentLoaded', () => management.Page.getInstance().initialize());
diff --git a/chrome/browser/resources/management/management_browser_proxy.html b/chrome/browser/resources/management/management_browser_proxy.html
new file mode 100644
index 0000000..abaff42
--- /dev/null
+++ b/chrome/browser/resources/management/management_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="management_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/management/management_browser_proxy.js b/chrome/browser/resources/management/management_browser_proxy.js
new file mode 100644
index 0000000..1f4df70
--- /dev/null
+++ b/chrome/browser/resources/management/management_browser_proxy.js
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.exportPath('management');
+/**
+ * @typedef {{
+ *    name: string,
+ *    permissions: !Array<string>
+ * }}
+ */
+management.Extension;
+
+cr.define('management', function() {
+  /** @interface */
+  class ManagementBrowserProxy {
+    /** @return {!Promise<!Array<!management.Extension>>} */
+    getExtensions() {}
+
+    // <if expr="chromeos">
+    /**
+     * @return {!Promise<boolean>} Boolean describing trust root configured
+     *     or not.
+     */
+    getLocalTrustRootsInfo() {}
+    // </if>
+
+    /**
+     * @return {!Promise<!Array<string>>} The list of browser reporting info
+     *     messages.
+     */
+    initBrowserReportingInfo() {}
+  }
+
+  /** @implements {management.ManagementBrowserProxy} */
+  class ManagementBrowserProxyImpl {
+    /** @override */
+    getExtensions() {
+      return cr.sendWithPromise('getExtensions');
+    }
+
+    // <if expr="chromeos">
+    /** @override */
+    getLocalTrustRootsInfo() {
+      return cr.sendWithPromise('getLocalTrustRootsInfo');
+    }
+    // </if>
+
+    /** @override */
+    initBrowserReportingInfo() {
+      return cr.sendWithPromise('initBrowserReportingInfo');
+    }
+  }
+
+  cr.addSingletonGetter(ManagementBrowserProxyImpl);
+
+  return {
+    ManagementBrowserProxy: ManagementBrowserProxy,
+    ManagementBrowserProxyImpl: ManagementBrowserProxyImpl
+  };
+});
diff --git a/chrome/browser/resources/management/management_ui.html b/chrome/browser/resources/management/management_ui.html
new file mode 100644
index 0000000..1bc12ae
--- /dev/null
+++ b/chrome/browser/resources/management/management_ui.html
@@ -0,0 +1,168 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="management_browser_proxy.html">
+
+<dom-module id="management-ui">
+  <template>
+    <style>
+      :host {
+        @apply --cr-page-host;
+        display: flex;
+        flex-direction: column;
+        height: 100%;
+      }
+
+      cr-toolbar {
+        --iron-icon-fill-color: white;
+        background-color: var(--md-toolbar-color);
+        color: white;
+        flex-shrink: 0;
+      }
+
+      main {
+        overflow: auto;
+        padding-bottom: 2em;
+      }
+
+      .header {
+        font-weight: 500;
+      }
+
+      h2 {
+        @apply --cr-title-text;
+        font-weight: 600;
+      }
+
+      .subtitle {
+        margin: 1em 0;
+      }
+
+      section {
+        @apply --cr-section;
+      }
+
+      .browser-report {
+        align-items: center;
+        display: flex;
+      }
+
+      .single-column {
+        align-items: flex-start;
+        flex-direction: column;
+        justify-content: center;
+      }
+
+      .content-indented {
+        margin-inline-start: 20px;
+      }
+
+      .three-line {
+        min-height: var(--cr-section-three-line-min-height);
+      }
+
+      .extension-name {
+        align-items: center;
+        display: flex;
+        flex: 2;
+      }
+
+      .extension-name > div {
+        align-items: center;
+        display: flex;
+      }
+
+      .extension-name img {
+        margin-inline-end: 20px;
+      }
+
+      .extension-permissions {
+        flex: 3;
+      }
+
+      .extensions-list .list-item {
+        display: flex;
+      }
+
+      .browser-report li,
+      .extensions-list li {
+        padding: 2px;
+      }
+
+      .browser-report ul,
+      .extensions-list ul {
+        list-style: none;
+        padding: 0;
+      }
+
+      .list-item div {
+        padding: 0 5px 0;
+      }
+    </style>
+
+    <cr-toolbar page-name="$i18n{title}" show-search="[[showSearchInToolbar_]]">
+    </cr-toolbar>
+    <main id="mainContent">
+      <template is="dom-if"
+          if="[[showBrowserReportingInfo_(browserReportingInfo_)]]">
+        <section class="three-line single-column">
+          <h2>$i18n{browserReporting}</h2>
+          <div class="content-indented browser-report">
+            <ul>
+              <template is="dom-repeat" items="[[browserReportingInfo_]]">
+                <li>[[item]]</li>
+              </template>
+            </ul>
+          </div>
+        </section>
+      </template>
+      <template is="dom-if" if="[[showExtensionReportingInfo_(extensions_)]]">
+        <section class="three-line single-column">
+          <h2>$i18n{extensionReporting}</h2>
+          <div class="content-indented subtitle">
+            $i18n{extensionsInstalled}
+          </div>
+          <div class="extensions-list">
+            <div class="list-item header">
+              <div class="extension-name">$i18n{extensionName}</div>
+              <div class="extension-permissions">
+                $i18n{extensionPermissions}
+              </div>
+            </div>
+            <template is="dom-repeat" items="[[extensions_]]">
+              <div class="list-item">
+                <div class="extension-name">
+                  <img src="[[item.icon]]" aria-describedby="a11yAssociation">
+                  <span>[[item.name]]</span>
+                </div>
+                <div class="extension-permissions">
+                  <ul>
+                    <template is="dom-repeat" items="[[item.permissions]]"
+                        as="permission">
+                      <li>[[permission]]</li>
+                    </template>
+                  </ul>
+                </div>
+            </template>
+          </div>
+        </section>
+      </template>
+      <if expr="chromeos">
+        <template is="dom-if" if="[[localTrustRoots_]]">
+          <section class="three-line single-column">
+            <h2>$i18n{localTrustRoots}</h2>
+            <div id="trust-roots-configuration">[[localTrustRoots_]]</div>
+          </section>
+        </template>
+      </if>
+      <if expr="not chromeos">
+        <section class="three-line single-column">
+          <p>$i18n{managementDesktopMonitoringNotice}</p>
+        </section>
+      </if>
+    </main>
+  </template>
+  <script src="management_ui.js"></script>
+</dom-module>
\ No newline at end of file
diff --git a/chrome/browser/resources/management/management_ui.js b/chrome/browser/resources/management/management_ui.js
new file mode 100644
index 0000000..0929422
--- /dev/null
+++ b/chrome/browser/resources/management/management_ui.js
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Polymer({
+  is: 'management-ui',
+
+  properties: {
+    /**
+     * List of messages related to browser reporting.
+     * @private {?Array<string>}
+     */
+    browserReportingInfo_: Array,
+
+    /**
+     * List of messages related to browser reporting.
+     * @private {?Array<!management.Extension>}
+     */
+    extensions_: Array,
+
+    // <if expr="chromeos">
+    /**
+     * Message stating if the Trust Roots are configured.
+     * @private
+     */
+    localTrustRoots_: String,
+    // </if>
+
+    /**
+     * Indicates if the search field in visible in the toolbar.
+     * @private
+     */
+    showSearchInToolbar_: {
+      type: Boolean,
+      value: false,
+    },
+  },
+
+  /** @private {?management.ManagementBrowserProxy} */
+  browserProxy_: null,
+
+  /** @override */
+  attached() {
+    document.documentElement.classList.remove('loading');
+    this.browserProxy_ = management.ManagementBrowserProxyImpl.getInstance();
+    this.initBrowserReportingInfo_();
+    this.getExtensions_();
+    // <if expr="chromeos">
+    this.getLocalTrustRootsInfo_();
+    // </if>
+  },
+
+  /** @private */
+  initBrowserReportingInfo_() {
+    this.browserProxy_.initBrowserReportingInfo().then(
+        reportingInfo => this.onBrowserReportingInfoReceived_(reportingInfo));
+  },
+
+  /**
+   * @param {!Array<string>} reportingInfo
+   * @private
+   */
+  onBrowserReportingInfoReceived_(reportingInfo) {
+    this.browserReportingInfo_ =
+        reportingInfo.map(id => loadTimeData.getString(id));
+  },
+
+  /** @private */
+  getExtensions_() {
+    this.browserProxy_.getExtensions().then(extensions => {
+      this.extensions_ = extensions;
+    });
+  },
+
+  // <if expr="chromeos">
+  /** @private */
+  getLocalTrustRootsInfo_() {
+    this.browserProxy_.getLocalTrustRootsInfo().then(trustRootsConfigured => {
+      this.localTrustRoots_ = loadTimeData.getString(
+          trustRootsConfigured ? 'managementTrustRootsConfigured' :
+                                 'managementTrustRootsNotConfigured');
+    });
+  },
+  // </if>
+
+  /**
+   * @return {boolean} True of there are browser reporting info to show.
+   * @private
+   */
+  showBrowserReportingInfo_() {
+    return !!this.browserReportingInfo_ &&
+        this.browserReportingInfo_.length > 0;
+  },
+
+  /**
+   * @return {boolean} True of there are extension reporting info to show.
+   * @private
+   */
+  showExtensionReportingInfo_() {
+    return !!this.extensions_ && this.extensions_.length > 0;
+  },
+});
diff --git a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html
index e582fdf..d7acee52 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html
+++ b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html
@@ -67,7 +67,8 @@
             checked$="[[equal_(selectedColor, item.color)]]"
             tabindex="1" style="--item-color: [[item.color]]"
             title$="[[lookup_(strings, item.name)]]"
-            aria-label$="[[lookup_(strings, item.name)]]">
+            aria-label$="[[lookup_(strings, item.name)]]"
+            on-pointerdown="blurOnPointerDown">
       </template>
       <paper-icon-button id="expand" icon="cr:expand-more"
           tabindex="3"
@@ -83,10 +84,11 @@
             checked$="[[equal_(selectedSize, item.size)]]"
             tabindex="2" style="--item-size: [[item.size]]"
             title$="{{lookup_(strings, item.name)}}"
-            aria-label$="[[lookup_(strings, item.name)]]">
+            aria-label$="[[lookup_(strings, item.name)]]"
+            on-pointerdown="blurOnPointerDown">
       </template>
     </div>
     </paper-icon-button>
   </template>
   <script src="viewer-pen-options.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
index 68735f1..db202e5 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
@@ -172,7 +172,7 @@
    * @param {*} a
    * @param {*} b
    */
-  equal_: function(a,b) {
+  equal_: function(a, b) {
     return a == b;
   },
 
@@ -185,5 +185,15 @@
    */
   lookup_: function(strings, name) {
     return strings ? strings[name] : '';
-  }
-});
\ No newline at end of file
+  },
+
+  /**
+   * Used to remove focus when clicking or tapping on a styled input
+   * element. This is a workaround until we can use the :focus-visible
+   * pseudo selector.
+   */
+  blurOnPointerDown(e) {
+    const target = e.target;
+    setTimeout(() => target.blur(), 0);
+  },
+});
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
index 368bc20..25b269c9 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
@@ -135,7 +135,7 @@
 }
 
 void AdvancedProtectionStatusManager::OnPrimaryAccountCleared(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   OnAdvancedProtectionDisabled();
 }
 
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.h b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
index 6bd48d6..bfc9c7c 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.h
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
@@ -83,7 +83,7 @@
 
   // IdentityManager::Observer implementations.
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override;
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
   void OnAccountUpdated(const AccountInfo& info) override;
   void OnAccountRemovedWithInfo(const AccountInfo& info) override;
 
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.cc b/chrome/browser/signin/signin_profile_attributes_updater.cc
index 3232d83..830a9e2 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.cc
+++ b/chrome/browser/signin/signin_profile_attributes_updater.cc
@@ -85,6 +85,6 @@
 }
 
 void SigninProfileAttributesUpdater::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   UpdateProfileAttributes();
 }
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.h b/chrome/browser/signin/signin_profile_attributes_updater.h
index a6020755..1ba9dc04 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.h
+++ b/chrome/browser/signin/signin_profile_attributes_updater.h
@@ -40,7 +40,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   identity::IdentityManager* identity_manager_;
   SigninErrorController* signin_error_controller_;
diff --git a/chrome/browser/signin/signin_util_win_browsertest.cc b/chrome/browser/signin/signin_util_win_browsertest.cc
index 5dbf31ed..91add871 100644
--- a/chrome/browser/signin/signin_util_win_browsertest.cc
+++ b/chrome/browser/signin/signin_util_win_browsertest.cc
@@ -15,8 +15,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_util_win.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
@@ -27,8 +26,10 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "components/os_crypt/os_crypt.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_pref_names.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
+#include "services/identity/public/cpp/primary_account_mutator.h"
 
 namespace {
 
@@ -208,9 +209,13 @@
     ASSERT_FALSE(signin_util::ReauthWithCredentialProviderIfPossible(profile));
 
     // Sign user out of browser.
-    SigninManager* manager = SigninManagerFactory::GetForProfile(profile);
-    manager->SignOut(signin_metrics::ProfileSignout::SIGNOUT_TEST,
-                     signin_metrics::SignoutDelete::DELETED);
+    auto* primary_account_mutator =
+        IdentityManagerFactory::GetForProfile(profile)
+            ->GetPrimaryAccountMutator();
+    primary_account_mutator->ClearPrimaryAccount(
+        identity::PrimaryAccountMutator::ClearAccountsAction::kDefault,
+        signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
+        signin_metrics::SignoutDelete::DELETED);
 
     // Even with a refresh token available, no reauth happens if the profile
     // is signed out.
@@ -233,12 +238,9 @@
     ASSERT_FALSE(signin_util::ReauthWithCredentialProviderIfPossible(profile));
 
     // Make sure the profile stays signed in, but in an auth error state.
-    ProfileOAuth2TokenService* token_service =
-        ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
-    OAuth2TokenServiceDelegate* delegate = token_service->GetDelegate();
-    SigninManager* manager = SigninManagerFactory::GetForProfile(profile);
-    delegate->UpdateAuthError(
-        manager->GetAuthenticatedAccountId(),
+    auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
+    identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+        identity_manager, identity_manager->GetPrimaryAccountId(),
         GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
             GoogleServiceAuthError::InvalidGaiaCredentialsReason::
                 CREDENTIALS_REJECTED_BY_SERVER));
diff --git a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
index 62d0a21..90b066a 100644
--- a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
+++ b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
@@ -6,20 +6,21 @@
 
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/sync/driver/sync_client.h"
+#include "components/browser_sync/browser_sync_client.h"
 #include "components/sync/model/model_type_store_service.h"
 
 SupervisedUserSyncModelTypeController::SupervisedUserSyncModelTypeController(
     syncer::ModelType type,
     const Profile* profile,
     const base::RepeatingClosure& dump_stack,
-    syncer::SyncClient* sync_client)
+    browser_sync::BrowserSyncClient* sync_client)
     : SyncableServiceBasedModelTypeController(
           type,
           sync_client->GetModelTypeStoreService()->GetStoreFactory(),
-          base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
-                         base::Unretained(sync_client),
-                         type),
+          base::BindOnce(
+              &browser_sync::BrowserSyncClient::GetSyncableServiceForType,
+              base::Unretained(sync_client),
+              type),
           dump_stack),
       profile_(profile) {
   DCHECK(type == syncer::SUPERVISED_USER_SETTINGS ||
diff --git a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h
index 2b626d0..be5feec 100644
--- a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h
+++ b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h
@@ -11,9 +11,9 @@
 
 class Profile;
 
-namespace syncer {
-class SyncClient;
-}
+namespace browser_sync {
+class BrowserSyncClient;
+}  // namespace browser_sync
 
 // A DataTypeController for supervised user sync datatypes, which enables or
 // disables these types based on the profile's IsSupervised state.
@@ -25,7 +25,7 @@
       syncer::ModelType type,
       const Profile* profile,
       const base::RepeatingClosure& dump_stack,
-      syncer::SyncClient* sync_client);
+      browser_sync::BrowserSyncClient* sync_client);
   ~SupervisedUserSyncModelTypeController() override;
 
   // DataTypeController override.
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 070889d..267c2fe5 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -163,12 +163,7 @@
 
 }  // namespace
 
-ChromeSyncClient::ChromeSyncClient(Profile* profile) : profile_(profile) {}
-
-ChromeSyncClient::~ChromeSyncClient() {
-}
-
-void ChromeSyncClient::Initialize() {
+ChromeSyncClient::ChromeSyncClient(Profile* profile) : profile_(profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   profile_web_data_service_ =
@@ -192,18 +187,17 @@
   password_store_ = PasswordStoreFactory::GetForProfile(
       profile_, ServiceAccessType::IMPLICIT_ACCESS);
 
-  // Component factory may already be set in tests.
-  if (!GetSyncApiComponentFactory()) {
-    component_factory_ = std::make_unique<ProfileSyncComponentsFactoryImpl>(
-        this, chrome::GetChannel(), prefs::kSavingBrowserHistoryDisabled,
-        base::CreateSingleThreadTaskRunnerWithTraits(
-            {content::BrowserThread::UI}),
-        web_data_service_thread_, profile_web_data_service_,
-        account_web_data_service_, password_store_,
-        BookmarkSyncServiceFactory::GetForProfile(profile_));
-  }
+  component_factory_ = std::make_unique<ProfileSyncComponentsFactoryImpl>(
+      this, chrome::GetChannel(), prefs::kSavingBrowserHistoryDisabled,
+      base::CreateSingleThreadTaskRunnerWithTraits(
+          {content::BrowserThread::UI}),
+      web_data_service_thread_, profile_web_data_service_,
+      account_web_data_service_, password_store_,
+      BookmarkSyncServiceFactory::GetForProfile(profile_));
 }
 
+ChromeSyncClient::~ChromeSyncClient() {}
+
 PrefService* ChromeSyncClient::GetPrefService() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return profile_->GetPrefs();
@@ -269,10 +263,6 @@
   return SessionSyncServiceFactory::GetForProfile(profile_);
 }
 
-bool ChromeSyncClient::HasPasswordStore() {
-  return password_store_ != nullptr;
-}
-
 autofill::PersonalDataManager* ChromeSyncClient::GetPersonalDataManager() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return autofill::PersonalDataManagerFactory::GetForProfile(profile_);
@@ -471,8 +461,8 @@
   return controllers;
 }
 
-BookmarkUndoService* ChromeSyncClient::GetBookmarkUndoServiceIfExists() {
-  return BookmarkUndoServiceFactory::GetForProfileIfExists(profile_);
+BookmarkUndoService* ChromeSyncClient::GetBookmarkUndoService() {
+  return BookmarkUndoServiceFactory::GetForProfile(profile_);
 }
 
 invalidation::InvalidationService* ChromeSyncClient::GetInvalidationService() {
@@ -617,6 +607,10 @@
           ->change_processor()
           ->GetControllerDelegate();
 #endif  // defined(OS_CHROMEOS)
+    case syncer::SECURITY_EVENTS:
+      // TODO(crbug.com/919489): Return the real delegate once it is wired to
+      // the security event service.
+      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::USER_CONSENTS:
       return ConsentAuditorFactory::GetForProfile(profile_)
           ->GetControllerDelegate();
@@ -690,9 +684,4 @@
   return component_factory_.get();
 }
 
-void ChromeSyncClient::SetSyncApiComponentFactoryForTesting(
-    std::unique_ptr<syncer::SyncApiComponentFactory> component_factory) {
-  component_factory_ = std::move(component_factory);
-}
-
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index ae728503..c89058c 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "chrome/browser/sync/glue/extensions_activity_monitor.h"
-#include "components/sync/driver/sync_client.h"
+#include "components/browser_sync/browser_sync_client.h"
 #include "components/sync/model/model_type_store_service.h"
 
 class Profile;
@@ -25,20 +25,19 @@
 }
 
 namespace syncer {
-class SyncApiComponentFactory;
 class SyncService;
 }
 
 namespace browser_sync {
 
-class ChromeSyncClient : public syncer::SyncClient {
+class ProfileSyncComponentsFactoryImpl;
+
+class ChromeSyncClient : public browser_sync::BrowserSyncClient {
  public:
   explicit ChromeSyncClient(Profile* profile);
   ~ChromeSyncClient() override;
 
-  void Initialize();
-
-  // SyncClient implementation.
+  // BrowserSyncClient implementation.
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
   syncer::ModelTypeStoreService* GetModelTypeStoreService() override;
@@ -47,13 +46,12 @@
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
-  bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
   syncer::DataTypeController::TypeVector CreateDataTypeControllers(
       syncer::SyncService* sync_service) override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   invalidation::InvalidationService* GetInvalidationService() override;
-  BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
+  BookmarkUndoService* GetBookmarkUndoService() override;
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
@@ -63,15 +61,14 @@
       syncer::ModelSafeGroup group) override;
   syncer::SyncApiComponentFactory* GetSyncApiComponentFactory() override;
 
-  // Helpers for overriding getters in tests.
-  void SetSyncApiComponentFactoryForTesting(
-      std::unique_ptr<syncer::SyncApiComponentFactory> component_factory);
-
  private:
   Profile* const profile_;
 
   // The sync api component factory in use by this client.
-  std::unique_ptr<syncer::SyncApiComponentFactory> component_factory_;
+  // TODO(crbug.com/915154): Revert to SyncApiComponentFactory once common
+  // controller creation is moved elsewhere.
+  std::unique_ptr<browser_sync::ProfileSyncComponentsFactoryImpl>
+      component_factory_;
 
   // Members that must be fetched on the UI thread but accessed on their
   // respective backend threads.
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index ab3c7ee..7ac80d4 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -183,7 +183,6 @@
       client_factory_
           ? client_factory_->Run(profile)
           : std::make_unique<browser_sync::ChromeSyncClient>(profile);
-  sync_client->Initialize();
 
   init_params.sync_client = std::move(sync_client);
   init_params.network_time_update_callback = base::Bind(&UpdateNetworkTime);
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index a41b7398..cfa8f09 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -45,7 +45,7 @@
 
   // Returns the collection of default datatypes.
   std::vector<syncer::ModelType> DefaultDatatypes() {
-    static_assert(43 == syncer::MODEL_TYPE_COUNT,
+    static_assert(44 == syncer::MODEL_TYPE_COUNT,
                   "When adding a new type, you probably want to add it here as "
                   "well (assuming it is already enabled).");
 
@@ -96,6 +96,8 @@
     if (base::FeatureList::IsEnabled(switches::kSyncSendTabToSelf)) {
       datatypes.push_back(syncer::SEND_TAB_TO_SELF);
     }
+    // TODO(markusheintz): Add security events once it is enabled.
+    // datatypes.push_back(syncer::SECURITY_EVENTS);
     return datatypes;
   }
 
diff --git a/chrome/browser/sync/profile_sync_test_util.cc b/chrome/browser/sync/profile_sync_test_util.cc
index 0ff4dfe..a3f3866 100644
--- a/chrome/browser/sync/profile_sync_test_util.cc
+++ b/chrome/browser/sync/profile_sync_test_util.cc
@@ -33,25 +33,12 @@
 
 ProfileSyncService::InitParams CreateProfileSyncServiceParamsForTest(
     Profile* profile) {
-  auto sync_client = std::make_unique<browser_sync::ChromeSyncClient>(profile);
-
-  sync_client->SetSyncApiComponentFactoryForTesting(
-      std::make_unique<NiceMock<syncer::SyncApiComponentFactoryMock>>());
-
-  ProfileSyncService::InitParams init_params =
-      CreateProfileSyncServiceParamsForTest(std::move(sync_client), profile);
-
-  return init_params;
-}
-
-ProfileSyncService::InitParams CreateProfileSyncServiceParamsForTest(
-    std::unique_ptr<syncer::SyncClient> sync_client,
-    Profile* profile) {
   ProfileSyncService::InitParams init_params;
 
   init_params.identity_manager = IdentityManagerFactory::GetForProfile(profile);
   init_params.start_behavior = ProfileSyncService::MANUAL_START;
-  init_params.sync_client = std::move(sync_client);
+  init_params.sync_client =
+      std::make_unique<browser_sync::ChromeSyncClient>(profile);
   init_params.network_time_update_callback = base::DoNothing();
   bool fcm_invalidations_enabled =
       base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
@@ -72,18 +59,6 @@
   return init_params;
 }
 
-std::unique_ptr<TestingProfile> MakeSignedInTestingProfile() {
-  std::unique_ptr<TestingProfile> profile =
-      IdentityTestEnvironmentProfileAdaptor::
-          CreateProfileForIdentityTestEnvironment();
-  auto identity_test_env_profile_adaptor =
-      std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get());
-
-  identity_test_env_profile_adaptor->identity_test_env()->SetPrimaryAccount(
-      "test@mail.com");
-  return profile;
-}
-
 std::unique_ptr<KeyedService> BuildMockProfileSyncService(
     content::BrowserContext* context) {
   return std::make_unique<NiceMock<browser_sync::ProfileSyncServiceMock>>(
diff --git a/chrome/browser/sync/profile_sync_test_util.h b/chrome/browser/sync/profile_sync_test_util.h
index 7bbd9f20..9c0abe6 100644
--- a/chrome/browser/sync/profile_sync_test_util.h
+++ b/chrome/browser/sync/profile_sync_test_util.h
@@ -19,16 +19,11 @@
 
 class KeyedService;
 class Profile;
-class TestingProfile;
 
 namespace content {
 class BrowserContext;
 }
 
-namespace syncer {
-class SyncClient;
-}
-
 ACTION_P(Notify, type) {
   content::NotificationService::current()->Notify(
       type,
@@ -44,14 +39,6 @@
 // Helper methods for constructing ProfileSyncService mocks.
 browser_sync::ProfileSyncService::InitParams
 CreateProfileSyncServiceParamsForTest(Profile* profile);
-browser_sync::ProfileSyncService::InitParams
-CreateProfileSyncServiceParamsForTest(
-    std::unique_ptr<syncer::SyncClient> sync_client,
-    Profile* profile);
-
-// A utility used by sync tests to create a TestingProfile with a Google
-// Services username stored in a (Testing)PrefService.
-std::unique_ptr<TestingProfile> MakeSignedInTestingProfile();
 
 // Helper routine to be used in conjunction with
 // BrowserContextKeyedServiceFactory::SetTestingFactory().
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 871c01b..87322ea 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/sync/sync_ui_util.h"
 
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -286,13 +287,14 @@
 }  // namespace
 
 MessageType GetStatusLabels(Profile* profile,
-                            const syncer::SyncService* service,
-                            identity::IdentityManager* identity_manager,
                             base::string16* status_label,
                             base::string16* link_label,
                             ActionType* action_type) {
-  DCHECK(service);
-
+  DCHECK(profile);
+  syncer::SyncService* service =
+      ProfileSyncServiceFactory::GetSyncServiceForProfile(profile);
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile);
   const bool is_user_signout_allowed =
       signin_util::IsUserSignoutAllowedForProfile(profile);
   GoogleServiceAuthError auth_error =
@@ -301,6 +303,12 @@
                              auth_error, status_label, link_label, action_type);
 }
 
+MessageType GetStatus(Profile* profile) {
+  ActionType action_type = NO_ACTION;
+  return GetStatusLabels(profile, /*status_label=*/nullptr,
+                         /*link_label=*/nullptr, &action_type);
+}
+
 #if !defined(OS_CHROMEOS)
 AvatarSyncErrorType GetMessagesForAvatarSyncError(
     Profile* profile,
@@ -375,16 +383,6 @@
 }
 #endif  // !defined(OS_CHROMEOS)
 
-MessageType GetStatus(Profile* profile,
-                      const syncer::SyncService* service,
-                      identity::IdentityManager* identity_manager) {
-  DCHECK(service);
-  ActionType action_type = NO_ACTION;
-  return GetStatusLabels(profile, service, identity_manager,
-                         /*status_label=*/nullptr, /*link_label=*/nullptr,
-                         &action_type);
-}
-
 bool ShouldRequestSyncConfirmation(const syncer::SyncService* service) {
   return !service->IsLocalSyncEnabled() &&
          service->GetUserSettings()->IsSyncRequested() &&
diff --git a/chrome/browser/sync/sync_ui_util.h b/chrome/browser/sync/sync_ui_util.h
index 56493c1..1ae4b17 100644
--- a/chrome/browser/sync/sync_ui_util.h
+++ b/chrome/browser/sync/sync_ui_util.h
@@ -10,10 +10,6 @@
 
 class Profile;
 
-namespace identity {
-class IdentityManager;
-}
-
 namespace syncer {
 class SyncService;
 }  // namespace syncer
@@ -43,23 +39,27 @@
   NO_SYNC_ERROR,                     // No sync error.
   MANAGED_USER_UNRECOVERABLE_ERROR,  // Unrecoverable error for managed users.
   UNRECOVERABLE_ERROR,               // Unrecoverable error for regular users.
-  SUPERVISED_USER_AUTH_ERROR,        // Auth token error for supervised users.
-  AUTH_ERROR,                        // Authentication error.
-  UPGRADE_CLIENT_ERROR,              // Out-of-date client error.
-  PASSPHRASE_ERROR,                  // Sync passphrase error.
-  SETTINGS_UNCONFIRMED_ERROR,        // Sync settings dialog not confirmed yet.
+  // TODO(crbug.com/911153): Remove this value. It is never returned, but some
+  // clients still check for it.
+  SUPERVISED_USER_AUTH_ERROR,  // Auth token error for supervised users.
+  AUTH_ERROR,                  // Authentication error.
+  UPGRADE_CLIENT_ERROR,        // Out-of-date client error.
+  PASSPHRASE_ERROR,            // Sync passphrase error.
+  SETTINGS_UNCONFIRMED_ERROR,  // Sync settings dialog not confirmed yet.
 };
 
-// Create status and link labels for the current status labels and link text
-// by querying |service|.
+// Returns the high-level sync status, and populates status and link label
+// strings for the current sync status by querying |profile|.
 // |status_label| and |link_label| must either be both null or both non-null.
 MessageType GetStatusLabels(Profile* profile,
-                            const syncer::SyncService* service,
-                            identity::IdentityManager* identity_manager,
                             base::string16* status_label,
                             base::string16* link_label,
                             ActionType* action_type);
 
+// Convenience version of GetStatusLabels for when you're not interested in the
+// actual labels, only in the return value.
+MessageType GetStatus(Profile* profile);
+
 #if !defined(OS_CHROMEOS)
 // Gets the error message and button label for the sync errors that should be
 // exposed to the user through the titlebar avatar button.
@@ -69,10 +69,6 @@
     int* button_string_id);
 #endif
 
-MessageType GetStatus(Profile* profile,
-                      const syncer::SyncService* service,
-                      identity::IdentityManager* identity_manager);
-
 // Whether sync is currently blocked from starting because the sync
 // confirmation dialog hasn't been shown. Note that once the dialog is
 // showing (i.e. IsFirstSetupInProgress() is true), this will return false.
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index efc045b..d073398 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -2,40 +2,33 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stddef.h>
-
 #include <memory>
 #include <set>
+#include <string>
 
 #include "base/bind.h"
-#include "base/macros.h"
+#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
-#include "chrome/browser/signin/signin_error_controller_factory.h"
-#include "chrome/browser/sync/profile_sync_test_util.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/sync_ui_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/sync/driver/test_sync_service.h"
-#include "content/public/test/test_browser_thread.h"
+#include "components/sync/engine/sync_engine.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/identity_test_environment.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
 #include "services/identity/public/cpp/primary_account_mutator.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
 using syncer::TestSyncService;
-using ::testing::_;
-using ::testing::AtMost;
-using ::testing::NiceMock;
-using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::SetArgPointee;
+
+namespace {
 
 // A number of distinct states of the SyncService can be generated for tests.
 enum DistinctState {
@@ -51,8 +44,6 @@
   NUMBER_OF_STATUS_CASES
 };
 
-namespace {
-
 const char kTestGaiaId[] = "gaia-id-test_user@test.com";
 const char kTestUser[] = "test_user@test.com";
 const char kRefreshToken[] = "refresh_token";
@@ -203,13 +194,31 @@
   }
 }
 
+std::unique_ptr<KeyedService> BuildTestSyncService(
+    content::BrowserContext* context) {
+  return std::make_unique<TestSyncService>();
+}
+
+std::unique_ptr<TestingProfile> BuildTestingProfile() {
+  return IdentityTestEnvironmentProfileAdaptor::
+      CreateProfileForIdentityTestEnvironment(
+          {{ProfileSyncServiceFactory::GetInstance(),
+            base::BindRepeating(&BuildTestSyncService)}});
+}
+
+std::unique_ptr<TestingProfile> BuildSignedInTestingProfile() {
+  std::unique_ptr<TestingProfile> profile = BuildTestingProfile();
+  IdentityTestEnvironmentProfileAdaptor identity_adaptor(profile.get());
+  identity_adaptor.identity_test_env()->SetPrimaryAccount(kTestUser);
+  return profile;
+}
+
 // This test ensures that each distinctive SyncService status will return a
 // unique combination of status and link messages from GetStatusLabels().
 TEST_F(SyncUIUtilTest, DistinctCasesReportUniqueMessageSets) {
   std::set<base::string16> messages;
   for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
-    std::unique_ptr<Profile> profile = IdentityTestEnvironmentProfileAdaptor::
-        CreateProfileForIdentityTestEnvironment();
+    std::unique_ptr<Profile> profile = BuildTestingProfile();
 
     IdentityTestEnvironmentProfileAdaptor env_adaptor(profile.get());
     identity::IdentityTestEnvironment* environment =
@@ -227,13 +236,14 @@
     // Need a primary account signed in before calling GetDistinctCase().
     environment->MakePrimaryAccountAvailable(kTestUser);
 
-    TestSyncService service;
-    GetDistinctCase(&service, identity_manager, idx);
+    TestSyncService* service = static_cast<TestSyncService*>(
+        ProfileSyncServiceFactory::GetSyncServiceForProfile(profile.get()));
+    GetDistinctCase(service, identity_manager, idx);
     base::string16 status_label;
     base::string16 link_label;
     sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
-    sync_ui_util::GetStatusLabels(profile.get(), &service, identity_manager,
-                                  &status_label, &link_label, &action_type);
+    sync_ui_util::GetStatusLabels(profile.get(), &status_label, &link_label,
+                                  &action_type);
 
     EXPECT_EQ(GetActionTypeforDistinctCase(idx), action_type)
         << "Wrong action returned for case #" << idx;
@@ -256,22 +266,21 @@
 }
 
 TEST_F(SyncUIUtilTest, UnrecoverableErrorWithActionableError) {
-  std::unique_ptr<Profile> profile(MakeSignedInTestingProfile());
-  identity::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(profile.get());
+  std::unique_ptr<Profile> profile = BuildSignedInTestingProfile();
 
-  TestSyncService service;
-  service.SetFirstSetupComplete(true);
-  service.SetDisableReasons(
+  TestSyncService* service = static_cast<TestSyncService*>(
+      ProfileSyncServiceFactory::GetSyncServiceForProfile(profile.get()));
+  service->SetFirstSetupComplete(true);
+  service->SetDisableReasons(
       syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR);
 
   // First time action is not set. We should get unrecoverable error.
-  service.SetDetailedSyncStatus(true, syncer::SyncStatus());
+  service->SetDetailedSyncStatus(true, syncer::SyncStatus());
 
   base::string16 link_label;
   base::string16 unrecoverable_error_status_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
-  sync_ui_util::GetStatusLabels(profile.get(), &service, identity_manager,
+  sync_ui_util::GetStatusLabels(profile.get(),
                                 &unrecoverable_error_status_label, &link_label,
                                 &action_type);
 
@@ -282,11 +291,10 @@
   // from previous one.
   syncer::SyncStatus status;
   status.sync_protocol_error.action = syncer::UPGRADE_CLIENT;
-  service.SetDetailedSyncStatus(true, status);
+  service->SetDetailedSyncStatus(true, status);
   base::string16 upgrade_client_status_label;
-  sync_ui_util::GetStatusLabels(profile.get(), &service, identity_manager,
-                                &upgrade_client_status_label, &link_label,
-                                &action_type);
+  sync_ui_util::GetStatusLabels(profile.get(), &upgrade_client_status_label,
+                                &link_label, &action_type);
   // Expect an explicit 'client upgrade' action.
   EXPECT_EQ(sync_ui_util::UPGRADE_CLIENT, action_type);
 
@@ -294,24 +302,23 @@
 }
 
 TEST_F(SyncUIUtilTest, ActionableErrorWithPassiveMessage) {
-  std::unique_ptr<Profile> profile(MakeSignedInTestingProfile());
-  identity::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(profile.get());
+  std::unique_ptr<Profile> profile = BuildSignedInTestingProfile();
 
-  TestSyncService service;
-  service.SetFirstSetupComplete(true);
-  service.SetDisableReasons(
+  TestSyncService* service = static_cast<TestSyncService*>(
+      ProfileSyncServiceFactory::GetSyncServiceForProfile(profile.get()));
+  service->SetFirstSetupComplete(true);
+  service->SetDisableReasons(
       syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR);
 
   // Set action to UPGRADE_CLIENT.
   syncer::SyncStatus status;
   status.sync_protocol_error.action = syncer::UPGRADE_CLIENT;
-  service.SetDetailedSyncStatus(true, status);
+  service->SetDetailedSyncStatus(true, status);
 
   base::string16 first_actionable_error_status_label;
   base::string16 link_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
-  sync_ui_util::GetStatusLabels(profile.get(), &service, identity_manager,
+  sync_ui_util::GetStatusLabels(profile.get(),
                                 &first_actionable_error_status_label,
                                 &link_label, &action_type);
   // Expect a 'client upgrade' call to action.
@@ -319,11 +326,11 @@
 
   // This time set action to ENABLE_SYNC_ON_ACCOUNT.
   status.sync_protocol_error.action = syncer::ENABLE_SYNC_ON_ACCOUNT;
-  service.SetDetailedSyncStatus(true, status);
+  service->SetDetailedSyncStatus(true, status);
 
   base::string16 second_actionable_error_status_label;
   action_type = sync_ui_util::NO_ACTION;
-  sync_ui_util::GetStatusLabels(profile.get(), &service, identity_manager,
+  sync_ui_util::GetStatusLabels(profile.get(),
                                 &second_actionable_error_status_label,
                                 &link_label, &action_type);
   // Expect a passive message instead of a call to action.
@@ -334,21 +341,19 @@
 }
 
 TEST_F(SyncUIUtilTest, SyncSettingsConfirmationNeededTest) {
-  std::unique_ptr<Profile> profile(MakeSignedInTestingProfile());
-  identity::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(profile.get());
+  std::unique_ptr<Profile> profile = BuildSignedInTestingProfile();
 
-  TestSyncService service;
-  service.SetFirstSetupComplete(false);
-  ASSERT_TRUE(sync_ui_util::ShouldRequestSyncConfirmation(&service));
+  TestSyncService* service = static_cast<TestSyncService*>(
+      ProfileSyncServiceFactory::GetSyncServiceForProfile(profile.get()));
+  service->SetFirstSetupComplete(false);
+  ASSERT_TRUE(sync_ui_util::ShouldRequestSyncConfirmation(service));
 
   base::string16 actionable_error_status_label;
   base::string16 link_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
 
-  sync_ui_util::GetStatusLabels(profile.get(), &service, identity_manager,
-                                &actionable_error_status_label, &link_label,
-                                &action_type);
+  sync_ui_util::GetStatusLabels(profile.get(), &actionable_error_status_label,
+                                &link_label, &action_type);
 
   EXPECT_EQ(action_type, sync_ui_util::CONFIRM_SYNC_SETTINGS);
 }
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc
index 1882abad..92b5a1a4 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.cc
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -249,10 +248,8 @@
     favicon_service->SetFavicons({node->url()}, icon_url,
                                  favicon_base::IconType::kFavicon, image);
     } else {
-      browser_sync::ProfileSyncService* pss =
-          ProfileSyncServiceFactory::GetForProfile(profile);
       sync_bookmarks::BookmarkChangeProcessor::ApplyBookmarkFavicon(
-          node, pss->GetSyncClientForTest(), icon_url, image.As1xPNGBytes());
+          node, favicon_service, icon_url, image.As1xPNGBytes());
     }
 
     // Wait for the favicon for |node| to be invalidated.
@@ -295,10 +292,8 @@
     favicon_service->DeleteFaviconMappings({node->url()},
                                            favicon_base::IconType::kFavicon);
   } else {
-    browser_sync::ProfileSyncService* pss =
-        ProfileSyncServiceFactory::GetForProfile(profile);
     sync_bookmarks::BookmarkChangeProcessor::ApplyBookmarkFavicon(
-        node, pss->GetSyncClientForTest(), /*icon_url=*/GURL(),
+        node, favicon_service, /*icon_url=*/GURL(),
         scoped_refptr<base::RefCountedString>(new base::RefCountedString()));
   }
 
diff --git a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
index 57d4aa3cb..689957e 100644
--- a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
@@ -80,7 +80,6 @@
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   browser_sync::ProfileSyncService* sync_service = GetSyncService(0);
   FilePath directory_path = sync_service->GetSyncClientForTest()
-                                ->GetModelTypeStoreService()
                                 ->GetSyncDataPath();
   ASSERT_TRUE(FolderContainsFiles(directory_path));
   sync_service->StopAndClear();
@@ -116,7 +115,6 @@
 
   // Now corrupt the database.
   FilePath directory_path = sync_service->GetSyncClientForTest()
-                                ->GetModelTypeStoreService()
                                 ->GetSyncDataPath();
   const FilePath sync_db(directory_path.Append(
       syncer::syncable::Directory::kSyncDatabaseFilename));
diff --git a/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc b/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc
index 3d5e986..5775266 100644
--- a/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc
@@ -111,7 +111,7 @@
 };
 
 IN_PROC_BROWSER_TEST_P(SingleClientHistoryDeleteDirectivesSyncTest,
-                       ShouldCommitDeleteDirective) {
+                       ShouldCommitTimeRangeDeleteDirective) {
   const GURL kPageUrl = GURL("http://foo.com");
   const base::Time kHistoryEntryTime = base::Time::Now();
   base::CancelableTaskTracker task_tracker;
@@ -123,10 +123,27 @@
   history_service->AddPage(kPageUrl, kHistoryEntryTime,
                            history::SOURCE_BROWSED);
 
-  history_service->ExpireLocalAndRemoteHistoryBetween(
-      WebHistoryServiceFactory::GetForProfile(GetProfile(0)), std::set<GURL>(),
-      /*begin_time=*/base::Time(), /*end_time=*/base::Time(),
-      /*user_initiated*/ true, base::DoNothing(), &task_tracker);
+  history_service->DeleteLocalAndRemoteHistoryBetween(
+      WebHistoryServiceFactory::GetForProfile(GetProfile(0)),
+      /*begin_time=*/base::Time(), /*end_time=*/base::Time(), base::DoNothing(),
+      &task_tracker);
+
+  EXPECT_TRUE(WaitForHistoryDeleteDirectives(1));
+}
+
+IN_PROC_BROWSER_TEST_P(SingleClientHistoryDeleteDirectivesSyncTest,
+                       ShouldCommitUrlDeleteDirective) {
+  const GURL kPageUrl = GURL("http://foo.com");
+  const base::Time kHistoryEntryTime = base::Time::Now();
+  ASSERT_TRUE(SetupSync());
+
+  history::HistoryService* history_service =
+      HistoryServiceFactory::GetForProfileWithoutCreating(GetProfile(0));
+  history_service->AddPage(kPageUrl, kHistoryEntryTime,
+                           history::SOURCE_BROWSED);
+
+  history_service->DeleteLocalAndRemoteUrl(
+      WebHistoryServiceFactory::GetForProfile(GetProfile(0)), kPageUrl);
 
   EXPECT_TRUE(WaitForHistoryDeleteDirectives(1));
 }
diff --git a/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc b/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
index a0da8c25..b0b824d 100644
--- a/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
@@ -6,6 +6,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/sync/test/integration/feature_toggler.h"
 #include "chrome/browser/sync/test/integration/preferences_helper.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
@@ -71,8 +72,16 @@
   EXPECT_FALSE(BooleanPrefMatches(pref_name.c_str()));
 }
 
+// Flaky on Windows. https://crbug.com/930482
+#if defined(OS_WIN)
+#define MAYBE_ShouldRemoveBadDataWhenRegistering \
+  DISABLED_ShouldRemoveBadDataWhenRegistering
+#else
+#define MAYBE_ShouldRemoveBadDataWhenRegistering \
+  ShouldRemoveBadDataWhenRegistering
+#endif
 IN_PROC_BROWSER_TEST_P(SingleClientPreferencesSyncTest,
-                       ShouldRemoveBadDataWhenRegistering) {
+                       MAYBE_ShouldRemoveBadDataWhenRegistering) {
   // Populate the data store with data of type boolean but register as string.
   SetPreexistingPreferencesFileContents(
       0, "{\"testing\":{\"my-test-preference\":true}}");
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 375d1f2..bbc80bc 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -29,6 +29,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/protocol/model_type_state.pb.h"
 #include "components/sync/test/fake_server/fake_server.h"
 #include "components/webdata/common/web_data_service_consumer.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
index 621ca3d..8114750 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
@@ -715,7 +715,7 @@
 }
 
 void SyncEngine::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   Reset();
   UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
                      "User signed out.");
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.h b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
index 4d5b4d76..d20e692 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
@@ -150,7 +150,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
   void OnPrimaryAccountSigninFailed(
       const GoogleServiceAuthError& error) override;
 
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 732d9151..eae1bde 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1853,13 +1853,7 @@
 }
 #endif
 
-// Flaky on Chrome OS only. TODO(https://crbug.com/823043) fix it.
-#if defined(OS_CHROMEOS)
-#define MAYBE_WindowOpenClose1 DISABLED_WindowOpenClose1
-#else
-#define MAYBE_WindowOpenClose1 WindowOpenClose1
-#endif
-IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_WindowOpenClose1) {
+IN_PROC_BROWSER_TEST_F(BrowserTest, WindowOpenClose1) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisablePopupBlocking);
   ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
index e66da11..7f6b4fe 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
@@ -185,8 +185,7 @@
 }
 
 void RecentTabsBuilderTestHelper::ExportToSessionSync(
-    syncer::ModelTypeProcessor* processor,
-    sync_sessions::OpenTabsUIDelegate* verification_delegate) {
+    syncer::ModelTypeProcessor* processor) {
   syncer::UpdateResponseDataList updates;
 
   for (int s = 0; s < GetSessionCount(); ++s) {
@@ -209,11 +208,11 @@
   // ClientTagBasedModelTypeProcessor uses ModelTypeProcessorProxy during
   // activation, which involves task posting for receiving updates.
   base::RunLoop().RunUntilIdle();
-  VerifyExport(verification_delegate);
 }
 
 void RecentTabsBuilderTestHelper::VerifyExport(
     sync_sessions::OpenTabsUIDelegate* delegate) {
+  DCHECK(delegate);
   // Make sure data is populated correctly in SessionModelAssociator.
   std::vector<const sync_sessions::SyncedSession*> sessions;
   ASSERT_TRUE(delegate->GetAllForeignSessions(&sessions));
diff --git a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h
index 08024ff..17cacd5 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h
+++ b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h
@@ -54,9 +54,8 @@
                        int window_index,
                        int tab_index);
 
-  void ExportToSessionSync(
-      syncer::ModelTypeProcessor* processor,
-      sync_sessions::OpenTabsUIDelegate* verification_delegate);
+  void ExportToSessionSync(syncer::ModelTypeProcessor* processor);
+  void VerifyExport(sync_sessions::OpenTabsUIDelegate* delegate);
 
   std::vector<base::string16> GetTabTitlesSortedByRecency();
 
@@ -71,7 +70,6 @@
   syncer::UpdateResponseData BuildUpdateResponseData(
       const sync_pb::SessionSpecifics& specifics,
       base::Time timestamp);
-  void VerifyExport(sync_sessions::OpenTabsUIDelegate* delegate);
 
   struct TabInfo;
   struct WindowInfo;
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index 500ca005..bbd87d6 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -165,11 +165,10 @@
   }
 
   void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) {
-    helper->ExportToSessionSync(
-        sync_processor_.get(),
-        static_cast<sync_sessions::SessionSyncServiceImpl*>(
-            session_sync_service_)
-            ->GetUnderlyingOpenTabsUIDelegateForTest());
+    helper->ExportToSessionSync(sync_processor_.get());
+    helper->VerifyExport(static_cast<sync_sessions::SessionSyncServiceImpl*>(
+                             session_sync_service_)
+                             ->GetUnderlyingOpenTabsUIDelegateForTest());
   }
 
  private:
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 93a8d5d3..8b03bced 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -590,17 +590,15 @@
   views::Widget::Close();
 }
 
-void OverlayWindowViews::Show() {
-#if defined(OS_CHROMEOS)
+void OverlayWindowViews::ShowInactive() {
   views::Widget::ShowInactive();
+#if defined(OS_CHROMEOS)
   // For rounded corners.
   if (ash::features::IsPipRoundedCornersEnabled()) {
     decorator_ = std::make_unique<ash::RoundedCornerDecorator>(
         GetNativeWindow(), GetNativeWindow(), GetRootView()->layer(),
         ash::kPipRoundedCornerRadius);
   }
-#else
-  views::Widget::Show();
 #endif
 
   // If this is not the first time the window is shown, this will be a no-op.
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index 3dc6d17..7f5048b2 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -40,7 +40,7 @@
   // OverlayWindow:
   bool IsActive() const override;
   void Close() override;
-  void Show() override;
+  void ShowInactive() override;
   void Hide() override;
   bool IsVisible() const override;
   bool IsAlwaysOnTop() const override;
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
index 17a7e80..ae9fae4 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
@@ -421,7 +421,7 @@
 }
 
 void LocalDiscoveryUIHandler::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   CheckUserLoggedIn();
 }
 
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
index cd90069..0844fb6 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
@@ -94,7 +94,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
  private:
   using DeviceDescriptionMap =
diff --git a/chrome/browser/ui/webui/management_ui.cc b/chrome/browser/ui/webui/management_ui.cc
index 9820ea7..729f4bdd 100644
--- a/chrome/browser/ui/webui/management_ui.cc
+++ b/chrome/browser/ui/webui/management_ui.cc
@@ -49,6 +49,7 @@
                              IDS_MANAGEMENT_TRUST_ROOTS_NOT_CONFIGURED);
   source->AddLocalizedString("managementDesktopMonitoringNotice",
                              IDS_MANAGEMENT_DESKTOP_MONITORING_NOTICE);
+  source->AddLocalizedString("managementTitle", IDS_MANAGEMENT_TITLE);
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   source->AddLocalizedString(kManagementExtensionReportMachineName,
@@ -81,8 +82,12 @@
 #endif  // defined(OS_CHROMEOS)
   source->SetJsonPath("strings.js");
   // Add required resources.
-  source->AddResourcePath("management.css", IDR_MANAGEMENT_CSS);
-  source->AddResourcePath("management.js", IDR_MANAGEMENT_JS);
+  source->AddResourcePath("management_browser_proxy.html",
+                          IDR_MANAGEMENT_BROWSER_PROXY_HTML);
+  source->AddResourcePath("management_browser_proxy.js",
+                          IDR_MANAGEMENT_BROWSER_PROXY_JS);
+  source->AddResourcePath("management_ui.html", IDR_MANAGEMENT_UI_HTML);
+  source->AddResourcePath("management_ui.js", IDR_MANAGEMENT_UI_JS);
   source->SetDefaultResource(IDR_MANAGEMENT_HTML);
   source->UseGzip();
   return source;
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc
index 5c08bdc7..99c9150 100644
--- a/chrome/browser/ui/webui/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -42,6 +42,7 @@
 #endif  // defined(OS_CHROMEOS)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
@@ -94,12 +95,6 @@
 
 #if defined(OS_CHROMEOS)
 
-base::string16 GetManagementPageTitle() {
-  return l10n_util::GetStringFUTF16(
-      IDS_MANAGEMENT_TITLE,
-      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME));
-}
-
 void AddChromeOSReportingDevice(base::Value* report_sources) {
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
@@ -220,12 +215,11 @@
 #endif  // defined(OS_CHROMEOS)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-
 const char kOnPremReportingExtensionStableId[] =
     "emahakmocgideepebncgnmlmliepgpgb";
 const char kOnPremReportingExtensionBetaId[] =
     "kigjhoekjcpdfjpimbdjegmgecmlicaf";
-const char kCloudReportingExtensionId[] = "empjldejiginopiohodkdoklcjklbaa";
+const char kCloudReportingExtensionId[] = "oempjldejiginopiohodkdoklcjklbaa";
 const char kPolicyKeyReportMachineIdData[] = "report_machine_id_data";
 const char kPolicyKeyReportUserIdData[] = "report_user_id_data";
 const char kPolicyKeyReportVersionData[] = "report_version_data";
@@ -268,11 +262,11 @@
     // Only show extension on page if there is at least one permission
     // message to show.
     if (!permission_messages.empty()) {
-      base::Value extension_to_add(base::Value::Type::DICTIONARY);
-      extension_to_add.SetKey("name", base::Value(extension->name()));
-      extension_to_add.SetKey("permissions",
-                              base::Value(std::move(permission_messages)));
-      powerful_extensions.GetList().push_back(std::move(extension_to_add));
+      std::unique_ptr<base::DictionaryValue> extension_to_add =
+          extensions::util::GetExtensionInfo(extension.get());
+      extension_to_add->SetKey("permissions",
+                               base::Value(std::move(permission_messages)));
+      powerful_extensions.GetList().push_back(std::move(*extension_to_add));
     }
   }
 
@@ -289,18 +283,28 @@
 
 void ManagementUIHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
-      "getManagementTitle",
-      base::BindRepeating(&ManagementUIHandler::HandleGetManagementTitle,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
       "getDeviceManagementStatus",
       base::BindRepeating(&ManagementUIHandler::HandleGetDeviceManagementStatus,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "getExtensions",
+      base::BindRepeating(&ManagementUIHandler::HandleGetExtensions,
+                          base::Unretained(this)));
+#if defined(OS_CHROMEOS)
+  web_ui()->RegisterMessageCallback(
+      "getLocalTrustRootsInfo",
+      base::BindRepeating(&ManagementUIHandler::HandleGetLocalTrustRootsInfo,
+                          base::Unretained(this)));
+#endif  // defined(OS_CHROMEOS)
+  web_ui()->RegisterMessageCallback(
       "getReportingDevice",
       base::BindRepeating(&ManagementUIHandler::HandleGetReportingDevice,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "getReportingInfo",
+      base::BindRepeating(&ManagementUIHandler::HandleGetReportingInfo,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "getReportingSecurity",
       base::BindRepeating(&ManagementUIHandler::HandleGetReportingSecurity,
                           base::Unretained(this)));
@@ -313,229 +317,9 @@
       base::BindRepeating(&ManagementUIHandler::HandleGetReportingWeb,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "getReportingInfo",
-      base::BindRepeating(&ManagementUIHandler::HandleGetReportingInfo,
+      "initBrowserReportingInfo",
+      base::BindRepeating(&ManagementUIHandler::HandleInitBrowserReportingInfo,
                           base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "getBrowserReportingInfo",
-      base::BindRepeating(&ManagementUIHandler::HandleGetBrowserReportingInfo,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "getExtensions",
-      base::BindRepeating(&ManagementUIHandler::HandleGetExtensions,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "getLocalTrustRootsInfo",
-      base::BindRepeating(&ManagementUIHandler::HandleGetLocalTrustRootsInfo,
-                          base::Unretained(this)));
-}
-
-base::string16 ManagementUIHandler::GetEnterpriseManagementStatusString() {
-  auto* profile = Profile::FromWebUI(web_ui());
-  const bool account_managed = IsProfileManaged(profile);
-  const std::string account_domain = GetAccountDomain(profile);
-  bool profile_associated_with_gaia_account = true;
-#if defined(OS_CHROMEOS)
-  profile_associated_with_gaia_account =
-      chromeos::IsProfileAssociatedWithGaiaAccount(profile);
-#endif  // defined(OS_CHROMEOS)
-
-  bool device_managed = false;
-  std::string device_domain;
-#if defined(OS_CHROMEOS)
-  policy::BrowserPolicyConnectorChromeOS* connector =
-      g_browser_process->platform_part()->browser_policy_connector_chromeos();
-  device_managed = connector->IsEnterpriseManaged();
-  if (device_managed)
-    device_domain = connector->GetEnterpriseDisplayDomain();
-  if (device_domain.empty() && connector->IsActiveDirectoryManaged())
-    device_domain = connector->GetRealm();
-#endif  // defined(OS_CHROMEOS)
-
-  bool primary_user_managed = false;
-  std::string primary_user_account_domain;
-#if defined(OS_CHROMEOS)
-  auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
-  if (primary_user) {
-    auto* primary_profile =
-        chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
-    if (primary_profile) {
-      primary_user_managed = IsProfileManaged(primary_profile);
-      primary_user_account_domain = GetAccountDomain(primary_profile);
-    }
-  }
-#endif  // defined(OS_CHROMEOS)
-
-  if (device_managed) {
-    DCHECK(!device_domain.empty());
-    if (account_managed) {
-      if (device_domain == account_domain ||
-          !profile_associated_with_gaia_account) {
-        return l10n_util::GetStringFUTF16(
-            IDS_MANAGEMENT_DEVICE_AND_ACCOUNT_MANAGED_BY,
-            base::UTF8ToUTF16(device_domain));
-      }
-      DCHECK(!account_domain.empty());
-      return l10n_util::GetStringFUTF16(
-          IDS_MANAGEMENT_DEVICE_MANAGED_BY_ACCOUNT_MANAGED_BY,
-          base::UTF8ToUTF16(device_domain), base::UTF8ToUTF16(account_domain));
-    }
-    return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_DEVICE_MANAGED_BY,
-                                      base::UTF8ToUTF16(device_domain));
-  }
-
-  if (account_managed) {
-    return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_ACCOUNT_MANAGED_BY,
-                                      base::UTF8ToUTF16(account_domain));
-  }
-
-  if (primary_user_managed) {
-    return l10n_util::GetStringFUTF16(
-        IDS_MANAGEMENT_ACCOUNT_MANAGED_BY,
-        base::UTF8ToUTF16(primary_user_account_domain));
-  }
-
-  return l10n_util::GetStringUTF16(IDS_MANAGEMENT_DEVICE_NOT_MANAGED);
-}
-
-void ManagementUIHandler::HandleGetManagementTitle(
-    const base::ListValue* args) {
-  AllowJavascript();
-#if defined(OS_CHROMEOS)
-  base::Value title(GetManagementPageTitle());
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */, title);
-#else
-  RejectJavascriptCallback(
-      args->GetList()[0] /* callback_id */,
-      base::Value("No device management title on Chrome desktop"));
-#endif  // defined(OS_CHROMEOS)
-}
-
-void ManagementUIHandler::HandleGetDeviceManagementStatus(
-    const base::ListValue* args) {
-  base::RecordAction(base::UserMetricsAction("ManagementPageViewed"));
-  AllowJavascript();
-  base::Value managed_string(GetEnterpriseManagementStatusString());
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            managed_string);
-}
-
-void ManagementUIHandler::HandleGetReportingDevice(
-    const base::ListValue* args) {
-  base::Value report_sources(base::Value::Type::LIST);
-  AllowJavascript();
-
-// Only Chrome OS devices report status.
-#if defined(OS_CHROMEOS)
-  AddChromeOSReportingDevice(&report_sources);
-#endif  // defined(OS_CHROMEOS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            report_sources);
-}
-
-void ManagementUIHandler::HandleGetReportingSecurity(
-    const base::ListValue* args) {
-  base::Value report_sources(base::Value::Type::LIST);
-  AllowJavascript();
-
-// Only Chrome OS devices report status.
-#if defined(OS_CHROMEOS)
-  AddChromeOSReportingSecurity(&report_sources);
-#endif  // defined(OS_CHROMEOS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            report_sources);
-}
-
-void ManagementUIHandler::HandleGetReportingUserActivity(
-    const base::ListValue* args) {
-  base::Value report_sources(base::Value::Type::LIST);
-  AllowJavascript();
-
-// Only Chrome OS devices report status.
-#if defined(OS_CHROMEOS)
-  AddChromeOSReportingUserActivity(&report_sources);
-#endif  // defined(OS_CHROMEOS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            report_sources);
-}
-
-void ManagementUIHandler::HandleGetReportingWeb(const base::ListValue* args) {
-  base::Value report_sources(base::Value::Type::LIST);
-  AllowJavascript();
-
-// Only Chrome OS devices report status.
-#if defined(OS_CHROMEOS)
-  AddChromeOSReportingWeb(&report_sources);
-#endif  // defined(OS_CHROMEOS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            report_sources);
-}
-
-void ManagementUIHandler::HandleGetReportingInfo(const base::ListValue* args) {
-  base::Value report_sources(base::Value::Type::LIST);
-  AllowJavascript();
-
-// Only Chrome OS devices report status.
-#if defined(OS_CHROMEOS)
-  AddChromeOSReportingInfo(&report_sources);
-#endif  // defined(OS_CHROMEOS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            report_sources);
-}
-
-void ManagementUIHandler::HandleGetBrowserReportingInfo(
-    const base::ListValue* args) {
-  base::Value report_sources(base::Value::Type::LIST);
-  AllowJavascript();
-
-// Only browsers with extensions enabled report status.
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  AddExtensionReportingInfo(&report_sources);
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            report_sources);
-}
-
-void ManagementUIHandler::HandleGetExtensions(const base::ListValue* args) {
-  AllowJavascript();
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  // List of all enabled extensions
-  const extensions::ExtensionSet& extensions =
-      extensions::ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))
-          ->enabled_extensions();
-
-  base::Value powerful_extensions = GetPowerfulExtensions(extensions);
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            powerful_extensions);
-#else
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            base::Value(base::Value::Type::LIST));
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-}
-
-void ManagementUIHandler::HandleGetLocalTrustRootsInfo(
-    const base::ListValue* args) {
-  CHECK_EQ(1U, args->GetSize());
-  base::Value trust_roots_configured(false);
-  AllowJavascript();
-// Only Chrome OS could have installed trusted certificates.
-#if defined(OS_CHROMEOS)
-  policy::PolicyCertService* policy_service =
-      policy::PolicyCertServiceFactory::GetForProfile(
-          Profile::FromWebUI(web_ui()));
-  if (policy_service && policy_service->has_policy_certificates())
-    trust_roots_configured = base::Value(true);
-#endif  // defined(OS_CHROMEOS)
-
-  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
-                            trust_roots_configured);
 }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -617,3 +401,195 @@
   }
 }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+base::string16 ManagementUIHandler::GetEnterpriseManagementStatusString() {
+  auto* profile = Profile::FromWebUI(web_ui());
+  const bool account_managed = IsProfileManaged(profile);
+  const std::string account_domain = GetAccountDomain(profile);
+  bool profile_associated_with_gaia_account = true;
+#if defined(OS_CHROMEOS)
+  profile_associated_with_gaia_account =
+      chromeos::IsProfileAssociatedWithGaiaAccount(profile);
+#endif  // defined(OS_CHROMEOS)
+
+  bool device_managed = false;
+  std::string device_domain;
+#if defined(OS_CHROMEOS)
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+  device_managed = connector->IsEnterpriseManaged();
+  if (device_managed)
+    device_domain = connector->GetEnterpriseDisplayDomain();
+  if (device_domain.empty() && connector->IsActiveDirectoryManaged())
+    device_domain = connector->GetRealm();
+#endif  // defined(OS_CHROMEOS)
+
+  bool primary_user_managed = false;
+  std::string primary_user_account_domain;
+#if defined(OS_CHROMEOS)
+  auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
+  if (primary_user) {
+    auto* primary_profile =
+        chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+    if (primary_profile) {
+      primary_user_managed = IsProfileManaged(primary_profile);
+      primary_user_account_domain = GetAccountDomain(primary_profile);
+    }
+  }
+#endif  // defined(OS_CHROMEOS)
+
+  if (device_managed) {
+    DCHECK(!device_domain.empty());
+    if (account_managed) {
+      if (device_domain == account_domain ||
+          !profile_associated_with_gaia_account) {
+        return l10n_util::GetStringFUTF16(
+            IDS_MANAGEMENT_DEVICE_AND_ACCOUNT_MANAGED_BY,
+            base::UTF8ToUTF16(device_domain));
+      }
+      DCHECK(!account_domain.empty());
+      return l10n_util::GetStringFUTF16(
+          IDS_MANAGEMENT_DEVICE_MANAGED_BY_ACCOUNT_MANAGED_BY,
+          base::UTF8ToUTF16(device_domain), base::UTF8ToUTF16(account_domain));
+    }
+    return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_DEVICE_MANAGED_BY,
+                                      base::UTF8ToUTF16(device_domain));
+  }
+
+  if (account_managed) {
+    return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_ACCOUNT_MANAGED_BY,
+                                      base::UTF8ToUTF16(account_domain));
+  }
+
+  if (primary_user_managed) {
+    return l10n_util::GetStringFUTF16(
+        IDS_MANAGEMENT_ACCOUNT_MANAGED_BY,
+        base::UTF8ToUTF16(primary_user_account_domain));
+  }
+
+  return l10n_util::GetStringUTF16(IDS_MANAGEMENT_DEVICE_NOT_MANAGED);
+}
+
+void ManagementUIHandler::HandleGetDeviceManagementStatus(
+    const base::ListValue* args) {
+  base::RecordAction(base::UserMetricsAction("ManagementPageViewed"));
+  AllowJavascript();
+  base::Value managed_string(GetEnterpriseManagementStatusString());
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            managed_string);
+}
+
+void ManagementUIHandler::HandleGetExtensions(const base::ListValue* args) {
+  AllowJavascript();
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  // List of all enabled extensions
+  const extensions::ExtensionSet& extensions =
+      extensions::ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))
+          ->enabled_extensions();
+
+  base::Value powerful_extensions = GetPowerfulExtensions(extensions);
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            powerful_extensions);
+#else
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            base::Value(base::Value::Type::LIST));
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+}
+
+#if defined(OS_CHROMEOS)
+void ManagementUIHandler::HandleGetLocalTrustRootsInfo(
+    const base::ListValue* args) {
+  CHECK_EQ(1U, args->GetSize());
+  base::Value trust_roots_configured(false);
+  AllowJavascript();
+
+  policy::PolicyCertService* policy_service =
+      policy::PolicyCertServiceFactory::GetForProfile(
+          Profile::FromWebUI(web_ui()));
+  if (policy_service && policy_service->has_policy_certificates())
+    trust_roots_configured = base::Value(true);
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            trust_roots_configured);
+}
+#endif  // defined(OS_CHROMEOS)
+
+void ManagementUIHandler::HandleGetReportingDevice(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+  AllowJavascript();
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingDevice(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingInfo(const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+  AllowJavascript();
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingInfo(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingSecurity(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+  AllowJavascript();
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingSecurity(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingUserActivity(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+  AllowJavascript();
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingUserActivity(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingWeb(const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+  AllowJavascript();
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingWeb(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleInitBrowserReportingInfo(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+  AllowJavascript();
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  AddExtensionReportingInfo(&report_sources);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
diff --git a/chrome/browser/ui/webui/management_ui_handler.h b/chrome/browser/ui/webui/management_ui_handler.h
index d7040dd2..61d9f87d 100644
--- a/chrome/browser/ui/webui/management_ui_handler.h
+++ b/chrome/browser/ui/webui/management_ui_handler.h
@@ -46,31 +46,31 @@
   void RegisterMessages() override;
 
  private:
-  void HandleGetManagementTitle(const base::ListValue* args);
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  void AddExtensionReportingInfo(base::Value* report_sources);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+  base::string16 GetEnterpriseManagementStatusString();
 
   void HandleGetDeviceManagementStatus(const base::ListValue* args);
 
+  void HandleGetExtensions(const base::ListValue* args);
+
+#if defined(OS_CHROMEOS)
+  void HandleGetLocalTrustRootsInfo(const base::ListValue* args);
+#endif  // defined(OS_CHROMEOS)
+
   void HandleGetReportingDevice(const base::ListValue* args);
 
+  void HandleGetReportingInfo(const base::ListValue* args);
+
   void HandleGetReportingSecurity(const base::ListValue* args);
 
   void HandleGetReportingUserActivity(const base::ListValue* args);
 
   void HandleGetReportingWeb(const base::ListValue* args);
 
-  void HandleGetReportingInfo(const base::ListValue* args);
-
-  void HandleGetBrowserReportingInfo(const base::ListValue* args);
-
-  void HandleGetExtensions(const base::ListValue* args);
-
-  void HandleGetLocalTrustRootsInfo(const base::ListValue* args);
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  void AddExtensionReportingInfo(base::Value* report_sources);
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
-  base::string16 GetEnterpriseManagementStatusString();
+  void HandleInitBrowserReportingInfo(const base::ListValue* args);
 
   DISALLOW_COPY_AND_ASSIGN(ManagementUIHandler);
 };
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index c5fe1773..711b5dbb 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -867,7 +867,7 @@
 }
 
 void PeopleHandler::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   UpdateSyncStatus();
 }
 
@@ -928,8 +928,7 @@
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
 
   bool status_has_error =
-      sync_ui_util::GetStatusLabels(profile_, service, identity_manager,
-                                    &status_label, &link_label,
+      sync_ui_util::GetStatusLabels(profile_, &status_label, &link_label,
                                     &action_type) == sync_ui_util::SYNC_ERROR;
   sync_status->SetString("statusText", status_label);
   sync_status->SetString("statusActionText", link_label);
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h
index 1bdb3f4..1708043 100644
--- a/chrome/browser/ui/webui/settings/people_handler.h
+++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -129,7 +129,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   void OnAccountUpdated(const AccountInfo& info) override;
   void OnAccountRemovedWithInfo(const AccountInfo& info) override;
diff --git a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
index 4a2788e..01cb670 100644
--- a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
@@ -250,9 +250,7 @@
   // However, if Sync is in error, clearing cookies should pause it.
   std::unique_ptr<AccountReconcilor::ScopedSyncedDataDeletion>
       scoped_data_deletion;
-  sync_ui_util::MessageType sync_status = sync_ui_util::GetStatus(
-      profile_, sync_service_, IdentityManagerFactory::GetForProfile(profile_));
-  if (sync_status == sync_ui_util::SYNCED) {
+  if (sync_ui_util::GetStatus(profile_) == sync_ui_util::SYNCED) {
     scoped_data_deletion = AccountReconcilorFactory::GetForProfile(profile_)
                                ->GetScopedSyncDataDeletion();
   }
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
index 0f29c6b..a521680b 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h"
 #include "chrome/browser/browsing_data/mock_browsing_data_cookie_helper.h"
 #include "chrome/browser/browsing_data/mock_browsing_data_local_storage_helper.h"
@@ -492,7 +493,13 @@
                   site_settings::SiteSettingSource::kDefault, 3U);
 }
 
-TEST_F(SiteSettingsHandlerTest, GetAllSites) {
+// Flaky on CrOS and Linux. https://crbug.com/930481
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#define MAYBE_GetAllSites DISABLED_GetAllSites
+#else
+#define MAYBE_GetAllSites GetAllSites
+#endif
+TEST_F(SiteSettingsHandlerTest, MAYBE_GetAllSites) {
   base::ListValue get_all_sites_args;
   get_all_sites_args.AppendString(kCallbackId);
   base::Value category_list(base::Value::Type::LIST);
diff --git a/chrome/credential_provider/gaiacp/gaia_credential.cc b/chrome/credential_provider/gaiacp/gaia_credential.cc
index db45610..702f49f 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential.cc
@@ -4,12 +4,7 @@
 
 #include "chrome/credential_provider/gaiacp/gaia_credential.h"
 
-#include <algorithm>
-#include <memory>
-
-#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
-#include "chrome/credential_provider/gaiacp/os_user_manager.h"
 
 namespace credential_provider {
 
@@ -26,14 +21,4 @@
   LOGFN(INFO);
 }
 
-void CGaiaCredential::ResetInternalState() {
-  // Reset sid and username so that the credential can be signed in with
-  // another user in case it was cancelled in the middle of a password change
-  // sign in.
-  set_user_sid(CComBSTR());
-  set_username(CComBSTR());
-
-  CGaiaCredentialBase::ResetInternalState();
-}
-
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gaia_credential.h b/chrome/credential_provider/gaiacp/gaia_credential.h
index 57d78c4..96a8729 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential.h
+++ b/chrome/credential_provider/gaiacp/gaia_credential.h
@@ -34,9 +34,6 @@
   END_COM_MAP()
 
   DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-  // CGaiaCredentialBase
-  void ResetInternalState() override;
 };
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index 942e0ad8..08e095c 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -9,6 +9,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -65,27 +66,34 @@
   return base::string16(&email_domains[0]);
 }
 
-// Choose a suitable username for the given gaia account.  If a username has
-// already been created for this gaia account, the same username is returned.
-// Otherwise a new one is generated, derived from the email.
+// Tries to find a user associated to the gaia_id stored in |result| under the
+// key |kKeyId|. If one exists, then this function will fill out |gaia_id|,
+// |username| and |sid| with the user's information. If not
+// this function will try to generate a new username derived from the email
+// and fill out only |gaia_id| and |username|. |sid| will be empty until the
+// user is created later on.
 void MakeUsernameForAccount(const base::DictionaryValue* result,
+                            base::string16* gaia_id,
                             wchar_t* username,
-                            DWORD length) {
+                            DWORD username_length,
+                            wchar_t* sid,
+                            DWORD sid_length) {
+  DCHECK(gaia_id);
+  DCHECK(username);
+  DCHECK(sid);
+
+  *gaia_id = GetDictString(result, kKeyId);
   // First try to detect if this gaia account has been used to create an OS
   // user already.  If so, return the OS username of that user.
-  wchar_t sid[128];
-  HRESULT hr =
-      GetSidFromId(GetDictString(result, kKeyId), sid, base::size(sid));
+  HRESULT hr = GetSidFromId(*gaia_id, sid, sid_length);
   if (SUCCEEDED(hr)) {
-    hr = OSUserManager::Get()->FindUserBySID(sid, username, length);
+    hr = OSUserManager::Get()->FindUserBySID(sid, username, username_length);
     if (SUCCEEDED(hr))
       return;
-
-    LOGFN(INFO) << "FindUserBySID hr=" << putHR(hr);
-  } else {
-    LOGFN(INFO) << "GetSidFromId: id not found";
   }
-
+  LOGFN(INFO) << "No existing user found associated to gaia id:" << *gaia_id;
+  username[0] = 0;
+  sid[0] = 0;
   // Create a username based on the email address.  Usernames are more
   // restrictive than emails, so some transformations are needed.  This tries
   // to preserve the email as much as possible in the username while respecting
@@ -130,7 +138,7 @@
       c = L'_';
   }
 
-  wcscpy_s(username, length, os_username.c_str());
+  wcscpy_s(username, username_length, os_username.c_str());
 }
 
 // Waits for the login UI to completes and returns the result of the operation.
@@ -334,6 +342,80 @@
   return S_OK;
 }
 
+// Creates a new windows OS user with the given |base_username|, |fullname| and
+// |password| on the local machine.  Returns the SID of the new user.
+// If a user with |base_username| already exists, the function will try to
+// generate a new indexed username up to |max_attempts| before failing.
+// The actual username used for the new user will be filled in |final_username|
+// if successful.
+HRESULT CreateNewUser(OSUserManager* manager,
+                      const wchar_t* base_username,
+                      const wchar_t* password,
+                      const wchar_t* fullname,
+                      const wchar_t* comment,
+                      bool add_to_users_group,
+                      int max_attempts,
+                      BSTR* final_username,
+                      BSTR* sid) {
+  DCHECK(manager);
+  DCHECK(base_username);
+  DCHECK(password);
+  DCHECK(fullname);
+  DCHECK(comment);
+  DCHECK(final_username);
+  DCHECK(sid);
+  wchar_t new_username[kWindowsUsernameBufferLength];
+  errno_t err = wcscpy_s(new_username, base::size(new_username), base_username);
+  if (err != 0) {
+    LOGFN(ERROR) << "wcscpy_s errno=" << err;
+    return E_FAIL;
+  }
+
+  // Keep trying to create the user account until an unused username can be
+  // found or |max_attempts| has been reached.
+  for (int i = 0; i < max_attempts; ++i) {
+    CComBSTR new_sid;
+    DWORD error;
+    HRESULT hr = manager->AddUser(new_username, password, fullname, comment,
+                                  add_to_users_group, &new_sid, &error);
+    if (hr == HRESULT_FROM_WIN32(NERR_UserExists)) {
+      base::string16 next_username = base_username;
+      base::string16 next_username_suffix =
+          base::NumberToString16(i + kInitialDuplicateUsernameIndex);
+      // Create a new user name that fits in |kWindowsUsernameBufferLength|
+      if (next_username.size() + next_username_suffix.size() >
+          (kWindowsUsernameBufferLength - 1)) {
+        next_username =
+            next_username.substr(0, (kWindowsUsernameBufferLength - 1) -
+                                        next_username_suffix.size()) +
+            next_username_suffix;
+      } else {
+        next_username += next_username_suffix;
+      }
+      LOGFN(INFO) << "Username '" << new_username
+                  << "' already exists. Trying '" << next_username << "'";
+
+      errno_t err = wcscpy_s(new_username, base::size(new_username),
+                             next_username.c_str());
+      if (err != 0) {
+        LOGFN(ERROR) << "wcscpy_s errno=" << err;
+        return E_FAIL;
+      }
+
+      continue;
+    } else if (FAILED(hr)) {
+      LOGFN(ERROR) << "manager->AddUser hr=" << putHR(hr);
+      return hr;
+    }
+
+    *sid = ::SysAllocString(new_sid);
+    *final_username = ::SysAllocString(new_username);
+    return S_OK;
+  }
+
+  return HRESULT_FROM_WIN32(NERR_UserExists);
+}
+
 }  // namespace
 
 CGaiaCredentialBase::UIProcessInfo::UIProcessInfo() {}
@@ -400,60 +482,41 @@
       return hr;
     }
 
-    constexpr int kMaxAttempts = 10;
-
+    CComBSTR sid_string;
+    CComBSTR gaia_username;
     // Keep trying to create the special Gaia account used to run the UI until
-    // an unused username can be found or kMaxAttempts has been reached.
-    for (int i = 0; sid == nullptr && i < kMaxAttempts; ++i) {
-      CComBSTR sid_string;
-      base::string16 fullname(
-          GetStringResource(IDS_GAIA_ACCOUNT_FULLNAME_BASE));
-      base::string16 comment(GetStringResource(IDS_GAIA_ACCOUNT_COMMENT_BASE));
-      hr = CreateNewUser(manager, gaia_username, password, fullname.c_str(),
-                         comment.c_str(), /*add_to_users_group=*/false,
-                         &sid_string);
-      if (hr == HRESULT_FROM_WIN32(NERR_UserExists)) {
-        base::string16 next_username = kDefaultGaiaAccountName;
-        next_username += base::NumberToString16(i);
-        LOGFN(INFO) << "Username '" << gaia_username
-                    << "' already exists. Trying '" << next_username << "'";
+    // an unused username can be found or kMaxUsernameAttempts has been reached.
+    hr =
+        CreateNewUser(manager, kDefaultGaiaAccountName, password,
+                      GetStringResource(IDS_GAIA_ACCOUNT_FULLNAME_BASE).c_str(),
+                      GetStringResource(IDS_GAIA_ACCOUNT_COMMENT_BASE).c_str(),
+                      /*add_to_users_group=*/false, kMaxUsernameAttempts,
+                      &gaia_username, &sid_string);
 
-        errno_t err = wcscpy_s(gaia_username, base::size(gaia_username),
-                               next_username.c_str());
-        if (err != 0) {
-          LOGFN(ERROR) << "wcscpy_s errno=" << err;
-          return E_FAIL;
-        }
+    if (FAILED(hr)) {
+      LOGFN(ERROR) << "CreateNewUser hr=" << putHR(hr);
+      return hr;
+    }
 
-        continue;
-      } else if (FAILED(hr)) {
-        LOGFN(ERROR) << "CreateNewUser hr=" << putHR(hr);
-        return hr;
-      }
+    if (!::ConvertStringSidToSid(sid_string, &sid)) {
+      hr = HRESULT_FROM_WIN32(::GetLastError());
+      LOGFN(ERROR) << "ConvertStringSidToSid hr=" << putHR(hr);
+      return hr;
+    }
 
-      // Save the password in a machine secret area.
-      hr = policy->StorePrivateData(kLsaKeyGaiaPassword, password);
-      if (FAILED(hr)) {
-        LOGFN(ERROR) << "Failed to store gaia user password in LSA hr="
-                     << putHR(hr);
-        return hr;
-      }
+    // Save the password in a machine secret area.
+    hr = policy->StorePrivateData(kLsaKeyGaiaPassword, password);
+    if (FAILED(hr)) {
+      LOGFN(ERROR) << "Failed to store gaia user password in LSA hr="
+                   << putHR(hr);
+      return hr;
+    }
 
-      if (!::ConvertStringSidToSid(sid_string, &sid)) {
-        hr = HRESULT_FROM_WIN32(::GetLastError());
-        LOGFN(ERROR) << "ConvertStringSidToSid hr=" << putHR(hr);
-        return hr;
-      }
-
-      // Save the gaia username in a machine secret area.
-      hr = policy->StorePrivateData(kLsaKeyGaiaUsername, gaia_username);
-      if (FAILED(hr)) {
-        LOGFN(ERROR) << "Failed to store gaia user name in LSA hr="
-                     << putHR(hr);
-        return hr;
-      }
-
-      break;
+    // Save the gaia username in a machine secret area.
+    hr = policy->StorePrivateData(kLsaKeyGaiaUsername, gaia_username);
+    if (FAILED(hr)) {
+      LOGFN(ERROR) << "Failed to store gaia user name in LSA hr=" << putHR(hr);
+      return hr;
     }
   }
 
@@ -563,10 +626,7 @@
       break;
     }
     case FID_PROVIDER_LABEL: {
-      UINT label_resource_id = IDS_AUTH_FID_PROVIDER_LABEL_BASE;
-      if (user_sid_.Length())
-        label_resource_id = IDS_EXISTING_AUTH_FID_PROVIDER_LABEL_BASE;
-      base::string16 label(GetStringResource(label_resource_id));
+      base::string16 label(GetStringResource(IDS_AUTH_FID_PROVIDER_LABEL_BASE));
       hr = ::SHStrDupW(label.c_str(), value);
       break;
     }
@@ -586,46 +646,27 @@
 
 void CGaiaCredentialBase::ResetInternalState() {
   LOGFN(INFO);
+  username_.Empty();
   password_.Empty();
   current_windows_password_.Empty();
   authentication_results_.reset();
   needs_to_update_windows_password_ = false;
   needs_windows_password_ = false;
 
-  // Don't reset user_sid_ or username_ as those are set for existing gaia
-  // users in CReauthCredential::SetGaiaUserInfo so that the user account
-  // matching the email can always be found for that credential even when the
-  // user cancels signin. These two members are reset in CGaiaCredential to
-  // allow changing between different users when cancelling signin on an
-  // unknown gaia user.
   TerminateLogonProcess();
 
   if (events_) {
     wchar_t* default_status_text = nullptr;
     GetStringValue(FID_DESCRIPTION, &default_status_text);
-    events_->SetFieldState(this, FID_DESCRIPTION,
-                           CPFS_DISPLAY_IN_SELECTED_TILE);
     events_->SetFieldString(this, FID_DESCRIPTION, default_status_text);
     events_->SetFieldState(this, FID_CURRENT_PASSWORD_FIELD, CPFS_HIDDEN);
     events_->SetFieldString(this, FID_CURRENT_PASSWORD_FIELD,
                             current_windows_password_);
-    events_->SetFieldState(this, FID_SUBMIT, CPFS_DISPLAY_IN_SELECTED_TILE);
     events_->SetFieldSubmitButton(this, FID_SUBMIT, FID_DESCRIPTION);
     UpdateSubmitButtonInteractiveState();
   }
 }
 
-HRESULT CGaiaCredentialBase::GetEmailForReauth(wchar_t* email, size_t length) {
-  if (email == nullptr)
-    return E_POINTER;
-
-  if (length < 1)
-    return E_INVALIDARG;
-
-  email[0] = 0;
-  return S_OK;
-}
-
 HRESULT CGaiaCredentialBase::GetBaseGlsCommandline(
     base::CommandLine* command_line) {
   DCHECK(command_line);
@@ -675,33 +716,29 @@
   return S_OK;
 }
 
-HRESULT CGaiaCredentialBase::GetGlsCommandline(
-    const wchar_t* email,
+HRESULT CGaiaCredentialBase::GetUserGlsCommandline(
     base::CommandLine* command_line) {
-  DCHECK(email);
+  return S_OK;
+}
+
+HRESULT CGaiaCredentialBase::GetGlsCommandline(
+    base::CommandLine* command_line) {
   HRESULT hr = GetBaseGlsCommandline(command_line);
   if (FAILED(hr)) {
     LOGFN(ERROR) << "GetBaseGlsCommandline hr=" << putHR(hr);
     return hr;
   }
 
-  command_line->AppendSwitchNative(kPrefillEmailSwitch, email);
-
-  // If an email pattern is specified, pass it to the GLS.
+  // If email domains are specified, pass them to the GLS.
   base::string16 email_domains = GetEmailDomains();
   if (email_domains[0])
     command_line->AppendSwitchNative(kEmailDomainsSwitch, email_domains);
 
-  // If this is an existing user with an SID, try to get its gaia id and pass
-  // it to the GLS for verification.
-  if (user_sid_.Length()) {
-    LOGFN(INFO) << "Existing user sid: " << user_sid_;
-    base::string16 gaia_id;
-    if (GetIdFromSid(OLE2CW(user_sid_), &gaia_id) == S_OK)
-      command_line->AppendSwitchNative(kGaiaIdSwitch, gaia_id);
-    LOGFN(INFO) << "Existing user gaia id: " << gaia_id;
+  hr = GetUserGlsCommandline(command_line);
+  if (FAILED(hr)) {
+    LOGFN(ERROR) << "GetBaseGlsCommandline hr=" << putHR(hr);
+    return hr;
   }
-
   LOGFN(INFO) << "Command line: " << command_line->GetCommandLineString();
   return S_OK;
 }
@@ -805,21 +842,6 @@
 }
 
 // static
-HRESULT CGaiaCredentialBase::CreateNewUser(OSUserManager* manager,
-                                           const wchar_t* username,
-                                           const wchar_t* password,
-                                           const wchar_t* fullname,
-                                           const wchar_t* comment,
-                                           bool add_to_users_group,
-                                           BSTR* sid) {
-  DWORD error;
-  HRESULT hr = manager->AddUser(username, password, fullname, comment,
-                                add_to_users_group, sid, &error);
-  LOGFN(INFO) << "hr=" << putHR(hr) << " username=" << username;
-  return hr;
-}
-
-// static
 BSTR CGaiaCredentialBase::AllocErrorString(UINT id) {
   CComBSTR str(GetStringResource(id).c_str());
   return str.Detach();
@@ -868,11 +890,11 @@
   LOGFN(INFO);
 
   // Cancel logon so that the next time this credential is clicked everything
-  // has to be re-entered by the user. This prevents a Windows password entered
-  // into the password field by the user from being persisted too long. The
-  // behaviour is similar to that of the normal windows password text box.
-  // Whenever a different user is selected and then the original credential
-  // is selected again, the password is cleared.
+  // has to be re-entered by the user. This prevents a Windows password
+  // entered into the password field by the user from being persisted too
+  // long. The behaviour is similar to that of the normal windows password
+  // text box. Whenever a different user is selected and then the original
+  // credential is selected again, the password is cleared.
   ResetInternalState();
 
   return S_OK;
@@ -974,7 +996,6 @@
                                             const wchar_t* psz) {
   USES_CONVERSION;
 
-  // No editable strings.
   HRESULT hr = E_INVALIDARG;
   switch (field_id) {
     case FID_CURRENT_PASSWORD_FIELD:
@@ -1017,7 +1038,8 @@
   *status_text = nullptr;
   *status_icon = CPSI_NONE;
 
-  // This may be a long running function so disable user input while processing.
+  // This may be a long running function so disable user input while
+  // processing.
   if (events_) {
     events_->SetFieldInteractiveState(this, FID_SUBMIT, CPFIS_DISABLED);
     events_->SetFieldInteractiveState(this, FID_CURRENT_PASSWORD_FIELD,
@@ -1036,10 +1058,10 @@
     *status_icon = CPSI_ERROR;
     *cpgsr = CPGSR_RETURN_NO_CREDENTIAL_FINISHED;
   } else if (hr == S_FALSE) {
-    // If HandleAutologon returns S_FALSE, then there was not enough information
-    // to log the user on or they need to update their password and gave an
-    // invalid old password.  Display the Gaia sign in page if there is not
-    // sufficient Gaia credentials or just return
+    // If HandleAutologon returns S_FALSE, then there was not enough
+    // information to log the user on or they need to update their password
+    // and gave an invalid old password.  Display the Gaia sign in page if
+    // there is not sufficient Gaia credentials or just return
     // CPGSR_NO_CREDENTIAL_NOT_FINISHED to wait for the user to try a new
     // password.
 
@@ -1104,15 +1126,8 @@
 HRESULT CGaiaCredentialBase::CreateAndRunLogonStub() {
   LOGFN(INFO);
 
-  wchar_t email[64];
-  HRESULT hr = GetEmailForReauth(email, base::size(email));
-  if (FAILED(hr)) {
-    LOGFN(ERROR) << "GetEmailForReauth hr=" << putHR(hr);
-    return hr;
-  }
-
   base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
-  hr = GetGlsCommandline(email, &command_line);
+  HRESULT hr = GetGlsCommandline(&command_line);
   if (FAILED(hr)) {
     LOGFN(ERROR) << "GetGlsCommandline hr=" << putHR(hr);
     return hr;
@@ -1152,15 +1167,17 @@
 
   // Background thread takes ownership of |uiprocinfo|.
   unsigned int wait_thread_id;
-  uintptr_t wait_thread = _beginthreadex(
-      nullptr, 0, WaitForLoginUI, uiprocinfo.release(), 0, &wait_thread_id);
+  UIProcessInfo* puiprocinfo = uiprocinfo.release();
+  uintptr_t wait_thread = _beginthreadex(nullptr, 0, WaitForLoginUI,
+                                         puiprocinfo, 0, &wait_thread_id);
   if (wait_thread != 0) {
     LOGFN(INFO) << "Started wait thread id=" << wait_thread_id;
     ::CloseHandle((HANDLE)wait_thread);
   } else {
     HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
     LOGFN(ERROR) << "Unable to start wait thread hr=" << putHR(hr);
-    ::TerminateProcess(uiprocinfo->procinfo.process_handle(), kUiecKilled);
+    ::TerminateProcess(puiprocinfo->procinfo.process_handle(), kUiecKilled);
+    delete puiprocinfo;
     return hr;
   }
 
@@ -1267,8 +1284,8 @@
 
   // Don't create a job here with UI restrictions, since win10 does not allow
   // nested jobs unless all jobs don't specify UI restrictions.  Since chrome
-  // will set a job with UI restrictions for renderer/gpu/etc processes, setting
-  // one here causes chrome to fail.
+  // will set a job with UI restrictions for renderer/gpu/etc processes,
+  // setting one here causes chrome to fail.
 
   // Environment is fully set up for UI, so let it go.
   if (::ResumeThread(uiprocinfo->procinfo.thread_handle()) ==
@@ -1283,10 +1300,10 @@
   // a handle to it.  Otherwise, the desktop will be destroyed and the process
   // will fail to start.
   //
-  // WaitForInputIdle() return immediately with an error if the process created
-  // is a console app.  In production this will not be the case, however in
-  // tests this may happen.  However, tests are not concerned with the
-  // destruction of the desktop since one is not created.
+  // WaitForInputIdle() return immediately with an error if the process
+  // created is a console app.  In production this will not be the case,
+  // however in tests this may happen.  However, tests are not concerned with
+  // the destruction of the desktop since one is not created.
   DWORD ret = ::WaitForInputIdle(uiprocinfo->procinfo.process_handle(), 10000);
   if (ret != 0)
     LOGFN(INFO) << "WaitForInputIdle, ret=" << ret;
@@ -1449,9 +1466,13 @@
               << " substatus=" << putHR(substatus);
 
   if (status == STATUS_SUCCESS && authentication_results_) {
-    // Update the password in |authentication_results_| with the real Windows
-    // password for the user so that the SaveAccountInfo process can correctly
-    // sign in to the user account.
+    // Update the sid, username and password in |authentication_results_| with
+    // the real Windows information for the user so that the SaveAccountInfo
+    // process can correctly sign in to the user account.
+    authentication_results_->SetKey(
+        kKeySID, base::Value(base::UTF16ToUTF8((BSTR)user_sid_)));
+    authentication_results_->SetKey(
+        kKeyUsername, base::Value(base::UTF16ToUTF8((BSTR)username_)));
     authentication_results_->SetKey(
         kKeyPassword, base::Value(base::UTF16ToUTF8((BSTR)password_)));
 
@@ -1470,15 +1491,8 @@
 }
 
 HRESULT CGaiaCredentialBase::GetUserSid(wchar_t** sid) {
-  USES_CONVERSION;
-  DCHECK(sid);
-  LOGFN(INFO) << "sid=" << OLE2CW(user_sid_);
-
-  HRESULT hr = ::SHStrDupW(OLE2CW(user_sid_), sid);
-  if (FAILED(hr))
-    LOGFN(ERROR) << "SHStrDupW hr=" << putHR(hr);
-
-  return hr;
+  *sid = nullptr;
+  return S_FALSE;
 }
 
 HRESULT CGaiaCredentialBase::Initialize(IGaiaCredentialProvider* provider) {
@@ -1506,103 +1520,63 @@
   }
 }
 
-HRESULT CGaiaCredentialBase::ValidateOrCreateUser(BSTR username,
-                                                  BSTR password,
-                                                  BSTR fullname,
-                                                  BSTR* sid,
-                                                  BSTR* error_text) {
-  USES_CONVERSION;
-
+HRESULT CGaiaCredentialBase::ValidateOrCreateUser(
+    const base::DictionaryValue* result,
+    BSTR* username,
+    BSTR* password,
+    BSTR* sid,
+    BSTR* error_text) {
   LOGFN(INFO);
+  DCHECK(username);
+  DCHECK(password);
+  DCHECK(sid);
   DCHECK(error_text);
   DCHECK(sid);
 
   *error_text = nullptr;
+  base::string16 local_password = GetDictString(result, kKeyPassword);
 
-  // Check if the user exists and if the passwords match.
-  OSUserManager* manager = OSUserManager::Get();
-  HRESULT checkpassword_hr =
-      manager->IsWindowsPasswordValid(username, password);
-  // If result is S_OK (0) then the user exists and the current Gaia password
-  // given is the same as the Windows password.
-  // If result is S_FALSE (1) then the user exists but the current password
-  // given through Gaia does not match the Windows password.
-  if (SUCCEEDED(checkpassword_hr)) {
-    // Make sure the user name that was already set matches the one that is
-    // found.
-    if (username_.Length() > 0 && username_ != username) {
-      LOGFN(ERROR) << "Username found '" << username << "' does not match the "
-                   << "username that is set '" << username_ << "'";
-      *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
-      return E_UNEXPECTED;
-    }
+  wchar_t found_username[kWindowsUsernameBufferLength];
+  wchar_t found_sid[kWindowsSidBufferLength];
+  base::string16 gaia_id;
+  MakeUsernameForAccount(result, &gaia_id, found_username,
+                         base::size(found_username), found_sid,
+                         base::size(found_sid));
 
-    // A return of S_FALSE means the passwords do not match, log it here and
-    // continue.
-    if (checkpassword_hr == S_FALSE)
-      LOGFN(INFO) << "User password has changed for=" << username;
+  // If an existing user associated to the gaia id was found, make sure that
+  // it is valid for this credential.
+  if (found_sid[0]) {
+    HRESULT hr = ValidateExistingUser(found_username, found_sid, error_text);
 
-    PSID found_sid;
-    HRESULT hr = manager->GetUserSID(username, &found_sid);
     if (FAILED(hr)) {
-      LOGFN(ERROR) << "Failed find SID for existing user with username '"
-                   << username << "' hr=" << putHR(hr);
-      *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
-      return E_UNEXPECTED;
+      LOGFN(ERROR) << "ValidateExistingUser hr=" << putHR(hr);
+      return hr;
     }
 
-    wchar_t* sid_string;
-    if (::ConvertSidToStringSid(found_sid, &sid_string)) {
-      BSTR found_sid = ::SysAllocString(W2OLE(sid_string));
-      ::LocalFree(sid_string);
+    *username = ::SysAllocString(found_username);
+    *password = ::SysAllocString(local_password.c_str());
+    *sid = ::SysAllocString(found_sid);
 
-      // If an SID is present for this credential, it must match the one that
-      // was found.
-      if (user_sid_.Length() > 0 && user_sid_ != found_sid) {
-        LOGFN(ERROR) << "SID found '" << found_sid << "' does not match the "
-                     << "username that is set '" << user_sid_ << "'";
-        *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
-        return E_UNEXPECTED;
-      } else {
-        *sid = found_sid;
-      }
-    } else {
-      checkpassword_hr = HRESULT_FROM_WIN32(::GetLastError());
-    }
-    ::LocalFree(found_sid);
-
-    return checkpassword_hr;
+    return S_OK;
   }
 
-  // The only other error that is accepted is NERR_UserNotFound which means a
-  // new user needs to be added.
-  if (checkpassword_hr != HRESULT_FROM_WIN32(NERR_UserNotFound)) {
-    LOGFN(ERROR) << "Unable to check password for '" << username
-                 << "' hr=" << putHR(checkpassword_hr);
-    *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
-    return checkpassword_hr;
-  }
-
-  // Fail if a user_sid_ or username_ was specified but no user was found. This
-  // should not happen.
-  if (user_sid_.Length() || username_.Length()) {
-    LOGFN(ERROR) << "Failed to find existing user '" << username << "'";
-    *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
-    return E_UNEXPECTED;
-  }
-
+  base::string16 local_fullname = GetDictString(result, kKeyFullname);
   base::string16 comment(GetStringResource(IDS_USER_ACCOUNT_COMMENT_BASE));
-  HRESULT hr = CreateNewUser(OSUserManager::Get(), OLE2CW(username),
-                             OLE2CW(password), OLE2CW(fullname),
-                             comment.c_str(), /*add_to_users_group=*/true, sid);
+  HRESULT hr = CreateNewUser(
+      OSUserManager::Get(), found_username, local_password.c_str(),
+      local_fullname.c_str(), comment.c_str(),
+      /*add_to_users_group=*/true, kMaxUsernameAttempts, username, sid);
 
-  DCHECK_NE(hr, HRESULT_FROM_WIN32(NERR_UserExists));
-  if (FAILED(hr)) {
-    LOGFN(ERROR) << "CreateNewUser hr=" << putHR(hr)
-                 << " account=" << OLE2CW(username);
+  // May return user exists if this is the anonymous credential and the
+  // maximum attempts to generate a new username has been reached.
+  if (hr == HRESULT_FROM_WIN32(NERR_UserExists)) {
+    LOGFN(ERROR) << "Could not find a new username based on desired username '"
+                 << found_username << "'. Maximum attempts reached.";
     *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
+    return hr;
   }
 
+  *password = ::SysAllocString(local_password.c_str());
   return hr;
 }
 
@@ -1611,9 +1585,9 @@
   USES_CONVERSION;
   DCHECK(status_text);
 
-  // Logon UI process is no longer needed and should already be finished by now
-  // so clear the handle so that calls to HandleAutoLogon do not block further
-  // processing thinking that there is still a logon process active.
+  // Logon UI process is no longer needed and should already be finished by
+  // now so clear the handle so that calls to HandleAutoLogon do not block
+  // further processing thinking that there is still a logon process active.
   logon_ui_process_ = INVALID_HANDLE_VALUE;
 
   // Convert the string to a base::Dictionary and add the calculated username
@@ -1637,33 +1611,21 @@
     LOGFN(ERROR) << "ValidateResult hr=" << putHR(hr);
     return hr;
   }
-
-  wchar_t username[kWindowsUsernameBufferLength];
-  MakeUsernameForAccount(dict.get(), username, base::size(username));
-
-  dict->SetString(kKeyUsername, username);
-
-  // From this point the code assume the dictionary |dict| is valid.
-  base::string16 new_username = GetDictString(dict, kKeyUsername);
-  base::string16 password = GetDictString(dict, kKeyPassword);
-
-  CComBSTR sid;
-  hr = ValidateOrCreateUser(
-      CComBSTR(W2COLE(new_username.c_str())),
-      CComBSTR(W2COLE(password.c_str())),
-      CComBSTR(W2COLE(GetDictString(dict, kKeyFullname).c_str())), &sid,
-      status_text);
+  // The value in |dict| is now known to contain everything that is needed
+  // from the GLS. Try to validate the user that wants to sign in and then
+  // add additional information into |dict| as needed.
+  hr = ValidateOrCreateUser(dict.get(), &username_, &password_, &user_sid_,
+                            status_text);
   if (FAILED(hr)) {
     LOGFN(ERROR) << "ValidateOrCreateUser hr=" << putHR(hr);
     return hr;
   }
 
-  // user_sid_ should have been verified to match or is empty in call to
-  // ValidateOrCreateUser.
-  DCHECK(user_sid_.Length() == 0 || user_sid_ == sid);
+  authentication_results_ = std::move(dict);
 
-  dict->SetString(kKeyUsername, new_username);
-  dict->SetString(kKeySID, OLE2CA(sid));
+  result_status_ = STATUS_SUCCESS;
+  result_substatus_ = STATUS_SUCCESS;
+  result_status_text_.clear();
 
   // Disable the submit button. Either the signon will succeed with the given
   // credentials or a password update will be needed and that flow will handle
@@ -1672,29 +1634,20 @@
     events_->SetFieldInteractiveState(this, FID_SUBMIT, CPFIS_DISABLED);
 
   // Check if the credentials are valid for the user. If they aren't show the
-  // password update prompt and continue without authenticating on the provider.
-  bool password_stale = hr == S_FALSE;
-  if (password_stale) {
+  // password update prompt and continue without authenticating on the
+  // provider.
+  if (!AreCredentialsValid()) {
     needs_to_update_windows_password_ = true;
     DisplayPasswordField(IDS_PASSWORD_UPDATE_NEEDED_BASE);
+    return S_FALSE;
   }
 
-  username_ = new_username.c_str();
-  password_ = password.c_str();
-  user_sid_ = sid;
-  authentication_results_ = std::move(dict);
-
-  result_status_ = STATUS_SUCCESS;
-  result_substatus_ = STATUS_SUCCESS;
-  result_status_text_.clear();
-
   // When this function returns, winlogon will be told to logon to the newly
   // created account.  This is important, as the save account info process
   // can't actually save the info until the user's profile is created, which
   // happens on first logon.
   return provider_->OnUserAuthenticated(static_cast<IGaiaCredential*>(this),
-                                        username_, password_, sid,
-                                        password_stale ? FALSE : TRUE);
+                                        username_, password_, user_sid_, TRUE);
 }
 
 HRESULT CGaiaCredentialBase::ReportError(LONG status,
@@ -1749,4 +1702,11 @@
   }
 }
 
+HRESULT CGaiaCredentialBase::ValidateExistingUser(
+    const base::string16& username,
+    const base::string16& sid,
+    BSTR* error_text) {
+  return S_OK;
+}
+
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.h b/chrome/credential_provider/gaiacp/gaia_credential_base.h
index 3282222..787e302 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.h
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.h
@@ -25,7 +25,6 @@
 namespace credential_provider {
 
 class OSProcessManager;
-class OSUserManager;
 
 enum FIELDID {
   FID_DESCRIPTION,
@@ -75,16 +74,6 @@
   CGaiaCredentialBase();
   ~CGaiaCredentialBase();
 
-  // Creates a new windows OS user with the given username, fullname, and
-  // password on the local machine.  Returns the SID of the new user.
-  static HRESULT CreateNewUser(OSUserManager* manager,
-                               const wchar_t* username,
-                               const wchar_t* password,
-                               const wchar_t* fullname,
-                               const wchar_t* comment,
-                               bool add_to_users_group,
-                               BSTR* sid);
-
   // Members to access user credentials.
   const CComBSTR& get_username() const { return username_; }
   const CComBSTR& get_password() const { return password_; }
@@ -129,11 +118,7 @@
                              BSTR status_text) override;
 
   // Gets the string value for the given credential UI field.
-  HRESULT GetStringValueImpl(DWORD field_id, wchar_t** value);
-
-  // Derived classes should implement this function to return an email address
-  // only when reauthenticating the user.
-  virtual HRESULT GetEmailForReauth(wchar_t* email, size_t length);
+  virtual HRESULT GetStringValueImpl(DWORD field_id, wchar_t** value);
 
   // Resets the state of the credential, forgetting any username or password
   // that may have been set previously.  Derived classes may override to
@@ -141,23 +126,33 @@
   // class method.
   virtual void ResetInternalState();
 
+  // Gets the base portion of the command line to run the Gaia Logon stub.
+  // This portion of the command line would only include the executable and
+  // any executable specific arguments needed to correctly start the GLS.
+  virtual HRESULT GetBaseGlsCommandline(base::CommandLine* command_line);
+
+  // Gets the user specific portion of the command line to run the Gaia Logon
+  // stub. This portion of the command line could include additional information
+  // such as the user's email and their gaia id.
+  virtual HRESULT GetUserGlsCommandline(base::CommandLine* command_line);
+
   // Display error message to the user.  Virtual so that tests can override.
   virtual void DisplayErrorInUI(LONG status, LONG substatus, BSTR status_text);
 
+  // Forks a stub process to save account information for a user.
+  virtual HRESULT ForkSaveAccountInfoStub(
+      const std::unique_ptr<base::DictionaryValue>& dict,
+      BSTR* status_text);
+
   // Forks the logon stub process and waits for it to start.
   virtual HRESULT ForkGaiaLogonStub(OSProcessManager* process_manager,
                                     const base::CommandLine& command_line,
                                     UIProcessInfo* uiprocinfo);
 
  private:
-  // Gets the base portion of the command line to run the Gaia Logon stub.
-  // This portion of the command line would only include the executable and
-  // any executable specific arguments needed to correctly start the GLS.
-  virtual HRESULT GetBaseGlsCommandline(base::CommandLine* command_line);
   // Gets the full command line to run the Gaia Logon stub (GLS). This
   // function calls GetBaseGlsCommandline.
-  HRESULT GetGlsCommandline(const wchar_t* email,
-                            base::CommandLine* command_line);
+  HRESULT GetGlsCommandline(base::CommandLine* command_line);
 
   // Called from GetSerialization() to handle auto-logon.  If the credential
   // has enough information in internal state to auto-logon, the two arguments
@@ -180,11 +175,6 @@
   static HRESULT CreateGaiaLogonToken(base::win::ScopedHandle* token,
                                       PSID* sid);
 
-  // Forks a stub process to save account information for a user.
-  static HRESULT ForkSaveAccountInfoStub(
-      const std::unique_ptr<base::DictionaryValue>& dict,
-      BSTR* status_text);
-
   // The param is a pointer to a UIProcessInfo struct.  This function must
   // release the memory for this structure using delete operator.
   static unsigned __stdcall WaitForLoginUI(void* param);
@@ -241,21 +231,26 @@
   // switches credentials in the middle of a sign in through the GLS.
   void TerminateLogonProcess();
 
-  // Checks if the information for the given |username| is valid and creates it
-  // if it does not exist.
-  // Returns S_OK if the user exists and the given |password| is a valid windows
-  // login password for the user or if the user does not exist and it was
-  // created successfully.
-  // Returns S_FALSE if the user exists but the given |password| is not the
-  // right password to signin to the Windows account. Otherwise an error result
-  // depending on the failure. On failure |error_text| will be allocated and
-  // filled with an error message. The caller must take ownership of this
-  // memory. On success (S_OK or S_FALSE) |sid| will be allocated and filled
-  // with the sid of the created or existing user. The caller must take
-  // ownership of this memory.
-  HRESULT ValidateOrCreateUser(BSTR username,
-                               BSTR password,
-                               BSTR fullname,
+  // Checks whether this credential can sign in the user specified by
+  // |username|, |sid|, For the default anonymous gaia credential this function
+  // will return S_OK. For implementers that are associated to a specific user,
+  // this function should verify if the |username| and |sid| matches the
+  // username and sid stored in the credential. If these verifications fail then
+  // the function should return an error code which will cause sign in to fail.
+  virtual HRESULT ValidateExistingUser(const base::string16& username,
+                                       const base::string16& sid,
+                                       BSTR* error_text);
+
+  // Checks the information given in |result| to determine if a user can be
+  // created or re-used.
+  // Returns S_OK if a valid was found or a new user was created. Also allocates
+  // and fills |username|, |password|, |sid| with the information for the user.
+  // The caller must take ownership of this memory.
+  // On failure |error_text| will be allocated and filled with an error message.
+  // The caller must take ownership of this memory.
+  HRESULT ValidateOrCreateUser(const base::DictionaryValue* result,
+                               BSTR* username,
+                               BSTR* password,
                                BSTR* sid,
                                BSTR* error_text);
 
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
index a8206c1..9cb34f0 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
 #include "chrome/credential_provider/gaiacp/reg_utils.h"
@@ -164,6 +165,62 @@
   EXPECT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 }
 
+TEST_F(GcpGaiaCredentialBaseTest,
+       GetSerialization_AssociateToMatchingAssociatedUser) {
+  USES_CONVERSION;
+  // Create a fake user that has the same gaia id as the test gaia id.
+  CComBSTR first_sid;
+  base::string16 username(L"foo");
+  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
+                      username, L"password", L"name", L"comment",
+                      base::UTF8ToUTF16(kDefaultGaiaId), base::string16(),
+                      &first_sid));
+  ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
+  FakeGaiaCredentialProvider provider;
+
+  // Start logon.
+  CComPtr<IGaiaCredential> gaia_cred;
+  CComPtr<ICredentialProviderCredential> cred;
+  ASSERT_EQ(S_OK, CreateCredentialWithProvider(&provider, &gaia_cred, &cred));
+
+  CComPtr<ITestCredential> test;
+  ASSERT_EQ(S_OK, cred.QueryInterface(&test));
+
+  ASSERT_EQ(S_OK, run_helper()->StartLogonProcessAndWait(cred));
+
+  // Now finish the logon.
+  CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE cpgsr;
+  CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION cpcs;
+  wchar_t* status_text;
+  CREDENTIAL_PROVIDER_STATUS_ICON status_icon;
+  ASSERT_EQ(S_OK,
+            cred->GetSerialization(&cpgsr, &cpcs, &status_text, &status_icon));
+  EXPECT_EQ(nullptr, status_text);
+  EXPECT_EQ(CPSI_SUCCESS, status_icon);
+  EXPECT_EQ(CPGSR_RETURN_CREDENTIAL_FINISHED, cpgsr);
+  EXPECT_LT(0u, cpcs.cbSerialization);
+  EXPECT_NE(nullptr, cpcs.rgbSerialization);
+
+  // State was not reset.
+  EXPECT_TRUE(test->AreCredentialsValid());
+
+  // User should have been associated.
+  EXPECT_EQ(test->GetFinalUsername(), username);
+  // Email should be the same as the default one.
+  EXPECT_EQ(test->GetFinalEmail(), kDefaultEmail);
+
+  wchar_t* report_status_text = nullptr;
+  CREDENTIAL_PROVIDER_STATUS_ICON report_icon;
+  EXPECT_EQ(S_OK, cred->ReportResult(0, 0, &report_status_text, &report_icon));
+  // State was reset.
+  EXPECT_FALSE(test->AreCredentialsValid());
+
+  EXPECT_EQ(S_OK, gaia_cred->Terminate());
+
+  // No new user should be created.
+  EXPECT_EQ(2ul, fake_os_user_manager()->GetUserCount());
+}
+
 TEST_F(GcpGaiaCredentialBaseTest, GetSerialization_MultipleCalls) {
   FakeGaiaCredentialProvider provider;
 
@@ -204,17 +261,19 @@
   ASSERT_EQ(S_OK, gaia_cred->Terminate());
 }
 
-TEST_F(GcpGaiaCredentialBaseTest, GetSerialization_PasswordChanged) {
+TEST_F(GcpGaiaCredentialBaseTest,
+       GetSerialization_PasswordChangedForAssociatedUser) {
+  USES_CONVERSION;
   FakeGaiaCredentialProvider provider;
 
   // Create a fake user for which the windows password does not match the gaia
   // password supplied by the test gls process.
-  OSUserManager* manager = OSUserManager::Get();
   CComBSTR sid;
-  DWORD error;
   CComBSTR windows_password = L"password2";
-  ASSERT_EQ(S_OK, manager->AddUser(L"foo", (BSTR)windows_password, L"Full Name",
-                                   L"comment", true, &sid, &error));
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager()->CreateTestOSUser(
+                L"foo", (BSTR)windows_password, L"Full Name", L"comment",
+                base::UTF8ToUTF16(kDefaultGaiaId), base::string16(), &sid));
 
   // Start logon.
   CComPtr<IGaiaCredential> gaia_cred;
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_unittests.cc
index 4d3e381..8b674326 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_unittests.cc
@@ -7,17 +7,37 @@
 #include <atlcomcli.h>
 
 #include "base/json/json_writer.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
+#include "chrome/credential_provider/gaiacp/gaia_resources.h"
+#include "chrome/credential_provider/gaiacp/reg_utils.h"
 #include "chrome/credential_provider/test/com_fakes.h"
 #include "chrome/credential_provider/test/gcp_fakes.h"
+#include "chrome/credential_provider/test/gls_runner_test_base.h"
+#include "chrome/credential_provider/test/test_credential.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace credential_provider {
 
-class GcpGaiaCredentialTest : public ::testing::Test {
+namespace testing {
+
+namespace {
+
+HRESULT CreateGaiaCredentialWithProvider(
+    IGaiaCredentialProvider* provider,
+    IGaiaCredential** gaia_credential,
+    ICredentialProviderCredential** credential) {
+  return CreateBaseInheritedCredentialWithProvider<CGaiaCredential>(
+      provider, gaia_credential, credential);
+}
+
+}  // namespace
+
+class GcpGaiaCredentialTest : public GlsRunnerTestBase {
  protected:
   GcpGaiaCredentialTest();
 
@@ -29,9 +49,6 @@
  private:
   FakeGaiaCredentialProvider provider_;
   CComBSTR signin_result_;
-
-  FakeOSUserManager fake_os_user_manager_;
-  FakeScopedLsaPolicyFactory fake_scoped_lsa_policy_factory_;
 };
 
 GcpGaiaCredentialTest::GcpGaiaCredentialTest() {
@@ -52,38 +69,57 @@
 TEST_F(GcpGaiaCredentialTest, OnUserAuthenticated) {
   USES_CONVERSION;
 
-  CComPtr<IGaiaCredential> cred;
-  ASSERT_EQ(S_OK, CComCreator<CComObject<CGaiaCredential>>::CreateInstance(
-                      nullptr, IID_IGaiaCredential, (void**)&cred));
-  ASSERT_EQ(S_OK, cred->Initialize(provider()));
+  CComPtr<IGaiaCredential> gaia_cred;
+  CComPtr<ICredentialProviderCredential> cred;
+  ASSERT_EQ(S_OK,
+            CreateGaiaCredentialWithProvider(provider(), &gaia_cred, &cred));
 
   CComBSTR error;
-  ASSERT_EQ(S_OK, cred->OnUserAuthenticated(signin_result(), &error));
-  ASSERT_TRUE(provider()->credentials_changed_fired());
+  ASSERT_EQ(S_OK, gaia_cred->OnUserAuthenticated(signin_result(), &error));
+  EXPECT_TRUE(provider()->credentials_changed_fired());
 }
 
 TEST_F(GcpGaiaCredentialTest, OnUserAuthenticated_SamePassword) {
   USES_CONVERSION;
 
-  CComPtr<IGaiaCredential> cred;
-  ASSERT_EQ(S_OK, CComCreator<CComObject<CGaiaCredential>>::CreateInstance(
-                      nullptr, IID_IGaiaCredential, (void**)&cred));
-  ASSERT_EQ(S_OK, cred->Initialize(provider()));
+  CComPtr<IGaiaCredential> gaia_cred;
+  CComPtr<ICredentialProviderCredential> cred;
+  ASSERT_EQ(S_OK,
+            CreateGaiaCredentialWithProvider(provider(), &gaia_cred, &cred));
 
   CComBSTR error;
-  ASSERT_EQ(S_OK, cred->OnUserAuthenticated(signin_result(), &error));
+  ASSERT_EQ(S_OK, gaia_cred->OnUserAuthenticated(signin_result(), &error));
+
   CComBSTR first_sid = provider()->sid();
 
+  // Report to register the user.
+  wchar_t* report_status_text = nullptr;
+  CREDENTIAL_PROVIDER_STATUS_ICON report_icon;
+  EXPECT_EQ(S_OK, cred->ReportResult(0, 0, &report_status_text, &report_icon));
+
   // Finishing with the same username+password should succeed.
   CComBSTR error2;
-  ASSERT_EQ(S_OK, cred->OnUserAuthenticated(signin_result(), &error2));
-  ASSERT_TRUE(provider()->credentials_changed_fired());
-  ASSERT_EQ(first_sid, provider()->sid());
+  ASSERT_EQ(S_OK, gaia_cred->OnUserAuthenticated(signin_result(), &error2));
+  EXPECT_TRUE(provider()->credentials_changed_fired());
+  EXPECT_EQ(first_sid, provider()->sid());
 }
 
 TEST_F(GcpGaiaCredentialTest, OnUserAuthenticated_DiffPassword) {
   USES_CONVERSION;
 
+  CredentialProviderSigninDialogTestDataStorage test_data_storage;
+
+  CComBSTR sid;
+  ASSERT_EQ(
+      S_OK,
+      fake_os_user_manager()->CreateTestOSUser(
+          L"foo_bar",
+          base::UTF8ToUTF16(test_data_storage.GetSuccessPassword()).c_str(),
+          base::UTF8ToUTF16(test_data_storage.GetSuccessFullName()).c_str(),
+          L"comment",
+          base::UTF8ToUTF16(test_data_storage.GetSuccessId()).c_str(),
+          base::UTF8ToUTF16(test_data_storage.GetSuccessEmail()).c_str(),
+          &sid));
   CComPtr<IGaiaCredential> cred;
   ASSERT_EQ(S_OK, CComCreator<CComObject<CGaiaCredential>>::CreateInstance(
                       nullptr, IID_IGaiaCredential, (void**)&cred));
@@ -91,15 +127,167 @@
 
   CComBSTR error;
   ASSERT_EQ(S_OK, cred->OnUserAuthenticated(signin_result(), &error));
-  CComBSTR first_sid = provider()->sid();
+  EXPECT_TRUE(provider()->credentials_changed_fired());
+
+  provider()->ResetCredentialsChangedFired();
 
   CComBSTR new_signin_result = MakeSigninResult("password2");
 
   // Finishing with the same username but different password should mark
   // the password as stale and not fire the credentials changed event.
-  ASSERT_EQ(S_OK, cred->OnUserAuthenticated(new_signin_result, &error));
-  ASSERT_FALSE(provider()->credentials_changed_fired());
-  ASSERT_EQ(first_sid, provider()->sid());
+  EXPECT_EQ(S_FALSE, cred->OnUserAuthenticated(new_signin_result, &error));
+  EXPECT_FALSE(provider()->credentials_changed_fired());
 }
 
+class GcpGaiaCredentialGlsRunnerTest : public GlsRunnerTestBase {};
+
+TEST_F(GcpGaiaCredentialGlsRunnerTest,
+       AssociateToExistingAssociatedUser_LongUsername) {
+  USES_CONVERSION;
+
+  // Create a fake user that has the same username but a different gaia id
+  // as the test gaia id.
+  CComBSTR sid;
+  base::string16 base_username(L"foo1234567890abcdefg");
+  base::string16 base_gaia_id(L"other-gaia-id");
+  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
+                      base_username.c_str(), L"password", L"name", L"comment",
+                      base_gaia_id, base::string16(), &sid));
+
+  ASSERT_EQ(2u, fake_os_user_manager()->GetUserCount());
+  FakeGaiaCredentialProvider provider;
+
+  // Start logon.
+  CComPtr<IGaiaCredential> gaia_cred;
+  CComPtr<ICredentialProviderCredential> cred;
+  ASSERT_EQ(S_OK,
+            CreateGaiaCredentialWithProvider(&provider, &gaia_cred, &cred));
+
+  CComPtr<ITestCredential> test;
+  ASSERT_EQ(S_OK, cred.QueryInterface(&test));
+  ASSERT_EQ(S_OK, test->SetGlsEmailAddress(base::UTF16ToUTF8(base_username) +
+                                           "@gmail.com"));
+  ASSERT_EQ(S_OK, run_helper()->StartLogonProcessAndWait(cred));
+
+  // New username should be truncated at the end and have the last character
+  // replaced with a new index
+  EXPECT_STREQ((base_username.substr(0, base_username.size() - 1) +
+                base::NumberToString16(kInitialDuplicateUsernameIndex))
+                   .c_str(),
+               provider.username());
+  EXPECT_NE(0u, provider.password().Length());
+  EXPECT_NE(0u, provider.sid().Length());
+  EXPECT_STREQ(test->GetErrorText(), nullptr);
+  EXPECT_EQ(TRUE, provider.credentials_changed_fired());
+  // New user should be created.
+  EXPECT_EQ(3u, fake_os_user_manager()->GetUserCount());
+
+  EXPECT_EQ(S_OK, gaia_cred->Terminate());
+}
+
+// This test checks the expected success / failure of user creation when
+// GCPW wants to associate a gaia id to a user that may already be associated
+// to another gaia id.
+// Parameters:
+// int: Number of existing users to create before trying to associate the
+// new user.
+// bool: Whether the final user creation is expected to succeed. For
+// bool: whether the created users are associated to a gaia id.
+// kMaxAttempts = 10, 0 to 8 users can be created and still have the
+// test succeed. If a 9th user is create the test will fail.
+class GcpAssociatedUserRunnableGaiaCredentialTest
+    : public GcpGaiaCredentialGlsRunnerTest,
+      public ::testing::WithParamInterface<std::tuple<int, bool, bool>> {};
+
+TEST_P(GcpAssociatedUserRunnableGaiaCredentialTest,
+       AssociateToExistingAssociatedUser) {
+  USES_CONVERSION;
+  int last_user_index = std::get<0>(GetParam());
+  bool should_succeed = std::get<1>(GetParam());
+  bool should_associate = std::get<2>(GetParam());
+
+  // Create many fake users that has the same username but a different gaia id
+  // as the test gaia id.
+  CComBSTR sid;
+  base::string16 base_username(L"foo");
+  base::string16 base_gaia_id(L"other-gaia-id");
+  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
+                      base_username.c_str(), L"password", L"name", L"comment",
+                      should_associate ? base_gaia_id : base::string16(),
+                      base::string16(), &sid));
+  ASSERT_EQ(S_OK, SetUserProperty(OLE2CW(sid), A2CW(kKeyId), base_gaia_id));
+
+  for (int i = 0; i < last_user_index; ++i) {
+    base::string16 user_suffix =
+        base::NumberToString16(i + kInitialDuplicateUsernameIndex);
+    ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
+                        (base_username + user_suffix).c_str(), L"password",
+                        L"name", L"comment",
+                        should_associate ? base_gaia_id + user_suffix
+                                         : base::string16(),
+                        base::string16(), &sid));
+  }
+
+  ASSERT_EQ(static_cast<size_t>(1 + last_user_index + 1),
+            fake_os_user_manager()->GetUserCount());
+  FakeGaiaCredentialProvider provider;
+
+  // Start logon.
+  CComPtr<IGaiaCredential> gaia_cred;
+  CComPtr<ICredentialProviderCredential> cred;
+  ASSERT_EQ(S_OK,
+            CreateGaiaCredentialWithProvider(&provider, &gaia_cred, &cred));
+
+  CComPtr<ITestCredential> test;
+  ASSERT_EQ(S_OK, cred.QueryInterface(&test));
+
+  ASSERT_EQ(S_OK, run_helper()->StartLogonProcessAndWait(cred));
+
+  if (should_succeed) {
+    EXPECT_STREQ(
+        (base_username + base::NumberToString16(last_user_index +
+                                                kInitialDuplicateUsernameIndex))
+            .c_str(),
+        provider.username());
+    EXPECT_NE(0u, provider.password().Length());
+    EXPECT_NE(0u, provider.sid().Length());
+    EXPECT_STREQ(test->GetErrorText(), nullptr);
+    EXPECT_EQ(TRUE, provider.credentials_changed_fired());
+    // New user should be created.
+    EXPECT_EQ(static_cast<size_t>(last_user_index + 2 + 1),
+              fake_os_user_manager()->GetUserCount());
+  } else {
+    EXPECT_EQ(0u, provider.username().Length());
+    EXPECT_EQ(0u, provider.password().Length());
+    EXPECT_EQ(0u, provider.sid().Length());
+    EXPECT_STREQ(test->GetErrorText(),
+                 GetStringResource(IDS_INTERNAL_ERROR_BASE).c_str());
+    EXPECT_EQ(FALSE, provider.credentials_changed_fired());
+    // No new user should be created.
+    EXPECT_EQ(static_cast<size_t>(last_user_index + 1 + 1),
+              fake_os_user_manager()->GetUserCount());
+  }
+  // Expect a different user name with the suffix added.
+  EXPECT_EQ(S_OK, gaia_cred->Terminate());
+}
+
+// For a max retry of 10, it is possible to create users 'username',
+// 'username0' ... 'username8' before failing. At 'username9' the test should
+// fail.
+
+INSTANTIATE_TEST_CASE_P(
+    AvailableUsername,
+    GcpAssociatedUserRunnableGaiaCredentialTest,
+    ::testing::Combine(::testing::Range(0, kMaxUsernameAttempts - 2),
+                       ::testing::Values(true),
+                       ::testing::Values(true, false)));
+
+INSTANTIATE_TEST_CASE_P(
+    UnavailableUsername,
+    GcpAssociatedUserRunnableGaiaCredentialTest,
+    ::testing::Combine(::testing::Values(kMaxUsernameAttempts - 1),
+                       ::testing::Values(false),
+                       ::testing::Values(true, false)));
+}  // namespace testing
+
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.h b/chrome/credential_provider/gaiacp/gcp_utils.h
index 6895ffe..21dcf85 100644
--- a/chrome/credential_provider/gaiacp/gcp_utils.h
+++ b/chrome/credential_provider/gaiacp/gcp_utils.h
@@ -36,6 +36,22 @@
 // Windows supports a maximum of 20 characters plus null in username.
 constexpr int kWindowsUsernameBufferLength = 21;
 
+// Maximum domain length is 256 characters including null.
+// https://support.microsoft.com/en-ca/help/909264/naming-conventions-in-active-directory-for-computers-domains-sites-and
+constexpr int kWindowsDomainBufferLength = 256;
+
+// According to:
+// https://stackoverflow.com/questions/1140528/what-is-the-maximum-length-of-a-sid-in-sddl-format
+constexpr int kWindowsSidBufferLength = 184;
+
+// Max number of attempts to find a new username when a user already exists
+// with the same username.
+constexpr int kMaxUsernameAttempts = 10;
+
+// First index to append to a username when another user with the same name
+// already exists.
+constexpr int kInitialDuplicateUsernameIndex = 2;
+
 // Because of some strange dependency problems with windows header files,
 // define STATUS_SUCCESS here instead of including ntstatus.h or SubAuth.h
 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
diff --git a/chrome/credential_provider/gaiacp/reauth_credential.cc b/chrome/credential_provider/gaiacp/reauth_credential.cc
index 9f5b87a..ef73c41 100644
--- a/chrome/credential_provider/gaiacp/reauth_credential.cc
+++ b/chrome/credential_provider/gaiacp/reauth_credential.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/credential_provider/gaiacp/reauth_credential.h"
 
-#include "base/stl_util.h"
+#include "base/command_line.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
+#include "chrome/credential_provider/gaiacp/gaia_resources.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
-#include "chrome/credential_provider/gaiacp/os_user_manager.h"
 #include "chrome/credential_provider/gaiacp/reg_utils.h"
 
 namespace credential_provider {
@@ -25,15 +25,88 @@
   LOGFN(INFO);
 }
 
-HRESULT CReauthCredential::GetEmailForReauth(wchar_t* email, size_t length) {
-  if (email == nullptr)
-    return E_POINTER;
+// ICredentialProviderCredential2 //////////////////////////////////////////////
+HRESULT CReauthCredential::GetUserSid(wchar_t** sid) {
+  USES_CONVERSION;
+  DCHECK(sid);
+  LOGFN(INFO) << "sid=" << OLE2CW(os_user_sid_);
 
-  if (length < 1)
-    return E_INVALIDARG;
+  HRESULT hr = ::SHStrDupW(OLE2CW(os_user_sid_), sid);
+  if (FAILED(hr))
+    LOGFN(ERROR) << "SHStrDupW hr=" << putHR(hr);
 
-  errno_t err = wcsncpy_s(email, length, OLE2CW(email_for_reauth_), _TRUNCATE);
-  return err == 0 ? S_OK : E_FAIL;
+  return hr;
+}
+
+// CGaiaCredentialBase /////////////////////////////////////////////////////////
+
+HRESULT CReauthCredential::GetUserGlsCommandline(
+    base::CommandLine* command_line) {
+  DCHECK(command_line);
+  DCHECK(os_user_sid_.Length());
+
+  // If this is an existing user with an SID, try to get its gaia id and pass
+  // it to the GLS for verification.
+  base::string16 gaia_id;
+  if (GetIdFromSid(OLE2CW(os_user_sid_), &gaia_id) == S_OK) {
+    command_line->AppendSwitchNative(kGaiaIdSwitch, gaia_id);
+    if (email_for_reauth_.Length()) {
+      command_line->AppendSwitchNative(kPrefillEmailSwitch,
+                                       (BSTR)email_for_reauth_);
+    }
+  } else {
+    LOGFN(ERROR) << "Reauth credential on user=" << os_username_
+                 << " does not have an associated Gaia id";
+    return E_UNEXPECTED;
+  }
+  return CGaiaCredentialBase::GetUserGlsCommandline(command_line);
+}
+
+HRESULT CReauthCredential::ValidateExistingUser(const base::string16& username,
+                                                const base::string16& sid,
+                                                BSTR* error_text) {
+  DCHECK(os_username_.Length());
+  DCHECK(os_user_sid_.Length());
+
+  // SID, domain and username found must match what is stored in this
+  // credential.
+  if ((os_username_ != W2COLE(username.c_str()))) {
+    LOGFN(ERROR) << "Username calculated '" << username
+                 << "' does not match the "
+                 << "username that is set '" << os_username_ << "'";
+    *error_text = AllocErrorString(IDS_ACCOUNT_IN_USE_BASE);
+    return E_UNEXPECTED;
+  }
+
+  if (os_user_sid_ != W2COLE(sid.c_str())) {
+    LOGFN(ERROR) << "SID found '" << sid << "' does not match the SID of the"
+                 << "user that is set '" << os_user_sid_ << "'";
+    *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
+    return E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+HRESULT CReauthCredential::GetStringValueImpl(DWORD field_id, wchar_t** value) {
+  if (field_id == FID_PROVIDER_LABEL) {
+    base::string16 label(
+        GetStringResource(IDS_EXISTING_AUTH_FID_PROVIDER_LABEL_BASE));
+    return ::SHStrDupW(label.c_str(), value);
+  }
+
+  return CGaiaCredentialBase::GetStringValueImpl(field_id, value);
+}
+
+// IReauthCredential ///////////////////////////////////////////////////////////
+
+HRESULT CReauthCredential::SetOSUserInfo(BSTR sid, BSTR username) {
+  DCHECK(sid);
+  DCHECK(username);
+
+  os_user_sid_ = sid;
+  os_username_ = username;
+  return S_OK;
 }
 
 IFACEMETHODIMP CReauthCredential::SetEmailForReauth(BSTR email) {
@@ -43,13 +116,4 @@
   return S_OK;
 }
 
-HRESULT CReauthCredential::SetOSUserInfo(BSTR sid, BSTR username) {
-  DCHECK(sid);
-  DCHECK(username);
-
-  set_user_sid(sid);
-  set_username(username);
-  return S_OK;
-}
-
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/reauth_credential.h b/chrome/credential_provider/gaiacp/reauth_credential.h
index 204ed7451..0baf8fb 100644
--- a/chrome/credential_provider/gaiacp/reauth_credential.h
+++ b/chrome/credential_provider/gaiacp/reauth_credential.h
@@ -10,7 +10,8 @@
 
 namespace credential_provider {
 
-// Implementation of a ICredentialProviderCredential backed by a Gaia account.
+// A credential for a user that exists on the system and is associated with a
+// Gaia account.
 class ATL_NO_VTABLE CReauthCredential
     : public CComObjectRootEx<CComMultiThreadModel>,
       public CGaiaCredentialBase,
@@ -24,9 +25,6 @@
   HRESULT FinalConstruct();
   void FinalRelease();
 
- protected:
-  HRESULT GetEmailForReauth(wchar_t* email, size_t length) override;
-
  private:
   // This class does not say it implements ICredentialProviderCredential2.
   // It only implements ICredentialProviderCredential.  Otherwise the
@@ -34,16 +32,39 @@
   // machines.
   BEGIN_COM_MAP(CReauthCredential)
   COM_INTERFACE_ENTRY(IGaiaCredential)
+  COM_INTERFACE_ENTRY(IReauthCredential)
   COM_INTERFACE_ENTRY(ICredentialProviderCredential)
   COM_INTERFACE_ENTRY(ICredentialProviderCredential2)
-  COM_INTERFACE_ENTRY(IReauthCredential)
   END_COM_MAP()
 
   DECLARE_PROTECT_FINAL_CONSTRUCT()
 
+  // ICredentialProviderCredential2
+  IFACEMETHODIMP GetUserSid(wchar_t** sid) override;
+
+  // CGaiaCredentialBase
+
+  // Adds additional command line switches to specify which gaia id to sign in
+  // and which email is used to prefill the Gaia page.
+  HRESULT GetUserGlsCommandline(base::CommandLine* command_line) override;
+
+  // Checks if the information for the given |domain|\|username|, |sid| is
+  // valid.
+  // Returns S_OK if the user information stored in this credential matches
+  // the user information that is being validated. Otherwise fills |error_text|
+  // with an appropriate error message and returns an error.
+  HRESULT ValidateExistingUser(const base::string16& username,
+                               const base::string16& sid,
+                               BSTR* error_text) override;
+  HRESULT GetStringValueImpl(DWORD field_id, wchar_t** value) override;
+
   // IReauthCredential
-  IFACEMETHODIMP SetEmailForReauth(BSTR email) override;
   IFACEMETHODIMP SetOSUserInfo(BSTR sid, BSTR username) override;
+  IFACEMETHODIMP SetEmailForReauth(BSTR email) override;
+
+  // Information about the OS user.
+  CComBSTR os_username_;
+  CComBSTR os_user_sid_;
 
   CComBSTR email_for_reauth_;
 };
diff --git a/chrome/credential_provider/gaiacp/scoped_user_profile.cc b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
index a8b04da..12b38f9 100644
--- a/chrome/credential_provider/gaiacp/scoped_user_profile.cc
+++ b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
@@ -145,8 +145,7 @@
   }
 
   for (auto image_size : kProfilePictureSizes) {
-    base::string16 image_size_postfix =
-        base::StringPrintf(L"%i", image_size);
+    base::string16 image_size_postfix = base::StringPrintf(L"%i", image_size);
     base::FilePath target_picture_path = account_picture_path.Append(
         base_picture_filename + image_size_postfix + base_picture_extension);
 
@@ -261,34 +260,49 @@
   return token_.IsValid();
 }
 
-HRESULT ScopedUserProfile::SaveAccountInfo(
-    const base::DictionaryValue& properties) {
-  LOGFN(INFO);
+HRESULT ScopedUserProfile::ExtractAssociationInformation(
+    const base::DictionaryValue& properties,
+    base::string16* sid,
+    base::string16* id,
+    base::string16* email,
+    base::string16* token_handle) {
+  DCHECK(sid);
+  DCHECK(id);
+  DCHECK(email);
+  DCHECK(token_handle);
 
-  base::string16 sid = GetDictString(&properties, kKeySID);
-  if (sid.empty()) {
+  *sid = GetDictString(&properties, kKeySID);
+  if (sid->empty()) {
     LOGFN(ERROR) << "SID is empty";
     return E_INVALIDARG;
   }
 
-  base::string16 id = GetDictString(&properties, kKeyId);
-  if (id.empty()) {
+  *id = GetDictString(&properties, kKeyId);
+  if (id->empty()) {
     LOGFN(ERROR) << "Id is empty";
     return E_INVALIDARG;
   }
 
-  base::string16 email = GetDictString(&properties, kKeyEmail);
-  if (email.empty()) {
+  *email = GetDictString(&properties, kKeyEmail);
+  if (email->empty()) {
     LOGFN(ERROR) << "Email is empty";
     return E_INVALIDARG;
   }
 
-  base::string16 token_handle = GetDictString(&properties, kKeyTokenHandle);
-  if (token_handle.empty()) {
+  *token_handle = GetDictString(&properties, kKeyTokenHandle);
+  if (token_handle->empty()) {
     LOGFN(ERROR) << "Token handle is empty";
     return E_INVALIDARG;
   }
 
+  return S_OK;
+}
+
+HRESULT ScopedUserProfile::RegisterAssociation(
+    const base::string16& sid,
+    const base::string16& id,
+    const base::string16& email,
+    const base::string16& token_handle) {
   // Save token handle.  This handle will be used later to determine if the
   // the user has changed their password since the account was created.
   HRESULT hr = SetUserProperty(sid, kUserTokenHandle, token_handle);
@@ -309,6 +323,28 @@
     return hr;
   }
 
+  return S_OK;
+}
+
+HRESULT ScopedUserProfile::SaveAccountInfo(
+    const base::DictionaryValue& properties) {
+  LOGFN(INFO);
+
+  base::string16 sid;
+  base::string16 id;
+  base::string16 email;
+  base::string16 token_handle;
+
+  HRESULT hr = ExtractAssociationInformation(properties, &sid, &id, &email,
+                                             &token_handle);
+  if (FAILED(hr))
+    return hr;
+
+  hr = RegisterAssociation(sid, id, email, token_handle);
+
+  if (FAILED(hr))
+    return hr;
+
   // Write account information to the user's hive.
   // NOTE: regular users cannot access the registry entry of other users,
   // but administrators and SYSTEM can.
diff --git a/chrome/credential_provider/gaiacp/scoped_user_profile.h b/chrome/credential_provider/gaiacp/scoped_user_profile.h
index 922684f2..0248f09f 100644
--- a/chrome/credential_provider/gaiacp/scoped_user_profile.h
+++ b/chrome/credential_provider/gaiacp/scoped_user_profile.h
@@ -36,6 +36,16 @@
   // tests are not running elevated.
   ScopedUserProfile();
 
+  HRESULT ExtractAssociationInformation(const base::DictionaryValue& properties,
+                                        base::string16* sid,
+                                        base::string16* id,
+                                        base::string16* email,
+                                        base::string16* token_handle);
+  HRESULT RegisterAssociation(const base::string16& sid,
+                              const base::string16& id,
+                              const base::string16& email,
+                              const base::string16& token_handle);
+
  private:
   friend class FakeScopedUserProfileFactory;
 
diff --git a/chrome/credential_provider/test/com_fakes.h b/chrome/credential_provider/test/com_fakes.h
index 434f20c..8717142 100644
--- a/chrome/credential_provider/test/com_fakes.h
+++ b/chrome/credential_provider/test/com_fakes.h
@@ -98,6 +98,7 @@
   const CComBSTR& password() const { return password_; }
   const CComBSTR& sid() const { return sid_; }
   bool credentials_changed_fired() const { return credentials_changed_fired_; }
+  void ResetCredentialsChangedFired() { credentials_changed_fired_ = FALSE; }
 
   // IGaiaCredentialProvider
   IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
diff --git a/chrome/credential_provider/test/gcp_fakes.cc b/chrome/credential_provider/test/gcp_fakes.cc
index dfe25ef..885ef9b 100644
--- a/chrome/credential_provider/test/gcp_fakes.cc
+++ b/chrome/credential_provider/test/gcp_fakes.cc
@@ -372,8 +372,34 @@
 
 FakeScopedUserProfile::FakeScopedUserProfile(const base::string16& sid,
                                              const base::string16& username,
-                                             const base::string16& password) {}
+                                             const base::string16& password) {
+  is_valid_ = OSUserManager::Get()->IsWindowsPasswordValid(
+                  username.c_str(), password.c_str()) == S_OK;
+}
 
 FakeScopedUserProfile::~FakeScopedUserProfile() {}
 
+HRESULT FakeScopedUserProfile::SaveAccountInfo(
+    const base::DictionaryValue& properties) {
+  if (!is_valid_)
+    return E_INVALIDARG;
+
+  base::string16 sid;
+  base::string16 id;
+  base::string16 email;
+  base::string16 token_handle;
+
+  HRESULT hr = ExtractAssociationInformation(properties, &sid, &id, &email,
+                                             &token_handle);
+  if (FAILED(hr))
+    return hr;
+
+  hr = RegisterAssociation(sid, id, email, token_handle);
+
+  if (FAILED(hr))
+    return hr;
+
+  return S_OK;
+}
+
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/test/gcp_fakes.h b/chrome/credential_provider/test/gcp_fakes.h
index d253442..566b58b4 100644
--- a/chrome/credential_provider/test/gcp_fakes.h
+++ b/chrome/credential_provider/test/gcp_fakes.h
@@ -182,6 +182,9 @@
 };
 
 class FakeScopedUserProfile : public ScopedUserProfile {
+ public:
+  HRESULT SaveAccountInfo(const base::DictionaryValue& properties) override;
+
  private:
   friend class FakeScopedUserProfileFactory;
 
@@ -189,6 +192,8 @@
                         const base::string16& username,
                         const base::string16& password);
   ~FakeScopedUserProfile() override;
+
+  bool is_valid_ = false;
 };
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/test/gcp_setup_unittests.cc b/chrome/credential_provider/test/gcp_setup_unittests.cc
index 281f9e7..9e11754 100644
--- a/chrome/credential_provider/test/gcp_setup_unittests.cc
+++ b/chrome/credential_provider/test/gcp_setup_unittests.cc
@@ -402,7 +402,8 @@
   EXPECT_FALSE(fake_scoped_lsa_policy_factory()
                    ->private_data()[kLsaKeyGaiaPassword]
                    .empty());
-  base::string16 expected_gaia_username = L"gaia0";
+  base::string16 expected_gaia_username =
+      L"gaia" + base::NumberToString16(kInitialDuplicateUsernameIndex);
   EXPECT_FALSE(fake_os_user_manager()
                    ->GetUserInfo(expected_gaia_username.c_str())
                    .sid.empty());
@@ -432,7 +433,8 @@
   int last_user_index = std::get<0>(GetParam());
   for (int i = 0; i < last_user_index; ++i) {
     base::string16 existing_gaia_username = kDefaultGaiaAccountName;
-    existing_gaia_username += base::NumberToString16(i);
+    existing_gaia_username +=
+        base::NumberToString16(i + kInitialDuplicateUsernameIndex);
     EXPECT_EQ(S_OK, fake_os_user_manager()->AddUser(
                         existing_gaia_username.c_str(), L"password",
                         L"fullname", L"comment", true, &sid, &error));
@@ -451,7 +453,8 @@
                      ->private_data()[kLsaKeyGaiaPassword]
                      .empty());
     base::string16 expected_gaia_username = kDefaultGaiaAccountName;
-    expected_gaia_username += base::NumberToString16(last_user_index);
+    expected_gaia_username += base::NumberToString16(
+        last_user_index + kInitialDuplicateUsernameIndex);
     EXPECT_FALSE(fake_os_user_manager()
                      ->GetUserInfo(expected_gaia_username.c_str())
                      .sid.empty());
@@ -471,14 +474,16 @@
 // For a max retry of 10, it is possible to create gaia users 'gaia',
 // 'gaia0' ... 'gaia8' before failing. At 'gaia9' the test should fail.
 
-INSTANTIATE_TEST_CASE_P(AvailableGaiaUserName,
-                        GcpGaiaUserCreationTest,
-                        ::testing::Combine(::testing::Range(0, 8),
-                                           ::testing::Values(true)));
+INSTANTIATE_TEST_CASE_P(
+    AvailableGaiaUserName,
+    GcpGaiaUserCreationTest,
+    ::testing::Combine(::testing::Range(0, kMaxUsernameAttempts - 2),
+                       ::testing::Values(true)));
 
-INSTANTIATE_TEST_CASE_P(UnavailableGaiaUserName,
-                        GcpGaiaUserCreationTest,
-                        ::testing::Values(std::make_tuple<int, bool>(9,
-                                                                     false)));
+INSTANTIATE_TEST_CASE_P(
+    UnavailableGaiaUserName,
+    GcpGaiaUserCreationTest,
+    ::testing::Values(std::make_tuple<int, bool>(kMaxUsernameAttempts - 1,
+                                                 false)));
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/test/gls_runner_test_base.h b/chrome/credential_provider/test/gls_runner_test_base.h
index 4f01554..677dd9b 100644
--- a/chrome/credential_provider/test/gls_runner_test_base.h
+++ b/chrome/credential_provider/test/gls_runner_test_base.h
@@ -31,6 +31,7 @@
   FakeOSProcessManager fake_os_process_manager_;
   FakeOSUserManager fake_os_user_manager_;
   FakeScopedLsaPolicyFactory fake_scoped_lsa_policy_factory_;
+  FakeScopedUserProfileFactory fake_scoped_user_profile_factory_;
   registry_util::RegistryOverrideManager registry_override_;
   FakeGlsRunHelper run_helper_;
 };
diff --git a/chrome/credential_provider/test/test_credential.h b/chrome/credential_provider/test/test_credential.h
index db137e2..1a84f16 100644
--- a/chrome/credential_provider/test/test_credential.h
+++ b/chrome/credential_provider/test/test_credential.h
@@ -103,6 +103,11 @@
       const base::CommandLine& command_line,
       CGaiaCredentialBase::UIProcessInfo* uiprocinfo) override;
 
+  // Overrides to directly save to a fake scoped user profile.
+  HRESULT ForkSaveAccountInfoStub(
+      const std::unique_ptr<base::DictionaryValue>& dict,
+      BSTR* status_text) override;
+
   void ResetInternalState() override;
 
   std::string gls_email_;
@@ -229,6 +234,13 @@
 }
 
 template <class T>
+HRESULT CTestCredentialBase<T>::ForkSaveAccountInfoStub(
+    const std::unique_ptr<base::DictionaryValue>& dict,
+    BSTR* status_text) {
+  return CGaiaCredentialBase::SaveAccountInfo(*dict);
+}
+
+template <class T>
 HRESULT CTestCredentialBase<T>::OnUserAuthenticated(BSTR authentication_info,
                                                     BSTR* status_text) {
   HRESULT hr = T::OnUserAuthenticated(authentication_info, status_text);
@@ -268,6 +280,57 @@
 }
 
 // This class is used to implement a test credential based off a fully
+// implemented CGaiaCredentialBase class.
+template <class T>
+class ATL_NO_VTABLE CTestCredentialForBaseInherited
+    : public CTestCredentialBase<T> {
+ public:
+  DECLARE_NO_REGISTRY()
+
+  CTestCredentialForBaseInherited();
+  ~CTestCredentialForBaseInherited();
+
+ private:
+  BEGIN_COM_MAP(CTestCredentialForBaseInherited)
+  COM_INTERFACE_ENTRY(IGaiaCredential)
+  COM_INTERFACE_ENTRY(ICredentialProviderCredential)
+  COM_INTERFACE_ENTRY(ICredentialProviderCredential2)
+  COM_INTERFACE_ENTRY(ITestCredential)
+  END_COM_MAP()
+};
+
+template <class T>
+CTestCredentialForBaseInherited<T>::CTestCredentialForBaseInherited() = default;
+
+template <class T>
+CTestCredentialForBaseInherited<T>::~CTestCredentialForBaseInherited() =
+    default;
+
+template <class T>
+HRESULT CreateBaseInheritedCredential(
+    ICredentialProviderCredential** credential) {
+  return CComCreator<CComObject<testing::CTestCredentialForBaseInherited<T>>>::
+      CreateInstance(nullptr, IID_ICredentialProviderCredential,
+                     reinterpret_cast<void**>(credential));
+}
+
+template <class T>
+HRESULT CreateBaseInheritedCredentialWithProvider(
+    IGaiaCredentialProvider* provider,
+    IGaiaCredential** gaia_credential,
+    ICredentialProviderCredential** credential) {
+  HRESULT hr = CreateBaseInheritedCredential<T>(credential);
+  if (SUCCEEDED(hr)) {
+    hr = (*credential)
+             ->QueryInterface(IID_IGaiaCredential,
+                              reinterpret_cast<void**>(gaia_credential));
+    if (SUCCEEDED(hr))
+      hr = (*gaia_credential)->Initialize(provider);
+  }
+  return hr;
+}
+
+// This class is used to implement a test credential based off a fully
 // implemented CGaiaCredentialBase class. The additional InterfaceT parameter
 // is used to specify any additional interfaces that should be registerd for
 // this class that is not part of CGaiaCredentialBase (this is used to
diff --git a/chrome/test/base/interactive_ui_tests_main.cc b/chrome/test/base/interactive_ui_tests_main.cc
index 6774007..3e5988f 100644
--- a/chrome/test/base/interactive_ui_tests_main.cc
+++ b/chrome/test/base/interactive_ui_tests_main.cc
@@ -15,6 +15,9 @@
 #if defined(USE_AURA)
 #include "ui/aura/test/ui_controls_factory_aura.h"
 #include "ui/base/test/ui_controls_aura.h"
+#if defined(USE_OZONE) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
 #if defined(USE_X11)
 #include "ui/views/test/ui_controls_factory_desktop_aurax11.h"
 #endif
@@ -45,7 +48,11 @@
     com_initializer_.reset(new base::win::ScopedCOMInitializer());
     ui_controls::InstallUIControlsAura(
         aura::test::CreateUIControlsAura(nullptr));
-#elif defined(OS_LINUX) && !defined(USE_OZONE)
+#elif defined(USE_OZONE) && defined(OS_LINUX)
+    ui::OzonePlatform::InitParams params;
+    params.single_process = true;
+    ui::OzonePlatform::EnsureInstance()->InitializeForUI(std::move(params));
+#elif defined(OS_LINUX)
     ui_controls::InstallUIControlsAura(
         views::test::CreateUIControlsDesktopAura());
 #else
diff --git a/chrome/test/data/webui/app_management/app_test.js b/chrome/test/data/webui/app_management/app_test.js
index 207c635..057689d 100644
--- a/chrome/test/data/webui/app_management/app_test.js
+++ b/chrome/test/data/webui/app_management/app_test.js
@@ -5,9 +5,21 @@
 'use strict';
 
 suite('<app-management-app>', function() {
+  let app;
+
+  setup(function() {
+    app = document.createElement('app-management-app');
+    document.body.appendChild(app);
+  });
+
   test('loads', async function() {
     // Check that the browser responds to the getApps() message.
     const {apps: initialApps} =
         await app_management.BrowserProxy.getInstance().handler.getApps();
   });
+
+  test('Searching switches to search page', async function() {
+    app.$$('cr-toolbar').fire('search-changed', 'SearchTest');
+    assert(app.$$('app-management-search-view'));
+  });
 });
diff --git a/chrome/test/data/webui/app_management/reducers_test.js b/chrome/test/data/webui/app_management/reducers_test.js
index 9ffc4c7..48201121 100644
--- a/chrome/test/data/webui/app_management/reducers_test.js
+++ b/chrome/test/data/webui/app_management/reducers_test.js
@@ -136,7 +136,6 @@
     state = app_management.reduceAction(state, action);
 
     assertEquals('searchTerm', state.search.term);
-    assertEquals(PageType.SEARCH, state.currentPage.pageType);
 
     // Search disappears when there is no term entered.
     action = app_management.actions.clearSearch();
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
index 56cbb60..7ad8b87 100644
--- a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
+++ b/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
@@ -25,6 +25,7 @@
     const base::Closure& dump_stack,
     syncer::SyncService* sync_service,
     syncer::SyncClient* sync_client,
+    const PersonalDataManagerProvider& pdm_provider,
     const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
     : AsyncDirectoryTypeController(type,
                                    dump_stack,
@@ -32,6 +33,7 @@
                                    sync_client,
                                    syncer::GROUP_DB,
                                    std::move(db_thread)),
+      pdm_provider_(pdm_provider),
       callback_registered_(false),
       web_data_service_(web_data_service),
       currently_enabled_(IsEnabled()) {
@@ -96,8 +98,7 @@
     if (!sync_service()->CanSyncFeatureStart() ||
         !sync_service()->GetPreferredDataTypes().Has(type()) ||
         !currently_enabled_) {
-      autofill::PersonalDataManager* pdm =
-          sync_client()->GetPersonalDataManager();
+      autofill::PersonalDataManager* pdm = pdm_provider_.Run();
       if (pdm) {
         int count = pdm->GetServerCreditCards().size() +
                     pdm->GetServerProfiles().size() +
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller.h b/components/autofill/core/browser/autofill_wallet_data_type_controller.h
index 837d293..be0e0fff 100644
--- a/components/autofill/core/browser/autofill_wallet_data_type_controller.h
+++ b/components/autofill/core/browser/autofill_wallet_data_type_controller.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -12,7 +13,8 @@
 
 namespace autofill {
 class AutofillWebDataService;
-}
+class PersonalDataManager;
+}  // namespace autofill
 
 namespace syncer {
 class SyncClient;
@@ -25,6 +27,9 @@
 class AutofillWalletDataTypeController
     : public syncer::AsyncDirectoryTypeController {
  public:
+  using PersonalDataManagerProvider =
+      base::RepeatingCallback<autofill::PersonalDataManager*()>;
+
   // |type| should be either AUTOFILL_WALLET or AUTOFILL_WALLET_METADATA.
   // |dump_stack| is called when an unrecoverable error occurs.
   AutofillWalletDataTypeController(
@@ -33,6 +38,7 @@
       const base::Closure& dump_stack,
       syncer::SyncService* sync_service,
       syncer::SyncClient* sync_client,
+      const PersonalDataManagerProvider& pdm_provider,
       const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
   ~AutofillWalletDataTypeController() override;
 
@@ -51,6 +57,9 @@
   // Report an error (which will stop the datatype asynchronously).
   void DisableForPolicy();
 
+  // Callback that allows accessing PersonalDataManager lazily.
+  const PersonalDataManagerProvider pdm_provider_;
+
   // Whether the database loaded callback has been registered.
   bool callback_registered_;
 
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc b/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc
index ca9744db..c8a98af 100644
--- a/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc
+++ b/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc
@@ -24,20 +24,21 @@
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/data_type_controller_mock.h"
 #include "components/sync/driver/fake_generic_change_processor.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/fake_sync_service.h"
-#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/model/fake_syncable_service.h"
 #include "components/sync/model/sync_error.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using autofill::AutofillWebDataService;
-
 namespace browser_sync {
 
 namespace {
 
+using autofill::AutofillWebDataService;
+using testing::_;
+using testing::Return;
+
 // Fake WebDataService implementation that stubs out the database loading.
 class FakeWebDataService : public AutofillWebDataService {
  public:
@@ -76,12 +77,9 @@
   DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
 };
 
-class AutofillWalletDataTypeControllerTest : public testing::Test,
-                                             public syncer::FakeSyncClient {
+class AutofillWalletDataTypeControllerTest : public testing::Test {
  public:
-  AutofillWalletDataTypeControllerTest()
-      : syncer::FakeSyncClient(&profile_sync_factory_),
-        last_type_(syncer::UNSPECIFIED) {}
+  AutofillWalletDataTypeControllerTest() : last_type_(syncer::UNSPECIFIED) {}
   ~AutofillWalletDataTypeControllerTest() override {}
 
   void SetUp() override {
@@ -90,12 +88,18 @@
     prefs_.registry()->RegisterBooleanPref(
         autofill::prefs::kAutofillCreditCardEnabled, true);
 
+    ON_CALL(sync_client_, GetPrefService()).WillByDefault(Return(&prefs_));
+    ON_CALL(sync_client_, GetSyncableServiceForType(_))
+        .WillByDefault(Return(syncable_service_.AsWeakPtr()));
+
     web_data_service_ = base::MakeRefCounted<FakeWebDataService>(
         base::ThreadTaskRunnerHandle::Get(),
         base::ThreadTaskRunnerHandle::Get());
     autofill_wallet_dtc_ = std::make_unique<AutofillWalletDataTypeController>(
         syncer::AUTOFILL_WALLET_DATA, base::ThreadTaskRunnerHandle::Get(),
-        base::DoNothing(), &sync_service_, this, web_data_service_);
+        base::DoNothing(), &sync_service_, &sync_client_,
+        AutofillWalletDataTypeController::PersonalDataManagerProvider(),
+        web_data_service_);
 
     last_type_ = syncer::UNSPECIFIED;
     last_error_ = syncer::SyncError();
@@ -108,14 +112,6 @@
     syncable_service_.StopSyncing(syncer::AUTOFILL_WALLET_DATA);
   }
 
-  // FakeSyncClient overrides.
-  PrefService* GetPrefService() override { return &prefs_; }
-
-  base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
-      syncer::ModelType type) override {
-    return syncable_service_.AsWeakPtr();
-  }
-
  protected:
   void SetStartExpectations() {
     autofill_wallet_dtc_->SetGenericChangeProcessorFactoryForTest(
@@ -147,10 +143,10 @@
   TestingPrefServiceSimple prefs_;
   syncer::FakeSyncService sync_service_;
   syncer::StartCallbackMock start_callback_;
-  syncer::SyncApiComponentFactoryMock profile_sync_factory_;
   syncer::FakeSyncableService syncable_service_;
   std::unique_ptr<AutofillWalletDataTypeController> autofill_wallet_dtc_;
   scoped_refptr<FakeWebDataService> web_data_service_;
+  testing::NiceMock<syncer::SyncClientMock> sync_client_;
 
   syncer::ModelType last_type_;
   syncer::SyncError last_error_;
@@ -183,8 +179,8 @@
   EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state());
   EXPECT_FALSE(last_error_.IsSet());
   EXPECT_EQ(syncer::AUTOFILL_WALLET_DATA, last_type_);
-  autofill::prefs::SetPaymentsIntegrationEnabled(GetPrefService(), false);
-  autofill::prefs::SetCreditCardAutofillEnabled(GetPrefService(), true);
+  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false);
+  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(last_error_.IsSet());
 }
@@ -202,8 +198,8 @@
   EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state());
   EXPECT_FALSE(last_error_.IsSet());
   EXPECT_EQ(syncer::AUTOFILL_WALLET_DATA, last_type_);
-  autofill::prefs::SetPaymentsIntegrationEnabled(GetPrefService(), true);
-  autofill::prefs::SetCreditCardAutofillEnabled(GetPrefService(), false);
+  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true);
+  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(last_error_.IsSet());
 }
@@ -212,8 +208,8 @@
        DatatypeDisabledByWalletImportAtStartup) {
   SetStartExpectations();
   web_data_service_->LoadDatabase();
-  autofill::prefs::SetPaymentsIntegrationEnabled(GetPrefService(), false);
-  autofill::prefs::SetCreditCardAutofillEnabled(GetPrefService(), true);
+  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false);
+  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true);
   EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
             autofill_wallet_dtc_->state());
   Start();
@@ -225,8 +221,8 @@
        DatatypeDisabledByCreditCardsAtStartup) {
   SetStartExpectations();
   web_data_service_->LoadDatabase();
-  autofill::prefs::SetPaymentsIntegrationEnabled(GetPrefService(), true);
-  autofill::prefs::SetCreditCardAutofillEnabled(GetPrefService(), false);
+  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true);
+  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false);
   EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
             autofill_wallet_dtc_->state());
   Start();
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 41e89b52..efca6b0 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -2690,7 +2690,7 @@
 }
 
 bool PersonalDataManager::ProfileChangesAreOnGoing() {
-  for (auto task : ongoing_profile_changes_) {
+  for (const auto& task : ongoing_profile_changes_) {
     if (ProfileChangesAreOnGoing(task.first)) {
       return true;
     }
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 48bc4cd..95c5ac0 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -168,8 +168,7 @@
   virtual void RemoveByGUID(const std::string& guid);
 
   // Returns the profile with the specified |guid|, or nullptr if there is no
-  // profile with the specified |guid|. Both web and auxiliary profiles may
-  // be returned.
+  // profile with the specified |guid|.
   virtual AutofillProfile* GetProfileByGUID(const std::string& guid);
 
   // Returns the profile with the specified |guid| from the given |profiles|, or
@@ -391,9 +390,6 @@
   // Records the sync transport consent if the user is in sync transport mode.
   virtual void OnUserAcceptedUpstreamOffer();
 
-  // Triggered when a profile is added/updated/removed on db.
-  void OnAutofillProfileChanged(const AutofillProfileDeepChange& change);
-
   void set_client_profile_validator_for_test(
       AutofillProfileValidator* validator) {
     client_profile_validator_ = validator;
@@ -407,8 +403,6 @@
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            AddCreditCard_CrazyCharacters);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, AddCreditCard_Invalid);
-  FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, FirstMiddleLast);
-  FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AutofillIsEnabledAtStartup);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            DedupeProfiles_ProfilesToDelete);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
@@ -453,8 +447,6 @@
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            DoNotConvertWalletAddressesInEphemeralStorage);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
-                           DeleteDisusedCreditCards_OncePerVersion);
-  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            DeleteDisusedCreditCards_DoNothingWhenDisabled);
   FRIEND_TEST_ALL_PREFIXES(
       PersonalDataManagerTest,
@@ -482,12 +474,6 @@
                            RequestProfileServerValidity);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            GetProfileSuggestions_Validity);
-  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerMockTest,
-                           UpdateProfilesValidityStates_MoveToJapan);
-  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerMockTest,
-                           UpdateProfilesValidityStates_AddUpdateSet);
-  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerMockTest,
-                           UpdateProfilesValidityStates_Dedupe);
 
   friend class autofill::AutofillInteractiveTest;
   friend class autofill::PersonalDataManagerFactory;
@@ -599,15 +585,11 @@
   std::vector<std::unique_ptr<AutofillProfile>> web_profiles_;
 
   // Profiles read from the user's account stored on the server.
-  mutable std::vector<std::unique_ptr<AutofillProfile>> server_profiles_;
+  std::vector<std::unique_ptr<AutofillProfile>> server_profiles_;
 
   // Stores the PaymentsCustomerData obtained from the database.
   std::unique_ptr<PaymentsCustomerData> payments_customer_data_;
 
-  // Storage for web profiles.  Contents are weak references.  Lifetime managed
-  // by |web_profiles_|.
-  mutable std::vector<AutofillProfile*> profiles_;
-
   // Cached versions of the local and server credit cards.
   std::vector<std::unique_ptr<CreditCard>> local_credit_cards_;
   std::vector<std::unique_ptr<CreditCard>> server_credit_cards_;
@@ -750,6 +732,9 @@
   void UpdateProfileInDB(const AutofillProfile& profile, bool enforced = false);
   void RemoveProfileFromDB(const std::string& guid);
 
+  // Triggered when a profile is added/updated/removed on db.
+  void OnAutofillProfileChanged(const AutofillProfileDeepChange& change);
+
   // Look at the next profile change for profile with guid = |guid|, and handle
   // it.
   void HandleNextProfileChange(const std::string& guid);
diff --git a/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc b/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
index f05cd122..bd2bff7 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
@@ -27,6 +27,7 @@
     const base::Closure& dump_stack,
     syncer::SyncService* sync_service,
     syncer::SyncClient* sync_client,
+    const PersonalDataManagerProvider& pdm_provider,
     const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
     : AsyncDirectoryTypeController(syncer::AUTOFILL_PROFILE,
                                    dump_stack,
@@ -34,6 +35,7 @@
                                    sync_client,
                                    syncer::GROUP_DB,
                                    std::move(db_thread)),
+      pdm_provider_(pdm_provider),
       web_data_service_(web_data_service),
       callback_registered_(false),
       currently_enabled_(IsEnabled()) {
@@ -53,7 +55,7 @@
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(state(), MODEL_STARTING);
 
-  sync_client()->GetPersonalDataManager()->RemoveObserver(this);
+  pdm_provider_.Run()->RemoveObserver(this);
 
   if (!web_data_service_)
     return;
@@ -78,8 +80,7 @@
     DisableForPolicy();
     return false;
   }
-  autofill::PersonalDataManager* personal_data =
-      sync_client()->GetPersonalDataManager();
+  autofill::PersonalDataManager* personal_data = pdm_provider_.Run();
 
   // Make sure PDM has the sync service. This is needed because in the account
   // wallet data mode, PDM uses the service to determine whether to use the
@@ -118,7 +119,7 @@
 
 void AutofillProfileDataTypeController::StopModels() {
   DCHECK(CalledOnValidThread());
-  sync_client()->GetPersonalDataManager()->RemoveObserver(this);
+  pdm_provider_.Run()->RemoveObserver(this);
 }
 
 bool AutofillProfileDataTypeController::ReadyForStart() const {
diff --git a/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h b/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h
index b2886eea..4641b0d2 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h
+++ b/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -16,6 +17,7 @@
 
 namespace autofill {
 class AutofillWebDataService;
+class PersonalDataManager;
 }  // namespace autofill
 
 namespace syncer {
@@ -30,12 +32,16 @@
     : public syncer::AsyncDirectoryTypeController,
       public autofill::PersonalDataManagerObserver {
  public:
+  using PersonalDataManagerProvider =
+      base::RepeatingCallback<autofill::PersonalDataManager*()>;
+
   // |dump_stack| is called when an unrecoverable error occurs.
   AutofillProfileDataTypeController(
       scoped_refptr<base::SingleThreadTaskRunner> db_thread,
       const base::Closure& dump_stack,
       syncer::SyncService* sync_service,
       syncer::SyncClient* sync_client,
+      const PersonalDataManagerProvider& pdm_provider,
       const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
   ~AutofillProfileDataTypeController() override;
 
@@ -61,6 +67,9 @@
   // Report an error (which will stop the datatype asynchronously).
   void DisableForPolicy();
 
+  // Callback that allows accessing PersonalDataManager lazily.
+  const PersonalDataManagerProvider pdm_provider_;
+
   // A reference to the AutofillWebDataService for this controller.
   scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
 
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index e11a6c70..88cc8c5 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -196,7 +196,7 @@
     return;
 
   DCHECK_NE(state_, AutofillAssistantState::STOPPED)
-      << "Unexpected transition from STOPPED to " << static_cast<int>(state);
+      << "Unexpected transition from " << state_ << " to " << state;
 
   state_ = state;
   GetUiController()->OnStateChanged(state);
@@ -540,8 +540,8 @@
 void Controller::OnFatalError(const std::string& error_message,
                               Metrics::DropOutReason reason) {
   LOG(ERROR) << "Autofill Assistant has encountered an error and is shutting "
-                "down. Reason: "
-             << static_cast<int>(reason);
+                "down, reason="
+             << reason;
   if (state_ == AutofillAssistantState::STOPPED)
     return;
 
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h
index f8fbf27..b3dd17e6 100644
--- a/components/autofill_assistant/browser/metrics.h
+++ b/components/autofill_assistant/browser/metrics.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_METRICS_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_METRICS_H_
 
+#include <ostream>
+
 namespace autofill_assistant {
 
 // A class to generate Autofill Assistant related histograms.
@@ -37,6 +39,76 @@
   };
 
   static void RecordDropOut(DropOutReason reason);
+
+  // Intended for debugging: writes string representation of |reason| to |out|.
+  friend std::ostream& operator<<(std::ostream& out,
+                                  const DropOutReason& reason) {
+#ifdef NDEBUG
+    // Non-debugging builds write the enum number.
+    out << static_cast<int>(reason);
+    return out;
+#else
+    // Debugging builds write a string representation of |reason|.
+    switch (reason) {
+      case AA_START:
+        out << "AA_START";
+        break;
+      case AUTOSTART_TIMEOUT:
+        out << "AUTOSTART_TIMEOUT";
+        break;
+      case NO_SCRIPTS:
+        out << "NO_SCRIPTS";
+        break;
+      case CUSTOM_TAB_CLOSED:
+        out << "CUSTOM_TAB_CLOSED";
+        break;
+      case DECLINED:
+        out << "DECLINED";
+        break;
+      case SHEET_CLOSED:
+        out << "SHEET_CLOSED";
+        break;
+      case SCRIPT_FAILED:
+        out << "SCRIPT_FAILED";
+        break;
+      case NAVIGATION:
+        out << "NAVIGATION";
+        break;
+      case OVERLAY_STOP:
+        out << "OVERLAY_STOP";
+        break;
+      case PR_FAILED:
+        out << "PR_FAILED";
+        break;
+      case CONTENT_DESTROYED:
+        out << "CONTENT_DESTROYED";
+        break;
+      case RENDER_PROCESS_GONE:
+        out << "RENDER_PROCESS_GONE";
+        break;
+      case INTERSTITIAL_PAGE:
+        out << "INTERSTITIAL_PAGE";
+        break;
+      case SCRIPT_SHUTDOWN:
+        out << "SCRIPT_SHUTDOWN";
+        break;
+      case SAFETY_NET_TERMINATE:
+        out << "SAFETY_NET_TERMINATE";
+        break;
+      case TAB_DETACHED:
+        out << "TAB_DETACHED";
+        break;
+      case TAB_CHANGED:
+        out << "TAB_CHANGED";
+        break;
+      case NUM_ENTRIES:
+        out << "NUM_ENTRIES";
+        // Intentionally no default case to make compilation fail if a new value
+        // was added to the enum but not to this list.
+    }
+    return out;
+#endif  // NDEBUG
+  }
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/selector.cc b/components/autofill_assistant/browser/selector.cc
index 2f4b06b..6e41fa6 100644
--- a/components/autofill_assistant/browser/selector.cc
+++ b/components/autofill_assistant/browser/selector.cc
@@ -4,6 +4,8 @@
 
 #include "components/autofill_assistant/browser/selector.h"
 
+#include "base/strings/string_util.h"
+
 namespace autofill_assistant {
 
 Selector::Selector() : pseudo_type(PseudoType::UNDEFINED) {}
@@ -41,4 +43,14 @@
   return this->selectors.empty();
 }
 
-}  // namespace autofill_assistant
\ No newline at end of file
+std::ostream& operator<<(std::ostream& out, const Selector& selector) {
+#ifdef NDEBUG
+  out << selector.selectors.size() << " element(s)";
+  return out;
+#else
+  out << "elements=[" << base::JoinString(selector.selectors, ",") << "]";
+  return out;
+#endif  // NDEBUG
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/selector.h b/components/autofill_assistant/browser/selector.h
index 713828b..686d0d9 100644
--- a/components/autofill_assistant/browser/selector.h
+++ b/components/autofill_assistant/browser/selector.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SELECTOR_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SELECTOR_H_
 
+#include <ostream>
 #include <string>
 #include <vector>
 
@@ -39,6 +40,10 @@
   bool operator<(const Selector& other) const;
   bool operator==(const Selector& other) const;
 
+  // The output operator. The actual selectors are only available in debug
+  // builds.
+  friend std::ostream& operator<<(std::ostream& out, const Selector& selector);
+
   // Checks whether this selector is empty.
   bool empty() const;
 };
diff --git a/components/autofill_assistant/browser/state.h b/components/autofill_assistant/browser/state.h
index e6a770f..d0ff42d 100644
--- a/components/autofill_assistant/browser/state.h
+++ b/components/autofill_assistant/browser/state.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STATE_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STATE_H_
 
+#include <ostream>
+
 namespace autofill_assistant {
 
 // High-level states the Autofill Assistant can be in.
@@ -47,6 +49,43 @@
   STOPPED
 };
 
+inline std::ostream& operator<<(std::ostream& out,
+                                const AutofillAssistantState& state) {
+#ifdef NDEBUG
+  // Non-debugging builds write the enum number.
+  out << static_cast<int>(state);
+  return out;
+#else
+  // Debugging builds write a string representation of |state|.
+  switch (state) {
+    case AutofillAssistantState::INACTIVE:
+      out << "INACTIVE";
+      break;
+    case AutofillAssistantState::STARTING:
+      out << "STARTING";
+      break;
+    case AutofillAssistantState::RUNNING:
+      out << "RUNNING";
+      break;
+    case AutofillAssistantState::PROMPT:
+      out << "PROMPT";
+      break;
+    case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT:
+      out << "AUTOSTART_FALLBACK_PROMPT";
+      break;
+    case AutofillAssistantState::MODAL_DIALOG:
+      out << "MODAL_DIALOG";
+      break;
+    case AutofillAssistantState::STOPPED:
+      out << "STOPPED";
+      break;
+      // Intentionally no default case to make compilation fail if a new value
+      // was added to the enum but not to this list.
+  }
+  return out;
+#endif  // NDEBUG
+}
+
 }  // namespace autofill_assistant
 
 #endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STATE_H_
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web_controller.cc
index 805648a..2e214e34 100644
--- a/components/autofill_assistant/browser/web_controller.cc
+++ b/components/autofill_assistant/browser/web_controller.cc
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/i18n/char_iterator.h"
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
@@ -253,7 +254,7 @@
 void WebController::ElementPositionGetter::OnGetBoxModelForStableCheck(
     std::unique_ptr<dom::GetBoxModelResult> result) {
   if (!result || !result->GetModel() || !result->GetModel()->GetContent()) {
-    DVLOG(1) << "Failed to get box model.";
+    DVLOG(1) << __func__ << " Failed to get box model.";
     OnError();
     return;
   }
@@ -324,7 +325,7 @@
 void WebController::ElementPositionGetter::OnScrollIntoView(
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result || result->HasExceptionDetails()) {
-    DVLOG(1) << "Failed to scroll the element.";
+    DVLOG(1) << __func__ << " Failed to scroll the element.";
     OnError();
     return;
   }
@@ -376,12 +377,14 @@
 }
 
 void WebController::LoadURL(const GURL& url) {
+  DVLOG(3) << __func__ << " " << url;
   web_contents_->GetController().LoadURLWithParams(
       content::NavigationController::LoadURLParams(url));
 }
 
 void WebController::ClickOrTapElement(const Selector& selector,
                                       base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector;
 #if defined(OS_ANDROID)
   TapElement(selector, std::move(callback));
 #else
@@ -415,7 +418,7 @@
     std::unique_ptr<FindElementResult> result) {
   // Found element must belong to a frame.
   if (!result->container_frame_host || result->object_id.empty()) {
-    DVLOG(1) << "Failed to find the element to click or tap.";
+    DVLOG(1) << __func__ << " Failed to find the element to click or tap.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -449,7 +452,7 @@
     bool is_a_click,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result || result->HasExceptionDetails()) {
-    DVLOG(1) << "Failed to scroll the element.";
+    DVLOG(1) << __func__ << " Failed to scroll the element.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -472,7 +475,7 @@
     int x,
     int y) {
   if (!has_coordinates) {
-    DVLOG(1) << "Failed to get element position.";
+    DVLOG(1) << __func__ << " Failed to get element position.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -511,7 +514,8 @@
     int y,
     std::unique_ptr<input::DispatchMouseEventResult> result) {
   if (!result) {
-    DVLOG(1) << "Failed to dispatch mouse left button pressed event.";
+    DVLOG(1) << __func__
+             << " Failed to dispatch mouse left button pressed event.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -538,7 +542,7 @@
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<input::DispatchTouchEventResult> result) {
   if (!result) {
-    DVLOG(1) << "Failed to dispatch touch start event.";
+    DVLOG(1) << __func__ << " Failed to dispatch touch start event.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -621,7 +625,7 @@
   element_result->container_frame_selector_index = 0;
   element_result->object_id = "";
   if (!result || !result->GetResult() || !result->GetResult()->HasObjectId()) {
-    DVLOG(1) << "Failed to get document root element.";
+    DVLOG(1) << __func__ << " Failed to get document root element.";
     std::move(callback).Run(std::move(element_result));
     return;
   }
@@ -716,7 +720,7 @@
     FindElementCallback callback,
     std::unique_ptr<dom::DescribeNodeResult> result) {
   if (!result || !result->GetNode()) {
-    DVLOG(1) << "Failed to describe the node for pseudo element.";
+    DVLOG(1) << __func__ << " Failed to describe the node for pseudo element.";
     std::move(callback).Run(std::move(element_result));
     return;
   }
@@ -762,7 +766,7 @@
     FindElementCallback callback,
     std::unique_ptr<dom::DescribeNodeResult> result) {
   if (!result || !result->GetNode()) {
-    DVLOG(1) << "Failed to describe the node.";
+    DVLOG(1) << __func__ << " Failed to describe the node.";
     std::move(callback).Run(std::move(element_result));
     return;
   }
@@ -793,7 +797,7 @@
     element_result->container_frame_host = FindCorrespondingRenderFrameHost(
         frame_name, node->GetContentDocument()->GetDocumentURL());
     if (!element_result->container_frame_host) {
-      DVLOG(1) << "Failed to find corresponding owner frame.";
+      DVLOG(1) << __func__ << " Failed to find corresponding owner frame.";
       std::move(callback).Run(std::move(element_result));
       return;
     }
@@ -834,7 +838,7 @@
     FindElementCallback callback,
     std::unique_ptr<dom::ResolveNodeResult> result) {
   if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
-    DVLOG(1) << "Failed to resolve object id from backend id.";
+    DVLOG(1) << __func__ << " Failed to resolve object id from backend id.";
     std::move(callback).Run(std::move(element_result));
     return;
   }
@@ -875,7 +879,7 @@
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<FindElementResult> element_result) {
   if (element_result->object_id.empty()) {
-    DVLOG(1) << "Failed to find the element to focus on.";
+    DVLOG(1) << __func__ << " Failed to find the element to focus on.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -899,7 +903,7 @@
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result || result->HasExceptionDetails()) {
-    DVLOG(1) << "Failed to focus on element.";
+    DVLOG(1) << __func__ << " Failed to focus on element.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -909,6 +913,7 @@
 void WebController::FillAddressForm(const autofill::AutofillProfile* profile,
                                     const Selector& selector,
                                     base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << selector;
   auto data_to_autofill = std::make_unique<FillFormInputData>();
   data_to_autofill->profile =
       std::make_unique<autofill::AutofillProfile>(*profile);
@@ -926,7 +931,7 @@
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<FindElementResult> element_result) {
   if (element_result->object_id.empty()) {
-    DVLOG(1) << "Failed to find the element for filling the form.";
+    DVLOG(1) << __func__ << " Failed to find the element for filling the form.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -952,7 +957,7 @@
     const autofill::FormData& form_data,
     const autofill::FormFieldData& form_field) {
   if (form_data.fields.empty()) {
-    DVLOG(1) << "Failed to get form data to fill form.";
+    DVLOG(1) << __func__ << " Failed to get form data to fill form.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -960,7 +965,7 @@
   ContentAutofillDriver* driver =
       ContentAutofillDriver::GetForRenderFrameHost(container_frame_host);
   if (!driver) {
-    DVLOG(1) << "Failed to get the autofill driver.";
+    DVLOG(1) << __func__ << " Failed to get the autofill driver.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -981,6 +986,7 @@
                                  const base::string16& cvc,
                                  const Selector& selector,
                                  base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector;
   auto data_to_autofill = std::make_unique<FillFormInputData>();
   data_to_autofill->card = std::move(card);
   data_to_autofill->cvc = cvc;
@@ -995,6 +1001,7 @@
 void WebController::SelectOption(const Selector& selector,
                                  const std::string& selected_option,
                                  base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector << ", option=" << selected_option;
   FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForSelectOption,
@@ -1008,7 +1015,7 @@
     std::unique_ptr<FindElementResult> element_result) {
   const std::string object_id = element_result->object_id;
   if (object_id.empty()) {
-    DVLOG(1) << "Failed to find the element to select an option.";
+    DVLOG(1) << __func__ << " Failed to find the element to select an option.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -1033,7 +1040,7 @@
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result || result->HasExceptionDetails()) {
-    DVLOG(1) << "Failed to select option.";
+    DVLOG(1) << __func__ << " Failed to select option.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -1045,6 +1052,7 @@
 
 void WebController::HighlightElement(const Selector& selector,
                                      base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector;
   FindElement(
       selector,
       /* strict_mode= */ true,
@@ -1057,7 +1065,7 @@
     std::unique_ptr<FindElementResult> element_result) {
   const std::string object_id = element_result->object_id;
   if (object_id.empty()) {
-    DVLOG(1) << "Failed to find the element to highlight.";
+    DVLOG(1) << __func__ << " Failed to find the element to highlight.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -1080,7 +1088,7 @@
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result || result->HasExceptionDetails()) {
-    DVLOG(1) << "Failed to highlight element.";
+    DVLOG(1) << __func__ << " Failed to highlight element.";
     OnResult(false, std::move(callback));
     return;
   }
@@ -1091,6 +1099,7 @@
 
 void WebController::FocusElement(const Selector& selector,
                                  base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector;
   DCHECK(!selector.empty());
   FindElement(
       selector,
@@ -1146,6 +1155,8 @@
                                   const std::string& value,
                                   bool simulate_key_presses,
                                   base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector << ", value=" << value
+           << ", simulate_key_presses=" << simulate_key_presses;
   if (simulate_key_presses) {
     std::vector<std::string> utf8_chars;
     base::i18n::UTF8CharIterator iter(&value);
@@ -1153,7 +1164,8 @@
       wchar_t wide_char = iter.get();
       std::string utf8_char;
       if (!base::WideToUTF8(&wide_char, 1, &utf8_char)) {
-        DVLOG(1) << "Failed to convert character to UTF-8: " << wide_char;
+        DVLOG(1) << __func__
+                 << " Failed to convert character to UTF-8: " << wide_char;
         OnResult(false, std::move(callback));
         return;
       }
@@ -1291,6 +1303,9 @@
                                  const std::vector<std::string>& attribute,
                                  const std::string& value,
                                  base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector << ", attribute=["
+           << base::JoinString(attribute, ",") << "], value=" << value;
+
   DCHECK(!selector.empty());
   DCHECK_GT(attribute.size(), 0u);
   FindElement(selector,
@@ -1345,6 +1360,8 @@
     const Selector& selector,
     const std::vector<std::string>& utf8_chars,
     base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " " << selector
+           << ", input=" << base::JoinString(utf8_chars, "");
   DCHECK(!selector.empty());
   FindElement(selector,
               /* strict_mode= */ true,
@@ -1367,6 +1384,7 @@
 void WebController::GetOuterHtml(
     const Selector& selector,
     base::OnceCallback<void(bool, const std::string&)> callback) {
+  DVLOG(3) << __func__ << " " << selector;
   FindElement(
       selector,
       /* strict_mode= */ true,
@@ -1450,6 +1468,7 @@
     std::unique_ptr<FindElementResult> element_result) {
   const std::string object_id = element_result->object_id;
   if (object_id.empty()) {
+    DVLOG(2) << __func__ << " Failed to find element for GetOuterHtml";
     OnResult(false, "", std::move(callback));
     return;
   }
@@ -1468,6 +1487,7 @@
     base::OnceCallback<void(bool, const std::string&)> callback,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result || result->HasExceptionDetails()) {
+    DVLOG(2) << __func__ << " Failed to find element for GetOuterHtml";
     OnResult(false, "", std::move(callback));
     return;
   }
@@ -1480,6 +1500,7 @@
 
 void WebController::SetCookie(const std::string& domain,
                               base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__ << " domain=" << domain;
   DCHECK(!domain.empty());
   auto expires_seconds =
       std::chrono::seconds(std::time(nullptr)).count() + kCookieExpiresSeconds;
@@ -1501,6 +1522,7 @@
 }
 
 void WebController::HasCookie(base::OnceCallback<void(bool)> callback) {
+  DVLOG(3) << __func__;
   devtools_client_->GetNetwork()->GetCookies(
       base::BindOnce(&WebController::OnHasCookie,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -1526,6 +1548,7 @@
 }
 
 void WebController::ClearCookie() {
+  DVLOG(3) << __func__;
   devtools_client_->GetNetwork()->DeleteCookies(kAutofillAssistantCookieName,
                                                 base::DoNothing());
 }
diff --git a/components/browser_sync/BUILD.gn b/components/browser_sync/BUILD.gn
index fef1dd0..4265fc59 100644
--- a/components/browser_sync/BUILD.gn
+++ b/components/browser_sync/BUILD.gn
@@ -6,6 +6,8 @@
 
 static_library("browser_sync") {
   sources = [
+    "browser_sync_client.cc",
+    "browser_sync_client.h",
     "browser_sync_switches.cc",
     "browser_sync_switches.h",
     "profile_sync_components_factory_impl.cc",
diff --git a/components/browser_sync/abstract_profile_sync_service_test.cc b/components/browser_sync/abstract_profile_sync_service_test.cc
index b842afd..99656582 100644
--- a/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -143,7 +143,7 @@
       profile_sync_service_bundle_.fake_invalidation_service(),
       sync_service_->sync_prefs()->AsWeakPtr(),
       std::move(initialization_success_callback));
-  EXPECT_CALL(*components, CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*components, CreateSyncEngine(_, _, _))
       .WillOnce(Return(ByMove(std::move(engine))));
 
   sync_service_->sync_prefs()->SetFirstSetupComplete();
diff --git a/components/browser_sync/browser_sync_client.cc b/components/browser_sync/browser_sync_client.cc
new file mode 100644
index 0000000..9c285221
--- /dev/null
+++ b/components/browser_sync/browser_sync_client.cc
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/browser_sync/browser_sync_client.h"
+
+#include "components/sync/model/model_type_store_service.h"
+
+namespace browser_sync {
+
+BrowserSyncClient::BrowserSyncClient() = default;
+
+BrowserSyncClient::~BrowserSyncClient() = default;
+
+base::FilePath BrowserSyncClient::GetSyncDataPath() {
+  return GetModelTypeStoreService()->GetSyncDataPath();
+}
+
+}  // namespace browser_sync
diff --git a/components/browser_sync/browser_sync_client.h b/components/browser_sync/browser_sync_client.h
new file mode 100644
index 0000000..4357047
--- /dev/null
+++ b/components/browser_sync/browser_sync_client.h
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_CLIENT_H_
+#define COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_CLIENT_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/model/model_type_controller_delegate.h"
+
+class BookmarkUndoService;
+
+namespace autofill {
+class PersonalDataManager;
+}  // namespace autofill
+
+namespace bookmarks {
+class BookmarkModel;
+}  // namespace bookmarks
+
+namespace favicon {
+class FaviconService;
+}  // namespace favicon
+
+namespace history {
+class HistoryService;
+}  // namespace history
+
+namespace syncer {
+class ModelTypeStoreService;
+}  // namespace syncer
+
+namespace browser_sync {
+
+// Extension to interface syncer::SyncClient to bundle dependencies that
+// sync-the-feature requires for datatypes common to all platforms.
+// Note: on some platforms, getters might return nullptr. Callers are expected
+// to handle these scenarios gracefully.
+class BrowserSyncClient : public syncer::SyncClient {
+ public:
+  BrowserSyncClient();
+  ~BrowserSyncClient() override;
+
+  base::FilePath GetSyncDataPath() final;
+  virtual syncer::ModelTypeStoreService* GetModelTypeStoreService() = 0;
+
+  // Returns a weak pointer to the ModelTypeControllerDelegate specified by
+  // |type|. Weak pointer may be unset if service is already destroyed.
+  virtual base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetControllerDelegateForModelType(syncer::ModelType type) = 0;
+
+  // DataType specific service getters.
+  virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0;
+  virtual favicon::FaviconService* GetFaviconService() = 0;
+  virtual history::HistoryService* GetHistoryService() = 0;
+  virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
+  virtual BookmarkUndoService* GetBookmarkUndoService() = 0;
+  virtual base::RepeatingClosure GetPasswordStateChangedCallback() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrowserSyncClient);
+};
+
+}  // namespace browser_sync
+
+#endif  // COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_CLIENT_H_
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 911fc67..a624a77 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/browser_sync/browser_sync_client.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/history/core/browser/sync/history_delete_directives_data_type_controller.h"
@@ -37,7 +38,6 @@
 #include "components/sync/driver/data_type_manager_impl.h"
 #include "components/sync/driver/glue/sync_engine_impl.h"
 #include "components/sync/driver/model_type_controller.h"
-#include "components/sync/driver/sync_client.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/driver/syncable_service_based_model_type_controller.h"
 #include "components/sync/engine/sync_engine.h"
@@ -107,7 +107,7 @@
 }  // namespace
 
 ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
-    syncer::SyncClient* sync_client,
+    browser_sync::BrowserSyncClient* sync_client,
     version_info::Channel channel,
     const char* history_disabled_pref,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
@@ -126,7 +126,9 @@
       web_data_service_on_disk_(web_data_service_on_disk),
       web_data_service_in_memory_(web_data_service_in_memory),
       password_store_(password_store),
-      bookmark_sync_service_(bookmark_sync_service) {}
+      bookmark_sync_service_(bookmark_sync_service) {
+  DCHECK(sync_client_);
+}
 
 ProfileSyncComponentsFactoryImpl::~ProfileSyncComponentsFactoryImpl() {}
 
@@ -135,6 +137,7 @@
     syncer::ModelTypeSet disabled_types,
     syncer::SyncService* sync_service) {
   syncer::DataTypeController::TypeVector controllers;
+
   const base::RepeatingClosure dump_stack =
       base::BindRepeating(&syncer::ReportUnrecoverableError, channel_);
 
@@ -180,6 +183,8 @@
         controllers.push_back(
             std::make_unique<AutofillProfileDataTypeController>(
                 db_thread_, dump_stack, sync_service, sync_client_,
+                base::BindRepeating(&BrowserSyncClient::GetPersonalDataManager,
+                                    base::Unretained(sync_client_)),
                 web_data_service_on_disk_));
       }
     }
@@ -198,7 +203,10 @@
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
                 syncer::AUTOFILL_WALLET_DATA, db_thread_, dump_stack,
-                sync_service, sync_client_, web_data_service_on_disk_));
+                sync_service, sync_client_,
+                base::BindRepeating(&BrowserSyncClient::GetPersonalDataManager,
+                                    base::Unretained(sync_client_)),
+                web_data_service_on_disk_));
       }
     }
 
@@ -216,7 +224,10 @@
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
                 syncer::AUTOFILL_WALLET_METADATA, db_thread_, dump_stack,
-                sync_service, sync_client_, web_data_service_on_disk_));
+                sync_service, sync_client_,
+                base::BindRepeating(&BrowserSyncClient::GetPersonalDataManager,
+                                    base::Unretained(sync_client_)),
+                web_data_service_on_disk_));
       }
     }
   }
@@ -235,7 +246,8 @@
                                   sync_client_->GetFaviconService()))));
     } else {
       controllers.push_back(std::make_unique<BookmarkDataTypeController>(
-          dump_stack, sync_service, sync_client_));
+          dump_stack, sync_service, sync_client_->GetBookmarkModel(),
+          sync_client_->GetHistoryService(), this));
     }
   }
 
@@ -258,7 +270,8 @@
               switches::kSyncPseudoUSSHistoryDeleteDirectives)) {
         controllers.push_back(
             std::make_unique<HistoryDeleteDirectivesModelTypeController>(
-                dump_stack, sync_service, sync_client_));
+                dump_stack, sync_service,
+                sync_client_->GetModelTypeStoreService(), sync_client_));
 
       } else {
         controllers.push_back(
@@ -324,14 +337,15 @@
       controllers.push_back(
           std::make_unique<password_manager::PasswordModelTypeController>(
               password_store_->CreateSyncControllerDelegate(), sync_service,
-              sync_client_));
+              sync_client_->GetPasswordStateChangedCallback()));
     } else if (base::FeatureList::IsEnabled(
                    switches::kSyncPseudoUSSPasswords)) {
       controllers.push_back(
           std::make_unique<password_manager::
                                PasswordSyncableServiceBasedModelTypeController>(
               sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
-              dump_stack, password_store_, sync_service, sync_client_));
+              dump_stack, password_store_, sync_service, sync_client_,
+              sync_client_->GetPasswordStateChangedCallback()));
     } else {
       controllers.push_back(std::make_unique<PasswordDataTypeController>(
           dump_stack, sync_service, sync_client_,
@@ -399,6 +413,9 @@
         syncer::USER_EVENTS));
   }
 
+  // TODO(crbug.com/919489): Enable security events once their controller
+  // delegate is wired properly.
+
   // Forward both on-disk and in-memory storage modes to the same delegate,
   // since behavior for USER_CONSENTS does not differ (they are always
   // persisted).
@@ -408,16 +425,16 @@
       syncer::USER_CONSENTS,
       /*delegate_on_disk=*/
       std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
-          ui_thread_,
-          base::BindRepeating(
-              &syncer::SyncClient::GetControllerDelegateForModelType,
-              base::Unretained(sync_client_), syncer::USER_CONSENTS)),
+          ui_thread_, base::BindRepeating(&browser_sync::BrowserSyncClient::
+                                              GetControllerDelegateForModelType,
+                                          base::Unretained(sync_client_),
+                                          syncer::USER_CONSENTS)),
       /*delegate_in_memory=*/
       std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
-          ui_thread_,
-          base::BindRepeating(
-              &syncer::SyncClient::GetControllerDelegateForModelType,
-              base::Unretained(sync_client_), syncer::USER_CONSENTS))));
+          ui_thread_, base::BindRepeating(&browser_sync::BrowserSyncClient::
+                                              GetControllerDelegateForModelType,
+                                          base::Unretained(sync_client_),
+                                          syncer::USER_CONSENTS))));
 
   return controllers;
 }
@@ -440,10 +457,10 @@
 ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
     const std::string& name,
     invalidation::InvalidationService* invalidator,
-    const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
-    const base::FilePath& sync_data_folder) {
-  return std::make_unique<syncer::SyncEngineImpl>(name, invalidator, sync_prefs,
-                                                  sync_data_folder);
+    const base::WeakPtr<syncer::SyncPrefs>& sync_prefs) {
+  return std::make_unique<syncer::SyncEngineImpl>(
+      name, invalidator, sync_prefs,
+      sync_client_->GetModelTypeStoreService()->GetSyncDataPath());
 }
 
 syncer::SyncApiComponentFactory::SyncComponents
@@ -459,12 +476,13 @@
 #endif
 
   auto model_associator = std::make_unique<BookmarkModelAssociator>(
-      bookmark_model, sync_client_, user_share, error_handler->Copy(),
+      bookmark_model, sync_client_->GetBookmarkUndoService(),
+      sync_client_->GetFaviconService(), user_share, error_handler->Copy(),
       kExpectMobileBookmarksFolder);
 
   SyncComponents components;
   components.change_processor = std::make_unique<BookmarkChangeProcessor>(
-      sync_client_, model_associator.get(), std::move(error_handler));
+      model_associator.get(), std::move(error_handler));
   components.model_associator = std::move(model_associator);
   return components;
 }
@@ -484,9 +502,9 @@
   return std::make_unique<ModelTypeController>(
       type, std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
                 ui_thread_,
-                base::BindRepeating(
-                    &syncer::SyncClient::GetControllerDelegateForModelType,
-                    base::Unretained(sync_client_), type)));
+                base::BindRepeating(&browser_sync::BrowserSyncClient::
+                                        GetControllerDelegateForModelType,
+                                    base::Unretained(sync_client_), type)));
 }
 
 std::unique_ptr<ModelTypeController>
diff --git a/components/browser_sync/profile_sync_components_factory_impl.h b/components/browser_sync/profile_sync_components_factory_impl.h
index bcd2b05..c68ccd1 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/components/browser_sync/profile_sync_components_factory_impl.h
@@ -19,7 +19,6 @@
 namespace syncer {
 class ModelTypeController;
 class ModelTypeControllerDelegate;
-class SyncClient;
 class SyncService;
 }
 
@@ -37,11 +36,13 @@
 
 namespace browser_sync {
 
+class BrowserSyncClient;
+
 class ProfileSyncComponentsFactoryImpl
     : public syncer::SyncApiComponentFactory {
  public:
   ProfileSyncComponentsFactoryImpl(
-      syncer::SyncClient* sync_client,
+      BrowserSyncClient* sync_client,
       version_info::Channel channel,
       const char* history_disabled_pref,
       const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
@@ -54,10 +55,14 @@
       sync_bookmarks::BookmarkSyncService* bookmark_sync_service);
   ~ProfileSyncComponentsFactoryImpl() override;
 
-  // SyncApiComponentFactory implementation:
+  // Creates and returns enabled datatypes and their controllers.
+  // |disabled_types| allows callers to prevent certain types from being
+  // created (e.g. to honor command-line flags).
   syncer::DataTypeController::TypeVector CreateCommonDataTypeControllers(
       syncer::ModelTypeSet disabled_types,
-      syncer::SyncService* sync_service) override;
+      syncer::SyncService* sync_service);
+
+  // SyncApiComponentFactory implementation:
   std::unique_ptr<syncer::DataTypeManager> CreateDataTypeManager(
       syncer::ModelTypeSet initial_types,
       const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
@@ -69,8 +74,7 @@
   std::unique_ptr<syncer::SyncEngine> CreateSyncEngine(
       const std::string& name,
       invalidation::InvalidationService* invalidator,
-      const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
-      const base::FilePath& sync_data_folder) override;
+      const base::WeakPtr<syncer::SyncPrefs>& sync_prefs) override;
   syncer::SyncApiComponentFactory::SyncComponents CreateBookmarkSyncComponents(
       std::unique_ptr<syncer::DataTypeErrorHandler> error_handler,
       syncer::UserShare* user_share) override;
@@ -105,7 +109,7 @@
       syncer::SyncService* sync_service);
 
   // Client/platform specific members.
-  syncer::SyncClient* const sync_client_;
+  BrowserSyncClient* const sync_client_;
   const version_info::Channel channel_;
   const char* history_disabled_pref_;
   const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 733c205..d22cf4e4 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -197,6 +197,7 @@
       weak_factory_(this) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(sync_client_);
+  DCHECK(IsLocalSyncEnabled() || identity_manager_ != nullptr);
 
   // If Sync is disabled via command line flag, then ProfileSyncService
   // shouldn't be instantiated.
@@ -494,8 +495,7 @@
 
   engine_ = sync_client_->GetSyncApiComponentFactory()->CreateSyncEngine(
       debug_identifier_, sync_client_->GetInvalidationService(),
-      sync_prefs_.AsWeakPtr(),
-      sync_client_->GetModelTypeStoreService()->GetSyncDataPath());
+      sync_prefs_.AsWeakPtr());
 
   // Clear any old errors the first time sync starts.
   if (!IsFirstSetupComplete())
@@ -625,9 +625,8 @@
       // the data directory needs to be cleaned up here.
       sync_thread_->task_runner()->PostTask(
           FROM_HERE,
-          base::BindOnce(
-              &syncer::syncable::Directory::DeleteDirectoryFiles,
-              sync_client_->GetModelTypeStoreService()->GetSyncDataPath()));
+          base::BindOnce(&syncer::syncable::Directory::DeleteDirectoryFiles,
+                         sync_client_->GetSyncDataPath()));
     }
     return;
   }
diff --git a/components/browser_sync/profile_sync_service_autofill_unittest.cc b/components/browser_sync/profile_sync_service_autofill_unittest.cc
index 29014a89..fcff9d7 100644
--- a/components/browser_sync/profile_sync_service_autofill_unittest.cc
+++ b/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/bind_test_util.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -42,7 +43,9 @@
 #include "components/sync/driver/data_type_controller.h"
 #include "components/sync/driver/data_type_manager_impl.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/engine/data_type_debug_info_listener.h"
+#include "components/sync/engine/sequenced_model_worker.h"
 #include "components/sync/protocol/autofill_specifics.pb.h"
 #include "components/sync/syncable/mutable_entry.h"
 #include "components/sync/syncable/read_node.h"
@@ -82,11 +85,12 @@
 using syncer::syncable::WriterTag;
 using syncer::syncable::WriteTransaction;
 using testing::_;
+using testing::ByMove;
 using testing::DoAll;
 using testing::ElementsAre;
 using testing::Not;
-using testing::SetArgPointee;
 using testing::Return;
+using testing::SetArgPointee;
 
 namespace browser_sync {
 
@@ -369,8 +373,6 @@
         profile_sync_service_bundle()->pref_service()->registry());
 
     data_type_thread()->Start();
-    profile_sync_service_bundle()->set_db_thread(
-        data_type_thread()->task_runner());
 
     web_database_ = std::make_unique<WebDatabaseFake>(&autofill_table_);
     web_data_wrapper_ = std::make_unique<MockWebDataServiceWrapper>(
@@ -398,16 +400,6 @@
                                  /*is_off_the_record=*/false);
 
     web_data_service_->StartSyncableService();
-
-    ProfileSyncServiceBundle::SyncClientBuilder builder(
-        profile_sync_service_bundle());
-    builder.SetPersonalDataManager(personal_data_manager_.get());
-    builder.SetSyncableServiceCallback(base::BindRepeating(
-        &ProfileSyncServiceAutofillTest::GetSyncableServiceForType,
-        base::Unretained(this)));
-    builder.set_activate_model_creation();
-    sync_client_owned_ = builder.Build();
-    sync_client_ = sync_client_owned_.get();
   }
 
   ~ProfileSyncServiceAutofillTest() override {
@@ -434,21 +426,37 @@
     profile_sync_service_bundle()
         ->identity_test_env()
         ->MakePrimaryAccountAvailable("test_user@gmail.com");
-    CreateSyncService(std::move(sync_client_owned_), std::move(callback));
 
-    EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
-                CreateCommonDataTypeControllers(_, _))
-        .WillOnce(testing::InvokeWithoutArgs([=]() {
-          syncer::DataTypeController::TypeVector controllers;
-          controllers.push_back(
-              std::make_unique<AutofillProfileDataTypeController>(
-                  data_type_thread()->task_runner(), base::DoNothing(),
-                  sync_service(), sync_client_, web_data_service_));
-          return controllers;
+    std::unique_ptr<syncer::SyncClientMock> sync_client =
+        profile_sync_service_bundle()->CreateSyncClientMock();
+    syncer::SyncClientMock* sync_client_copy = sync_client.get();
+    CreateSyncService(std::move(sync_client), std::move(callback));
+
+    syncer::DataTypeController::TypeVector controllers;
+    controllers.push_back(std::make_unique<AutofillProfileDataTypeController>(
+        data_type_thread()->task_runner(), /*dump_stack=*/base::DoNothing(),
+        sync_service(), sync_client_copy,
+        base::BindLambdaForTesting([&]() -> autofill::PersonalDataManager* {
+          return personal_data_manager_.get();
+        }),
+        web_data_service_));
+
+    ON_CALL(*sync_client_copy, GetSyncableServiceForType(AUTOFILL_PROFILE))
+        .WillByDefault(testing::Invoke([=](syncer::ModelType) {
+          return AutofillProfileSyncableService::FromWebDataService(
+                     web_data_service_.get())
+              ->AsWeakPtr();
         }));
-    EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
-                CreateDataTypeManager(_, _, _, _, _, _))
-        .WillOnce(ReturnNewDataTypeManagerWithDebugListener(
+    ON_CALL(*sync_client_copy, CreateDataTypeControllers(_))
+        .WillByDefault(Return(ByMove(std::move(controllers))));
+    ON_CALL(*sync_client_copy, CreateModelWorkerForGroup(syncer::GROUP_DB))
+        .WillByDefault(
+            Return(base::MakeRefCounted<syncer::SequencedModelWorker>(
+                data_type_thread()->task_runner(), syncer::GROUP_DB)));
+
+    ON_CALL(*profile_sync_service_bundle()->component_factory(),
+            CreateDataTypeManager(_, _, _, _, _, _))
+        .WillByDefault(ReturnNewDataTypeManagerWithDebugListener(
             syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr())));
 
     EXPECT_CALL(personal_data_manager(), IsDataLoaded())
@@ -526,14 +534,6 @@
  private:
   friend class AddAutofillProfileHelper;
 
-  base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
-      syncer::ModelType type) {
-    DCHECK(type == AUTOFILL_PROFILE);
-    return AutofillProfileSyncableService::FromWebDataService(
-               web_data_service_.get())
-        ->AsWeakPtr();
-  }
-
   AutofillTableMock autofill_table_;
   std::unique_ptr<WebDatabaseFake> web_database_;
   std::unique_ptr<MockWebDataServiceWrapper> web_data_wrapper_;
@@ -541,11 +541,6 @@
   std::unique_ptr<MockPersonalDataManager> personal_data_manager_;
   syncer::DataTypeAssociationStats association_stats_;
   base::WeakPtrFactory<DataTypeDebugInfoListener> debug_ptr_factory_;
-  // |sync_client_owned_| keeps the created client until it is passed to the
-  // created ProfileSyncService. |sync_client_| just keeps a weak reference to
-  // the client the whole time.
-  std::unique_ptr<syncer::FakeSyncClient> sync_client_owned_;
-  syncer::FakeSyncClient* sync_client_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest);
 };
diff --git a/components/browser_sync/profile_sync_service_bookmark_unittest.cc b/components/browser_sync/profile_sync_service_bookmark_unittest.cc
index 457199d..1cf5fbf 100644
--- a/components/browser_sync/profile_sync_service_bookmark_unittest.cc
+++ b/components/browser_sync/profile_sync_service_bookmark_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/containers/queue.h"
 #include "base/containers/stack.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
@@ -37,8 +38,6 @@
 #include "components/bookmarks/managed/managed_bookmark_service.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
-#include "components/browser_sync/profile_sync_test_util.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/engine/engine_util.h"
 #include "components/sync/model/data_type_error_handler.h"
 #include "components/sync/model/data_type_error_handler_mock.h"
@@ -56,6 +55,7 @@
 #include "components/sync/syncable/write_transaction.h"
 #include "components/sync_bookmarks/bookmark_change_processor.h"
 #include "components/sync_bookmarks/bookmark_model_associator.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -355,18 +355,12 @@
 
   ProfileSyncServiceBookmarkTest()
       : managed_bookmark_service_(new bookmarks::ManagedBookmarkService(
-            profile_sync_service_bundle_.pref_service(),
+            &pref_service_,
             base::Bind(ReturnEmptyString))),
         local_merge_result_(syncer::BOOKMARKS),
         syncer_merge_result_(syncer::BOOKMARKS) {
     EXPECT_TRUE(data_dir_.CreateUniqueTempDir());
-    ProfileSyncServiceBundle::SyncClientBuilder builder(
-        &profile_sync_service_bundle_);
-    builder.SetBookmarkModelCallback(base::Bind(
-        &ProfileSyncServiceBookmarkTest::model, base::Unretained(this)));
-    sync_client_ = builder.Build();
-    bookmarks::RegisterProfilePrefs(
-        profile_sync_service_bundle_.pref_service()->registry());
+    bookmarks::RegisterProfilePrefs(pref_service_.registry());
   }
 
   ~ProfileSyncServiceBookmarkTest() override {
@@ -454,8 +448,7 @@
                        false);
     }
 
-    model->Load(profile_sync_service_bundle_.pref_service(), data_path,
-                base::ThreadTaskRunnerHandle::Get(),
+    model->Load(&pref_service_, data_path, base::ThreadTaskRunnerHandle::Get(),
                 base::ThreadTaskRunnerHandle::Get());
     bookmarks::test::WaitForBookmarkModelToLoad(model.get());
     return model;
@@ -548,7 +541,8 @@
 
     // Set up model associator.
     model_associator_ = std::make_unique<BookmarkModelAssociator>(
-        model_.get(), sync_client_.get(), test_user_share_.user_share(),
+        model_.get(), /*bookmark_undo_service=*/nullptr,
+        /*favicon_service=*/nullptr, test_user_share_.user_share(),
         std::make_unique<syncer::DataTypeErrorHandlerMock>(),
         kExpectMobileBookmarks);
 
@@ -795,7 +789,7 @@
         std::make_unique<syncer::DataTypeErrorHandlerMock>();
     mock_error_handler_ = error_handler.get();
     change_processor_ = std::make_unique<BookmarkChangeProcessor>(
-        sync_client_.get(), model_associator_.get(), std::move(error_handler));
+        model_associator_.get(), std::move(error_handler));
   }
 
   syncer::DataTypeErrorHandlerMock* mock_error_handler() {
@@ -815,9 +809,7 @@
  private:
   base::TestMessageLoop message_loop_;
   base::ScopedTempDir data_dir_;
-  ProfileSyncServiceBundle profile_sync_service_bundle_;
-
-  std::unique_ptr<syncer::FakeSyncClient> sync_client_;
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
   std::unique_ptr<BookmarkModel> model_;
   syncer::TestUserShare test_user_share_;
   std::unique_ptr<BookmarkChangeProcessor> change_processor_;
diff --git a/components/browser_sync/profile_sync_service_startup_unittest.cc b/components/browser_sync/profile_sync_service_startup_unittest.cc
index 104a073..4d17637e 100644
--- a/components/browser_sync/profile_sync_service_startup_unittest.cc
+++ b/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/sync/driver/data_type_manager_mock.h"
 #include "components/sync/driver/fake_data_type_controller.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/engine/fake_sync_engine.h"
 #include "components/sync/engine/mock_sync_engine.h"
@@ -77,24 +78,20 @@
   void CreateSyncService(ProfileSyncService::StartBehavior start_behavior,
                          syncer::ModelTypeSet registered_types =
                              syncer::ModelTypeSet(syncer::BOOKMARKS)) {
-    ProfileSyncServiceBundle::SyncClientBuilder builder(
-        &profile_sync_service_bundle_);
-    ProfileSyncService::InitParams init_params =
-        profile_sync_service_bundle_.CreateBasicInitParams(start_behavior,
-                                                           builder.Build());
+    syncer::DataTypeController::TypeVector controllers;
+    for (syncer::ModelType type : registered_types) {
+      controllers.push_back(
+          std::make_unique<syncer::FakeDataTypeController>(type));
+    }
 
-    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_, _))
-        .WillByDefault(InvokeWithoutArgs([=]() {
-          syncer::DataTypeController::TypeVector controllers;
-          for (syncer::ModelType type : registered_types) {
-            controllers.push_back(
-                std::make_unique<syncer::FakeDataTypeController>(type));
-          }
-          return controllers;
-        }));
+    std::unique_ptr<syncer::SyncClientMock> sync_client =
+        profile_sync_service_bundle_.CreateSyncClientMock();
+    ON_CALL(*sync_client, CreateDataTypeControllers(_))
+        .WillByDefault(Return(ByMove(std::move(controllers))));
 
-    sync_service_ =
-        std::make_unique<ProfileSyncService>(std::move(init_params));
+    sync_service_ = std::make_unique<ProfileSyncService>(
+        profile_sync_service_bundle_.CreateBasicInitParams(
+            start_behavior, std::move(sync_client)));
   }
 
   void SimulateTestUserSignin() {
@@ -123,7 +120,7 @@
   FakeSyncEngine* SetUpFakeSyncEngine() {
     auto sync_engine = std::make_unique<FakeSyncEngine>();
     FakeSyncEngine* sync_engine_raw = sync_engine.get();
-    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _))
         .WillByDefault(Return(ByMove(std::move(sync_engine))));
     return sync_engine_raw;
   }
@@ -131,7 +128,7 @@
   MockSyncEngine* SetUpMockSyncEngine() {
     auto sync_engine = std::make_unique<NiceMock<MockSyncEngine>>();
     MockSyncEngine* sync_engine_raw = sync_engine.get();
-    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _))
         .WillByDefault(Return(ByMove(std::move(sync_engine))));
     return sync_engine_raw;
   }
@@ -610,7 +607,7 @@
   // Disable sync through policy.
   sync_prefs()->SetManagedForTest(true);
 
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _)).Times(0);
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _)).Times(0);
   EXPECT_CALL(*component_factory(), CreateDataTypeManager(_, _, _, _, _, _))
       .Times(0);
   sync_service()->Initialize();
diff --git a/components/browser_sync/profile_sync_service_unittest.cc b/components/browser_sync/profile_sync_service_unittest.cc
index 31140e9..525d07b7 100644
--- a/components/browser_sync/profile_sync_service_unittest.cc
+++ b/components/browser_sync/profile_sync_service_unittest.cc
@@ -22,6 +22,7 @@
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/fake_data_type_controller.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/driver/sync_service_observer.h"
 #include "components/sync/driver/sync_token_status.h"
@@ -189,22 +190,20 @@
   void CreateService(ProfileSyncService::StartBehavior behavior) {
     DCHECK(!service_);
 
-    ProfileSyncServiceBundle::SyncClientBuilder builder(
-        &profile_sync_service_bundle_);
-    ProfileSyncService::InitParams init_params =
-        profile_sync_service_bundle_.CreateBasicInitParams(behavior,
-                                                           builder.Build());
-    service_ = std::make_unique<ProfileSyncService>(std::move(init_params));
+    syncer::DataTypeController::TypeVector controllers;
+    controllers.push_back(
+        std::make_unique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
 
-    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_, _))
-        .WillByDefault(testing::InvokeWithoutArgs([=]() {
-          syncer::DataTypeController::TypeVector controllers;
-          controllers.push_back(
-              std::make_unique<syncer::FakeDataTypeController>(
-                  syncer::BOOKMARKS));
-          return controllers;
-        }));
-    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+    std::unique_ptr<syncer::SyncClientMock> sync_client =
+        profile_sync_service_bundle_.CreateSyncClientMock();
+    ON_CALL(*sync_client, CreateDataTypeControllers(_))
+        .WillByDefault(Return(ByMove(std::move(controllers))));
+
+    service_ = std::make_unique<ProfileSyncService>(
+        profile_sync_service_bundle_.CreateBasicInitParams(
+            behavior, std::move(sync_client)));
+
+    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _))
         .WillByDefault(ReturnNewFakeSyncEngine());
     ON_CALL(*component_factory(), CreateDataTypeManager(_, _, _, _, _, _))
         .WillByDefault(
@@ -214,26 +213,25 @@
   void CreateServiceWithLocalSyncBackend() {
     DCHECK(!service_);
 
-    ProfileSyncServiceBundle::SyncClientBuilder builder(
-        &profile_sync_service_bundle_);
+    syncer::DataTypeController::TypeVector controllers;
+    controllers.push_back(
+        std::make_unique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
+
+    std::unique_ptr<syncer::SyncClientMock> sync_client =
+        profile_sync_service_bundle_.CreateSyncClientMock();
+    ON_CALL(*sync_client, CreateDataTypeControllers(_))
+        .WillByDefault(Return(ByMove(std::move(controllers))));
+
     ProfileSyncService::InitParams init_params =
         profile_sync_service_bundle_.CreateBasicInitParams(
-            ProfileSyncService::AUTO_START, builder.Build());
+            ProfileSyncService::AUTO_START, std::move(sync_client));
 
     prefs()->SetBoolean(syncer::prefs::kEnableLocalSyncBackend, true);
     init_params.identity_manager = nullptr;
 
     service_ = std::make_unique<ProfileSyncService>(std::move(init_params));
 
-    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_, _))
-        .WillByDefault(testing::InvokeWithoutArgs([=]() {
-          syncer::DataTypeController::TypeVector controllers;
-          controllers.push_back(
-              std::make_unique<syncer::FakeDataTypeController>(
-                  syncer::BOOKMARKS));
-          return controllers;
-        }));
-    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+    ON_CALL(*component_factory(), CreateSyncEngine(_, _, _))
         .WillByDefault(ReturnNewFakeSyncEngine());
     ON_CALL(*component_factory(), CreateDataTypeManager(_, _, _, _, _, _))
         .WillByDefault(
@@ -363,7 +361,7 @@
 TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
   SignIn();
   CreateService(ProfileSyncService::AUTO_START);
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngine());
   EXPECT_CALL(*component_factory(), CreateDataTypeManager(_, _, _, _, _, _))
       .WillOnce(
@@ -377,7 +375,7 @@
 
 TEST_F(ProfileSyncServiceTest, SuccessfulLocalBackendInitialization) {
   CreateServiceWithLocalSyncBackend();
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngine());
   EXPECT_CALL(*component_factory(), CreateDataTypeManager(_, _, _, _, _, _))
       .WillOnce(
@@ -536,7 +534,7 @@
 // before the backend initialize call returns.
 TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
   CreateService(ProfileSyncService::AUTO_START);
-  ON_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  ON_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillByDefault(ReturnNewFakeSyncEngineNoReturn());
 
   SignIn();
@@ -551,7 +549,7 @@
 TEST_F(ProfileSyncServiceWithoutStandaloneTransportTest, EarlyRequestStop) {
   CreateService(ProfileSyncService::AUTO_START);
   // Set up a fake sync engine that will not immediately finish initialization.
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngineNoReturn());
   SignIn();
   InitializeForNthSync();
@@ -569,7 +567,7 @@
 
   // Request start again, this time with an engine that does get initialized.
   // Sync should become active.
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngine());
   service()->GetUserSettings()->SetSyncRequested(true);
   EXPECT_EQ(syncer::SyncService::DISABLE_REASON_NONE,
@@ -583,7 +581,7 @@
 TEST_F(ProfileSyncServiceWithStandaloneTransportTest, EarlyRequestStop) {
   CreateService(ProfileSyncService::AUTO_START);
   // Set up a fake sync engine that will not immediately finish initialization.
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngineNoReturn());
   SignIn();
   InitializeForNthSync();
@@ -593,7 +591,7 @@
 
   // Request stop. This should immediately restart the service in standalone
   // transport mode.
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngine());
   service()->GetUserSettings()->SetSyncRequested(false);
   EXPECT_EQ(syncer::SyncService::DISABLE_REASON_USER_CHOICE,
@@ -761,7 +759,7 @@
 
   CreateService(ProfileSyncService::AUTO_START);
   SignIn();
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCollectCredentials>(
               &init_credentials, base::RepeatingClosure()))));
@@ -807,7 +805,7 @@
 
   CreateService(ProfileSyncService::AUTO_START);
   SignIn();
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCollectCredentials>(
               &init_credentials, invalidate_credentials_callback))));
@@ -867,7 +865,7 @@
 
   CreateService(ProfileSyncService::AUTO_START);
   SignIn();
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCollectCredentials>(
               &init_credentials, base::RepeatingClosure()))));
@@ -983,7 +981,7 @@
 
   CreateService(ProfileSyncService::AUTO_START);
   SignIn();
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCollectCredentials>(
               &init_credentials, base::RepeatingClosure()))));
@@ -1046,7 +1044,7 @@
 
   CreateService(ProfileSyncService::AUTO_START);
   SignIn();
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCollectCredentials>(
               &init_credentials, base::RepeatingClosure()))));
@@ -1176,7 +1174,7 @@
   // Initialize sync, ensure that both DataTypeManager and SyncEngine are
   // initialized and DTM::Configure is called with
   // CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE.
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCaptureClearServerData>(
               base::BindRepeating(&OnClearServerDataCalled,
@@ -1251,7 +1249,7 @@
   ShutdownAndDeleteService();
   CreateService(ProfileSyncService::AUTO_START);
   base::Closure captured_callback;
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCaptureClearServerData>(
               base::BindRepeating(&OnClearServerDataCalled,
@@ -1295,7 +1293,7 @@
       switches::kSyncClearDataOnPassphraseEncryption);
   SignIn();
   CreateService(ProfileSyncService::AUTO_START);
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCaptureClearServerData>(
               base::BindRepeating(&OnClearServerDataCalled,
@@ -1313,7 +1311,7 @@
   // Simulate browser restart. First configuration is a regular one.
   ShutdownAndDeleteService();
   CreateService(ProfileSyncService::AUTO_START);
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(
           Return(ByMove(std::make_unique<FakeSyncEngineCaptureClearServerData>(
               base::BindRepeating(&OnClearServerDataCalled,
@@ -1389,7 +1387,7 @@
           ReturnNewFakeDataTypeManager(GetDefaultConfigureCalledCallback()))
       .WillOnce(
           ReturnNewFakeDataTypeManager(GetDefaultConfigureCalledCallback()));
-  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _, _))
+  EXPECT_CALL(*component_factory(), CreateSyncEngine(_, _, _))
       .WillOnce(ReturnNewFakeSyncEngine())
       .WillOnce(ReturnNewFakeSyncEngine());
 
diff --git a/components/browser_sync/profile_sync_test_util.cc b/components/browser_sync/profile_sync_test_util.cc
index b26ad96..ec37273 100644
--- a/components/browser_sync/profile_sync_test_util.cc
+++ b/components/browser_sync/profile_sync_test_util.cc
@@ -8,19 +8,10 @@
 #include <utility>
 
 #include "base/bind_helpers.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/sync/history_model_worker.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync/device_info/local_device_info_provider_impl.h"
 #include "components/sync/engine/passive_model_worker.h"
-#include "components/sync/engine/sequenced_model_worker.h"
-#include "components/sync/engine/ui_model_worker.h"
 #include "components/sync/model/model_type_store_test_util.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
@@ -30,189 +21,10 @@
 
 namespace browser_sync {
 
-namespace {
-
-class BundleSyncClient : public syncer::FakeSyncClient {
- public:
-  BundleSyncClient(syncer::SyncApiComponentFactory* factory,
-                   PrefService* pref_service,
-                   syncer::ModelTypeStoreService* model_type_store_service,
-                   syncer::DeviceInfoSyncService* device_info_sync_service,
-                   autofill::PersonalDataManager* personal_data_manager,
-                   const base::Callback<base::WeakPtr<syncer::SyncableService>(
-                       syncer::ModelType type)>& get_syncable_service_callback,
-                   const base::Callback<bookmarks::BookmarkModel*(void)>&
-                       get_bookmark_model_callback,
-                   scoped_refptr<base::SequencedTaskRunner> db_thread,
-                   scoped_refptr<base::SequencedTaskRunner> file_thread,
-                   history::HistoryService* history_service);
-
-  ~BundleSyncClient() override;
-
-  PrefService* GetPrefService() override;
-  autofill::PersonalDataManager* GetPersonalDataManager() override;
-  base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
-      syncer::ModelType type) override;
-  syncer::ModelTypeStoreService* GetModelTypeStoreService() override;
-  syncer::DeviceInfoSyncService* GetDeviceInfoSyncService() override;
-  scoped_refptr<syncer::ModelSafeWorker> CreateModelWorkerForGroup(
-      syncer::ModelSafeGroup group) override;
-  history::HistoryService* GetHistoryService() override;
-  bookmarks::BookmarkModel* GetBookmarkModel() override;
-
- private:
-  PrefService* const pref_service_;
-  syncer::ModelTypeStoreService* const model_type_store_service_;
-  syncer::DeviceInfoSyncService* const device_info_sync_service_;
-  autofill::PersonalDataManager* const personal_data_manager_;
-  const base::Callback<base::WeakPtr<syncer::SyncableService>(
-      syncer::ModelType type)>
-      get_syncable_service_callback_;
-  const base::Callback<bookmarks::BookmarkModel*(void)>
-      get_bookmark_model_callback_;
-  // These task runners, if not null, are used in CreateModelWorkerForGroup.
-  const scoped_refptr<base::SequencedTaskRunner> db_thread_;
-  const scoped_refptr<base::SequencedTaskRunner> file_thread_;
-  history::HistoryService* history_service_;
-};
-
-BundleSyncClient::BundleSyncClient(
-    syncer::SyncApiComponentFactory* factory,
-    PrefService* pref_service,
-    syncer::ModelTypeStoreService* model_type_store_service,
-    syncer::DeviceInfoSyncService* device_info_sync_service,
-    autofill::PersonalDataManager* personal_data_manager,
-    const base::Callback<base::WeakPtr<syncer::SyncableService>(
-        syncer::ModelType type)>& get_syncable_service_callback,
-    const base::Callback<bookmarks::BookmarkModel*(void)>&
-        get_bookmark_model_callback,
-    scoped_refptr<base::SequencedTaskRunner> db_thread,
-    scoped_refptr<base::SequencedTaskRunner> file_thread,
-    history::HistoryService* history_service)
-    : syncer::FakeSyncClient(factory),
-      pref_service_(pref_service),
-      model_type_store_service_(model_type_store_service),
-      device_info_sync_service_(device_info_sync_service),
-      personal_data_manager_(personal_data_manager),
-      get_syncable_service_callback_(get_syncable_service_callback),
-      get_bookmark_model_callback_(get_bookmark_model_callback),
-      db_thread_(db_thread),
-      file_thread_(file_thread),
-      history_service_(history_service) {
-  EXPECT_EQ(!!db_thread_, !!file_thread_);
-}
-
-BundleSyncClient::~BundleSyncClient() = default;
-
-PrefService* BundleSyncClient::GetPrefService() {
-  return pref_service_;
-}
-
-autofill::PersonalDataManager* BundleSyncClient::GetPersonalDataManager() {
-  return personal_data_manager_;
-}
-
-base::WeakPtr<syncer::SyncableService>
-BundleSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
-  if (get_syncable_service_callback_.is_null())
-    return syncer::FakeSyncClient::GetSyncableServiceForType(type);
-  return get_syncable_service_callback_.Run(type);
-}
-
-scoped_refptr<syncer::ModelSafeWorker>
-BundleSyncClient::CreateModelWorkerForGroup(syncer::ModelSafeGroup group) {
-  if (!db_thread_)
-    return FakeSyncClient::CreateModelWorkerForGroup(group);
-  EXPECT_TRUE(file_thread_)
-      << "DB thread was specified but FILE thread was not.";
-  switch (group) {
-    case syncer::GROUP_DB:
-      return new syncer::SequencedModelWorker(db_thread_, syncer::GROUP_DB);
-    case syncer::GROUP_FILE:
-      return new syncer::SequencedModelWorker(file_thread_, syncer::GROUP_FILE);
-    case syncer::GROUP_UI:
-      return new syncer::UIModelWorker(base::ThreadTaskRunnerHandle::Get());
-    case syncer::GROUP_PASSIVE:
-      return new syncer::PassiveModelWorker();
-    case syncer::GROUP_HISTORY: {
-      history::HistoryService* history_service = GetHistoryService();
-      if (!history_service)
-        return nullptr;
-      return new HistoryModelWorker(history_service->AsWeakPtr(),
-                                    base::ThreadTaskRunnerHandle::Get());
-    }
-    default:
-      return nullptr;
-  }
-}
-
-syncer::ModelTypeStoreService* BundleSyncClient::GetModelTypeStoreService() {
-  return model_type_store_service_;
-}
-
-syncer::DeviceInfoSyncService* BundleSyncClient::GetDeviceInfoSyncService() {
-  return device_info_sync_service_;
-}
-
-history::HistoryService* BundleSyncClient::GetHistoryService() {
-  if (history_service_)
-    return history_service_;
-  return FakeSyncClient::GetHistoryService();
-}
-
-bookmarks::BookmarkModel* BundleSyncClient::GetBookmarkModel() {
-  if (get_bookmark_model_callback_.is_null())
-    return FakeSyncClient::GetBookmarkModel();
-  return get_bookmark_model_callback_.Run();
-}
-
-}  // namespace
-
-ProfileSyncServiceBundle::SyncClientBuilder::~SyncClientBuilder() = default;
-
-ProfileSyncServiceBundle::SyncClientBuilder::SyncClientBuilder(
-    ProfileSyncServiceBundle* bundle)
-    : bundle_(bundle) {}
-
-void ProfileSyncServiceBundle::SyncClientBuilder::SetPersonalDataManager(
-    autofill::PersonalDataManager* personal_data_manager) {
-  personal_data_manager_ = personal_data_manager;
-}
-
-// The client will call this callback to produce the service.
-void ProfileSyncServiceBundle::SyncClientBuilder::SetSyncableServiceCallback(
-    const base::RepeatingCallback<base::WeakPtr<syncer::SyncableService>(
-        syncer::ModelType type)>& get_syncable_service_callback) {
-  get_syncable_service_callback_ = get_syncable_service_callback;
-}
-
-void ProfileSyncServiceBundle::SyncClientBuilder::SetHistoryService(
-    history::HistoryService* history_service) {
-  history_service_ = history_service;
-}
-
-void ProfileSyncServiceBundle::SyncClientBuilder::SetBookmarkModelCallback(
-    const base::Callback<bookmarks::BookmarkModel*(void)>&
-        get_bookmark_model_callback) {
-  get_bookmark_model_callback_ = get_bookmark_model_callback;
-}
-
-std::unique_ptr<syncer::FakeSyncClient>
-ProfileSyncServiceBundle::SyncClientBuilder::Build() {
-  return std::make_unique<BundleSyncClient>(
-      bundle_->component_factory(), bundle_->pref_service(),
-      &bundle_->model_type_store_service_, &bundle_->device_info_sync_service_,
-      personal_data_manager_, get_syncable_service_callback_,
-      get_bookmark_model_callback_,
-      activate_model_creation_ ? bundle_->db_thread() : nullptr,
-      activate_model_creation_ ? base::SequencedTaskRunnerHandle::Get()
-                               : nullptr,
-      history_service_);
-}
+using testing::Return;
 
 ProfileSyncServiceBundle::ProfileSyncServiceBundle()
-    : db_thread_(base::SequencedTaskRunnerHandle::Get()),
-      device_info_sync_service_(
+    : device_info_sync_service_(
           model_type_store_service_.GetStoreFactory(),
           std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
               version_info::Channel::UNKNOWN,
@@ -230,6 +42,22 @@
 
 ProfileSyncServiceBundle::~ProfileSyncServiceBundle() {}
 
+std::unique_ptr<syncer::SyncClientMock>
+ProfileSyncServiceBundle::CreateSyncClientMock() {
+  auto sync_client =
+      std::make_unique<testing::NiceMock<syncer::SyncClientMock>>();
+  ON_CALL(*sync_client, GetPrefService()).WillByDefault(Return(&pref_service_));
+  ON_CALL(*sync_client, GetDeviceInfoSyncService())
+      .WillByDefault(Return(&device_info_sync_service_));
+  ON_CALL(*sync_client, GetSyncApiComponentFactory())
+      .WillByDefault(Return(&component_factory_));
+  // Used by control types.
+  ON_CALL(*sync_client, CreateModelWorkerForGroup(syncer::GROUP_PASSIVE))
+      .WillByDefault(
+          Return(base::MakeRefCounted<syncer::PassiveModelWorker>()));
+  return std::move(sync_client);
+}
+
 ProfileSyncService::InitParams ProfileSyncServiceBundle::CreateBasicInitParams(
     ProfileSyncService::StartBehavior start_behavior,
     std::unique_ptr<syncer::SyncClient> sync_client) {
diff --git a/components/browser_sync/profile_sync_test_util.h b/components/browser_sync/profile_sync_test_util.h
index a582718..bda4db31 100644
--- a/components/browser_sync/profile_sync_test_util.h
+++ b/components/browser_sync/profile_sync_test_util.h
@@ -14,17 +14,13 @@
 #include "components/invalidation/impl/fake_invalidation_service.h"
 #include "components/invalidation/impl/profile_identity_provider.h"
 #include "components/sync/device_info/device_info_sync_service_impl.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/model/test_model_type_store_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "services/identity/public/cpp/identity_test_environment.h"
 #include "services/network/test/test_url_loader_factory.h"
 
-namespace history {
-class HistoryService;
-}
-
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -44,54 +40,8 @@
 
   ~ProfileSyncServiceBundle();
 
-  // Builders
-
-  // Builds a child of FakeSyncClient which overrides some of the client's
-  // accessors to return objects from the bundle.
-  class SyncClientBuilder {
-   public:
-    // Construct the builder and associate with the |bundle| to source objects
-    // from.
-    explicit SyncClientBuilder(ProfileSyncServiceBundle* bundle);
-
-    ~SyncClientBuilder();
-
-    void SetPersonalDataManager(
-        autofill::PersonalDataManager* personal_data_manager);
-
-    // The client will call this callback to produce the SyncableService
-    // specific to |type|.
-    void SetSyncableServiceCallback(
-        const base::RepeatingCallback<base::WeakPtr<syncer::SyncableService>(
-            syncer::ModelType type)>& get_syncable_service_callback);
-
-    void SetHistoryService(history::HistoryService* history_service);
-
-    void SetBookmarkModelCallback(
-        const base::Callback<bookmarks::BookmarkModel*(void)>&
-            get_bookmark_model_callback);
-
-    void set_activate_model_creation() { activate_model_creation_ = true; }
-
-    std::unique_ptr<syncer::FakeSyncClient> Build();
-
-   private:
-    // Associated bundle to source objects from.
-    ProfileSyncServiceBundle* const bundle_;
-
-    autofill::PersonalDataManager* personal_data_manager_;
-    base::Callback<base::WeakPtr<syncer::SyncableService>(
-        syncer::ModelType type)>
-        get_syncable_service_callback_;
-    history::HistoryService* history_service_ = nullptr;
-    base::Callback<bookmarks::BookmarkModel*(void)>
-        get_bookmark_model_callback_;
-    // If set, the built client will be able to build some ModelSafeWorker
-    // instances.
-    bool activate_model_creation_ = false;
-
-    DISALLOW_COPY_AND_ASSIGN(SyncClientBuilder);
-  };
+  // Creates a mock sync client that leverages the dependencies in this bundle.
+  std::unique_ptr<syncer::SyncClientMock> CreateSyncClientMock();
 
   // Creates an InitParams instance with the specified |start_behavior| and
   // |sync_client|, and fills the rest with dummy values and objects owned by
@@ -130,19 +80,11 @@
     return &fake_invalidation_service_;
   }
 
-  base::SequencedTaskRunner* db_thread() { return db_thread_.get(); }
-
-  void set_db_thread(
-      const scoped_refptr<base::SequencedTaskRunner>& db_thread) {
-    db_thread_ = db_thread;
-  }
-
   syncer::DeviceInfoSyncService* device_info_sync_service() {
     return &device_info_sync_service_;
   }
 
  private:
-  scoped_refptr<base::SequencedTaskRunner> db_thread_;
   sync_preferences::TestingPrefServiceSyncable pref_service_;
   syncer::TestModelTypeStoreService model_type_store_service_;
   syncer::DeviceInfoSyncServiceImpl device_info_sync_service_;
diff --git a/components/browser_sync/sync_auth_manager.cc b/components/browser_sync/sync_auth_manager.cc
index 07e28b8..814f3f7 100644
--- a/components/browser_sync/sync_auth_manager.cc
+++ b/components/browser_sync/sync_auth_manager.cc
@@ -251,7 +251,7 @@
 }
 
 void SyncAuthManager::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
                             syncer::STOP_SOURCE_LIMIT);
   UpdateSyncAccountIfNecessary();
diff --git a/components/browser_sync/sync_auth_manager.h b/components/browser_sync/sync_auth_manager.h
index 925482e..bb8b892 100644
--- a/components/browser_sync/sync_auth_manager.h
+++ b/components/browser_sync/sync_auth_manager.h
@@ -92,7 +92,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
   void OnRefreshTokenUpdatedForAccount(
       const AccountInfo& account_info) override;
   void OnRefreshTokenRemovedForAccount(const std::string& account_id) override;
diff --git a/components/gcm_driver/account_tracker.cc b/components/gcm_driver/account_tracker.cc
index a460194..c473691 100644
--- a/components/gcm_driver/account_tracker.cc
+++ b/components/gcm_driver/account_tracker.cc
@@ -103,7 +103,7 @@
 }
 
 void AccountTracker::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   TRACE_EVENT0("identity", "AccountTracker::OnPrimaryAccountCleared");
   DVLOG(1) << "LOGOUT";
   StopTrackingAllAccounts();
diff --git a/components/gcm_driver/account_tracker.h b/components/gcm_driver/account_tracker.h
index 961bcd42..04c4e6e 100644
--- a/components/gcm_driver/account_tracker.h
+++ b/components/gcm_driver/account_tracker.h
@@ -80,7 +80,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
   void OnRefreshTokenUpdatedForAccount(
       const AccountInfo& account_info) override;
   void OnRefreshTokenRemovedForAccount(const std::string& account_id) override;
diff --git a/components/gcm_driver/gcm_profile_service.cc b/components/gcm_driver/gcm_profile_service.cc
index f43314d..1c68291 100644
--- a/components/gcm_driver/gcm_profile_service.cc
+++ b/components/gcm_driver/gcm_profile_service.cc
@@ -50,7 +50,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
  private:
   void StartAccountTracker(
@@ -100,7 +100,7 @@
 }
 
 void GCMProfileService::IdentityObserver::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   account_id_.clear();
 
   // Still need to notify GCMDriver for UMA purpose.
diff --git a/components/gcm_driver/resources/gcm_internals.html b/components/gcm_driver/resources/gcm_internals.html
index e8bd5f7..54d5874 100644
--- a/components/gcm_driver/resources/gcm_internals.html
+++ b/components/gcm_driver/resources/gcm_internals.html
@@ -217,6 +217,5 @@
   </table>
 </if>
 
-<script src="chrome://resources/js/i18n_template.js"></script>
 </body>
 </html>
diff --git a/components/history/core/browser/expire_history_backend.cc b/components/history/core/browser/expire_history_backend.cc
index 60c3f8a..ca3a6160 100644
--- a/components/history/core/browser/expire_history_backend.cc
+++ b/components/history/core/browser/expire_history_backend.cc
@@ -183,11 +183,12 @@
   thumb_db_ = thumb_db;
 }
 
-void ExpireHistoryBackend::DeleteURL(const GURL& url) {
-  DeleteURLs(std::vector<GURL>(1, url));
+void ExpireHistoryBackend::DeleteURL(const GURL& url, base::Time end_time) {
+  DeleteURLs({url}, end_time);
 }
 
-void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
+void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls,
+                                      base::Time end_time) {
   if (!main_db_)
     return;
 
@@ -206,16 +207,26 @@
     // Collect all the visits and delete them. Note that we don't give up if
     // there are no visits, since the URL could still have an entry that we
     // should delete.
-    VisitVector visits;
-    main_db_->GetVisitsForURL(url_row.id(), &visits);
+    VisitVector visits_to_delete;
+    main_db_->GetVisitsForURL(url_row.id(), &visits_to_delete);
+    size_t total_visits = visits_to_delete.size();
+    if (!end_time.is_null() && !end_time.is_max()) {
+      // Remove all items that should not be deleted from |visits_to_delete|.
+      visits_to_delete.erase(
+          std::remove_if(visits_to_delete.begin(), visits_to_delete.end(),
+                         [=](auto& v) { return v.visit_time > end_time; }),
+          visits_to_delete.end());
+    }
+    DeleteVisitRelatedInfo(visits_to_delete, &effects);
 
-    DeleteVisitRelatedInfo(visits, &effects);
-
-    // We skip ExpireURLsForVisits (since we are deleting from the
-    // URL, and not starting with visits in a given time range). We
-    // therefore need to call the deletion and favicon update
-    // functions manually.
-    DeleteOneURL(url_row, is_pinned, &effects);
+    // Remove the URL if all visits have been removed.
+    if (visits_to_delete.size() == total_visits) {
+      // We skip ExpireURLsForVisits (since we are deleting from the
+      // URL, and not starting with visits in a given time range). We
+      // therefore need to call the deletion and favicon update
+      // functions manually.
+      DeleteOneURL(url_row, is_pinned, &effects);
+    }
   }
 
   DeleteFaviconsIfPossible(&effects);
diff --git a/components/history/core/browser/expire_history_backend.h b/components/history/core/browser/expire_history_backend.h
index 8c95f37..98b9205 100644
--- a/components/history/core/browser/expire_history_backend.h
+++ b/components/history/core/browser/expire_history_backend.h
@@ -72,11 +72,11 @@
   // will continue until the object is deleted.
   void StartExpiringOldStuff(base::TimeDelta expiration_threshold);
 
-  // Deletes everything associated with a URL.
-  void DeleteURL(const GURL& url);
+  // Deletes everything associated with a URL until |end_time|.
+  void DeleteURL(const GURL& url, base::Time end_time);
 
-  // Deletes everything associated with each URL in the list.
-  void DeleteURLs(const std::vector<GURL>& url);
+  // Deletes everything associated with each URL in the list until |end_time|.
+  void DeleteURLs(const std::vector<GURL>& url, base::Time end_time);
 
   // Removes all visits to restrict_urls (or all URLs if empty) in the given
   // time range, updating the URLs accordingly.
diff --git a/components/history/core/browser/expire_history_backend_unittest.cc b/components/history/core/browser/expire_history_backend_unittest.cc
index 9fcb30fc..983fa33 100644
--- a/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/components/history/core/browser/expire_history_backend_unittest.cc
@@ -470,7 +470,7 @@
   ASSERT_EQ(1U, visits.size());
 
   // Delete the URL and its dependencies.
-  expirer_.DeleteURL(last_row.url());
+  expirer_.DeleteURL(last_row.url(), base::Time::Max());
 
   // All the normal data + the favicon should be gone.
   EnsureURLInfoGone(last_row, false);
@@ -478,6 +478,48 @@
   EXPECT_FALSE(HasFavicon(favicon_id));
 }
 
+// Deletes visits to a URL with a time bound. The url, favicon and the second
+// visit should not get deleted.
+TEST_F(ExpireHistoryTest, DeleteURLWithTimeBound) {
+  URLID url_ids[3];
+  base::Time visit_times[4];
+  AddExampleData(url_ids, visit_times);
+
+  // Remove the first url because it shares the favicon with the second url.
+  URLRow first_row;
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &first_row));
+  expirer_.DeleteURL(first_row.url(), base::Time::Max());
+
+  // Verify things are the way we expect with a URL row, favicon.
+  URLRow second_row;
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &second_row));
+  favicon_base::FaviconID favicon_id =
+      GetFavicon(second_row.url(), favicon_base::IconType::kFavicon);
+  EXPECT_TRUE(HasFavicon(favicon_id));
+
+  VisitVector visits;
+  main_db_->GetVisitsForURL(url_ids[1], &visits);
+  ASSERT_EQ(2U, visits.size());
+
+  // Delete the first visit but not the URL and dependencies.
+  expirer_.DeleteURL(second_row.url(), visits[0].visit_time);
+  // The second visit, URL and favicon should still be there.
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &second_row));
+  VisitVector visits_after_deletion;
+  main_db_->GetVisitsForURL(url_ids[1], &visits_after_deletion);
+  ASSERT_EQ(1U, visits_after_deletion.size());
+  EXPECT_EQ(visits[1].visit_time, visits_after_deletion[0].visit_time);
+  EXPECT_TRUE(GetFavicon(second_row.url(), favicon_base::IconType::kFavicon));
+  EXPECT_TRUE(HasFavicon(favicon_id));
+
+  // Delete the second visit.
+  expirer_.DeleteURL(second_row.url(), visits[1].visit_time);
+  // All the normal data + the favicon should be gone.
+  EnsureURLInfoGone(second_row, false);
+  EXPECT_FALSE(GetFavicon(second_row.url(), favicon_base::IconType::kFavicon));
+  EXPECT_FALSE(HasFavicon(favicon_id));
+}
+
 // Deletes a URL with a favicon that other URLs reference, so that the favicon
 // should not get deleted. This also tests deleting more than one visit.
 TEST_F(ExpireHistoryTest, DeleteURLWithoutFavicon) {
@@ -497,7 +539,7 @@
   EXPECT_EQ(2U, visits.size());
 
   // Delete the URL and its dependencies.
-  expirer_.DeleteURL(last_row.url());
+  expirer_.DeleteURL(last_row.url(), base::Time::Max());
 
   // All the normal data except the favicon should be gone.
   EnsureURLInfoGone(last_row, false);
@@ -518,7 +560,7 @@
   StarURL(url_row.url());
 
   // Attempt to delete the url.
-  expirer_.DeleteURL(url_row.url());
+  expirer_.DeleteURL(url_row.url(), base::Time::Max());
 
   // Verify it no longer exists.
   GURL url = url_row.url();
@@ -541,7 +583,7 @@
   StarURL(url);
 
   // Delete it.
-  expirer_.DeleteURL(url);
+  expirer_.DeleteURL(url, base::Time::Max());
 
   // The favicon should exist.
   favicon_base::FaviconID favicon_id =
@@ -550,7 +592,7 @@
 
   // Unstar the URL and try again to delete it.
   history_client_.ClearAllBookmarks();
-  expirer_.DeleteURL(url);
+  expirer_.DeleteURL(url, base::Time::Max());
 
   // The favicon should be gone.
   favicon_id = GetFavicon(url, favicon_base::IconType::kFavicon);
@@ -581,7 +623,7 @@
   StarURL(rows[0].url());
 
   // Delete the URLs and their dependencies.
-  expirer_.DeleteURLs(urls);
+  expirer_.DeleteURLs(urls, base::Time::Max());
 
   EnsureURLInfoGone(rows[0], false);
   EnsureURLInfoGone(rows[1], false);
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 5bb1f79..fb5726e 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -2420,7 +2420,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
-  expirer_.DeleteURLs(urls);
+  expirer_.DeleteURLs(urls, base::Time::Max());
 
   db_->GetStartDate(&first_recorded_time_);
   // Force a commit, if the user is deleting something for privacy reasons, we
@@ -2429,7 +2429,7 @@
 }
 
 void HistoryBackend::DeleteURL(const GURL& url) {
-  expirer_.DeleteURL(url);
+  expirer_.DeleteURL(url, base::Time::Max());
 
   db_->GetStartDate(&first_recorded_time_);
   // Force a commit, if the user is deleting something for privacy reasons, we
@@ -2437,6 +2437,17 @@
   Commit();
 }
 
+void HistoryBackend::DeleteURLsUntil(
+    const std::vector<std::pair<GURL, base::Time>>& urls_and_timestamps) {
+  for (const auto& pair : urls_and_timestamps) {
+    expirer_.DeleteURL(pair.first, pair.second);
+  }
+  db_->GetStartDate(&first_recorded_time_);
+  // Force a commit, if the user is deleting something for privacy reasons, we
+  // want to get it on disk ASAP.
+  Commit();
+}
+
 void HistoryBackend::ExpireHistoryBetween(const std::set<GURL>& restrict_urls,
                                           Time begin_time,
                                           Time end_time,
@@ -2551,7 +2562,7 @@
     // that we can delete all associated icons in the case of deleting an
     // unvisited bookmarked URL.
     if (visits.empty())
-      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
+      expirer_.DeleteURL(*i, base::Time::Max());
   }
 }
 
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index 2a125ad..2ffbe2d 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -415,9 +415,13 @@
 
   // Deleting ------------------------------------------------------------------
 
-  virtual void DeleteURLs(const std::vector<GURL>& urls);
+  void DeleteURLs(const std::vector<GURL>& urls);
 
-  virtual void DeleteURL(const GURL& url);
+  void DeleteURL(const GURL& url);
+
+  // Deletes all visits to urls until the corresponding timestamp.
+  void DeleteURLsUntil(
+      const std::vector<std::pair<GURL, base::Time>>& urls_and_timestamps);
 
   // Calls ExpireHistoryBackend::ExpireHistoryBetween and commits the change.
   void ExpireHistoryBetween(const std::set<GURL>& restrict_urls,
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index f83a693..ff4bcd5 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -844,7 +844,7 @@
   history_client_.AddBookmark(row2.url());
 
   // Delete url 2.
-  backend_->expirer_.DeleteURL(row2.url());
+  backend_->expirer_.DeleteURL(row2.url(), base::Time::Max());
   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), nullptr));
   VisitVector visits;
   backend_->db_->GetVisitsForURL(row2_id, &visits);
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index de0c3340..bdfb446 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -1128,20 +1128,15 @@
       std::move(callback));
 }
 
-void HistoryService::ExpireLocalAndRemoteHistoryBetween(
+void HistoryService::DeleteLocalAndRemoteHistoryBetween(
     WebHistoryService* web_history,
-    const std::set<GURL>& restrict_urls,
     Time begin_time,
     Time end_time,
-    bool user_initiated,
     base::OnceClosure callback,
     base::CancelableTaskTracker* tracker) {
-  // TODO(dubroy): This should be factored out into a separate class that
-  // dispatches deletions to the proper places.
+  // TODO(crbug.com/929111): This should be factored out into a separate class
+  // that dispatches deletions to the proper places.
   if (web_history) {
-    // TODO(dubroy): This API does not yet support deletion of specific URLs.
-    DCHECK(restrict_urls.empty());
-
     delete_directive_handler_.CreateDeleteDirectives(std::set<int64_t>(),
                                                      begin_time, end_time);
 
@@ -1174,12 +1169,50 @@
               }
             }
           })");
-    web_history->ExpireHistoryBetween(restrict_urls, begin_time, end_time,
-                                      base::Bind(&ExpireWebHistoryComplete),
-                                      partial_traffic_annotation);
+    web_history->ExpireHistoryBetween(
+        /*restrict_urls=*/{}, begin_time, end_time,
+        base::Bind(&ExpireWebHistoryComplete), partial_traffic_annotation);
   }
-  ExpireHistoryBetween(restrict_urls, begin_time, end_time, user_initiated,
-                       std::move(callback), tracker);
+  ExpireHistoryBetween(/*restrict_urls=*/{}, begin_time, end_time,
+                       /*user_initiated=*/true, std::move(callback), tracker);
+}
+
+void HistoryService::DeleteLocalAndRemoteUrl(WebHistoryService* web_history,
+                                             const GURL& url) {
+  DCHECK(url.is_valid());
+  // TODO(crbug.com/929111): This should be factored out into a separate class
+  // that dispatches deletions to the proper places.
+  if (web_history) {
+    delete_directive_handler_.CreateUrlDeleteDirective(url);
+
+    // Attempt online deletion from the history server, but ignore the result.
+    // Deletion directives ensure that the results will eventually be deleted.
+    net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
+        net::DefinePartialNetworkTrafficAnnotation("web_history_delete_url",
+                                                   "web_history_service", R"(
+          semantics {
+            description:
+              "If a user who syncs their browsing history deletes urls from  "
+              "history, Chrome sends a request to a google.com "
+              "host to execute the corresponding deletion serverside."
+            trigger:
+              "Deleting urls from browsing history, e.g. by an extension."
+            data:
+              "The selected urls, a version info token to resolve transaction "
+              "conflicts, and an OAuth2 token authenticating the user."
+          }
+          policy {
+            chrome_policy {
+              AllowDeletingBrowserHistory {
+                AllowDeletingBrowserHistory: false
+              }
+            }
+          })");
+    web_history->ExpireHistoryBetween(
+        /*restrict_urls=*/{url}, base::Time(), base::Time::Max(),
+        base::Bind(&ExpireWebHistoryComplete), partial_traffic_annotation);
+  }
+  DeleteURL(url);
 }
 
 void HistoryService::OnDBLoaded() {
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 69c6812..b751f28 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -360,14 +360,16 @@
   // Removes all visits to the given URLs in the specified time range. Calls
   // ExpireHistoryBetween() to delete local visits, and handles deletion of
   // synced visits if appropriate.
-  void ExpireLocalAndRemoteHistoryBetween(WebHistoryService* web_history,
-                                          const std::set<GURL>& restrict_urls,
+  void DeleteLocalAndRemoteHistoryBetween(WebHistoryService* web_history,
                                           base::Time begin_time,
                                           base::Time end_time,
-                                          bool user_initiated,
                                           base::OnceClosure callback,
                                           base::CancelableTaskTracker* tracker);
 
+  // Removes all visits to the given url. Calls DeleteUrl() to delete local
+  // visits and handles deletion of synced visits if appropriate.
+  void DeleteLocalAndRemoteUrl(WebHistoryService* web_history, const GURL& url);
+
   // Processes the given |delete_directive| and sends it to the
   // SyncChangeProcessor (if it exists).  Returns any error resulting
   // from sending the delete directive to sync.
diff --git a/components/history/core/browser/history_service_unittest.cc b/components/history/core/browser/history_service_unittest.cc
index 5dc9119..b98a76d 100644
--- a/components/history/core/browser/history_service_unittest.cc
+++ b/components/history/core/browser/history_service_unittest.cc
@@ -617,6 +617,10 @@
 // static
 const int HistoryDBTaskImpl::kWantInvokeCount = 2;
 
+base::Time UnixUsecToTime(int64_t usec) {
+  return base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(usec);
+}
+
 }  // namespace
 
 TEST_F(HistoryServiceTest, HistoryDBTask) {
@@ -666,8 +670,7 @@
 
   const GURL test_url("http://www.google.com/");
   for (int64_t i = 1; i <= 10; ++i) {
-    base::Time t =
-        base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
+    base::Time t = UnixUsecToTime(i);
     history_service_->AddPage(test_url, t, nullptr, 0, GURL(),
                               history::RedirectList(), ui::PAGE_TRANSITION_LINK,
                               history::SOURCE_BROWSED, false);
@@ -729,8 +732,7 @@
   ASSERT_TRUE(history_service_.get());
   const GURL test_url("http://www.google.com/");
   for (int64_t i = 1; i <= 20; i++) {
-    base::Time t =
-        base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
+    base::Time t = UnixUsecToTime(i);
     history_service_->AddPage(test_url, t, nullptr, 0, GURL(),
                               history::RedirectList(), ui::PAGE_TRANSITION_LINK,
                               history::SOURCE_BROWSED, false);
@@ -782,16 +784,11 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   ASSERT_EQ(5, query_url_row_.visit_count());
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1),
-            query_url_visits_[0].visit_time);
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(2),
-            query_url_visits_[1].visit_time);
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(11),
-            query_url_visits_[2].visit_time);
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(12),
-            query_url_visits_[3].visit_time);
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(20),
-            query_url_visits_[4].visit_time);
+  EXPECT_EQ(UnixUsecToTime(1), query_url_visits_[0].visit_time);
+  EXPECT_EQ(UnixUsecToTime(2), query_url_visits_[1].visit_time);
+  EXPECT_EQ(UnixUsecToTime(11), query_url_visits_[2].visit_time);
+  EXPECT_EQ(UnixUsecToTime(12), query_url_visits_[3].visit_time);
+  EXPECT_EQ(UnixUsecToTime(20), query_url_visits_[4].visit_time);
 
   // Expect two sync changes for deleting processed directives.
   const syncer::SyncChangeList& sync_changes = change_processor.changes();
@@ -808,8 +805,7 @@
   ASSERT_TRUE(history_service_.get());
   const GURL test_url("http://www.google.com/");
   for (int64_t i = 1; i <= 10; ++i) {
-    base::Time t =
-        base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
+    base::Time t = UnixUsecToTime(i);
     history_service_->AddPage(test_url, t, nullptr, 0, GURL(),
                               history::RedirectList(), ui::PAGE_TRANSITION_LINK,
                               history::SOURCE_BROWSED, false);
@@ -855,12 +851,9 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   ASSERT_EQ(3, query_url_row_.visit_count());
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1),
-            query_url_visits_[0].visit_time);
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6),
-            query_url_visits_[1].visit_time);
-  EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(7),
-            query_url_visits_[2].visit_time);
+  EXPECT_EQ(UnixUsecToTime(1), query_url_visits_[0].visit_time);
+  EXPECT_EQ(UnixUsecToTime(6), query_url_visits_[1].visit_time);
+  EXPECT_EQ(UnixUsecToTime(7), query_url_visits_[2].visit_time);
 
   // Expect two sync changes for deleting processed directives.
   const syncer::SyncChangeList& sync_changes = change_processor.changes();
@@ -871,6 +864,74 @@
   EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
 }
 
+// Create a delete directive for urls.  The expected entries should be
+// deleted.
+TEST_F(HistoryServiceTest, ProcessUrlDeleteDirective) {
+  ASSERT_TRUE(history_service_.get());
+  const GURL test_url1("http://www.google.com/");
+  const GURL test_url2("http://maps.google.com/");
+
+  history_service_->AddPage(test_url1, UnixUsecToTime(3), nullptr, 0, GURL(),
+                            history::RedirectList(), ui::PAGE_TRANSITION_LINK,
+                            history::SOURCE_BROWSED, false);
+  history_service_->AddPage(test_url2, UnixUsecToTime(6), nullptr, 0, GURL(),
+                            history::RedirectList(), ui::PAGE_TRANSITION_LINK,
+                            history::SOURCE_BROWSED, false);
+  history_service_->AddPage(test_url1, UnixUsecToTime(10), nullptr, 0, GURL(),
+                            history::RedirectList(), ui::PAGE_TRANSITION_LINK,
+                            history::SOURCE_BROWSED, false);
+
+  EXPECT_TRUE(QueryURL(history_service_.get(), test_url1));
+  ASSERT_EQ(2, query_url_row_.visit_count());
+  EXPECT_TRUE(QueryURL(history_service_.get(), test_url2));
+
+  // Delete the first visit of url1 and all visits of url2.
+  syncer::SyncDataList directives;
+  sync_pb::EntitySpecifics entity_specs1;
+  sync_pb::UrlDirective* url_directive =
+      entity_specs1.mutable_history_delete_directive()->mutable_url_directive();
+  url_directive->set_url(test_url1.spec());
+  url_directive->set_end_time_usec(8);
+  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs1));
+  sync_pb::EntitySpecifics entity_specs2;
+  url_directive =
+      entity_specs2.mutable_history_delete_directive()->mutable_url_directive();
+  url_directive->set_url(test_url2.spec());
+  url_directive->set_end_time_usec(8);
+  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs2));
+
+  syncer::FakeSyncChangeProcessor change_processor;
+  EXPECT_FALSE(history_service_
+                   ->MergeDataAndStartSyncing(
+                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
+                       std::unique_ptr<syncer::SyncChangeProcessor>(
+                           new syncer::SyncChangeProcessorWrapperForTest(
+                               &change_processor)),
+                       std::unique_ptr<syncer::SyncErrorFactory>())
+                   .error()
+                   .IsSet());
+
+  // Inject a task to check status and keep message loop filled before
+  // directive processing finishes.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CheckDirectiveProcessingResult,
+                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
+                     &change_processor, 2));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(QueryURL(history_service_.get(), test_url1));
+  EXPECT_EQ(UnixUsecToTime(10), query_url_visits_[0].visit_time);
+  EXPECT_FALSE(QueryURL(history_service_.get(), test_url2));
+
+  // Expect a sync change for deleting processed directives.
+  const syncer::SyncChangeList& sync_changes = change_processor.changes();
+  ASSERT_EQ(2u, sync_changes.size());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
+  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
+  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
+}
+
 // Helper to add a page with specified days back in the past.
 void AddPageInThePast(HistoryService* history,
                       const std::string& url_spec,
diff --git a/components/history/core/browser/sync/delete_directive_handler.cc b/components/history/core/browser/sync/delete_directive_handler.cc
index f554452..25b087c 100644
--- a/components/history/core/browser/sync/delete_directive_handler.cc
+++ b/components/history/core/browser/sync/delete_directive_handler.cc
@@ -10,6 +10,7 @@
 #include <map>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "base/json/json_writer.h"
 #include "base/rand_util.h"
@@ -87,6 +88,7 @@
         delete_directive.global_id_directive();
 
     DCHECK(!delete_directive.has_time_range_directive());
+    DCHECK(!delete_directive.has_url_directive());
     DCHECK_NE(global_id_directive.global_id_size(), 0);
     if (global_id_directive.has_start_time_usec())
       DCHECK_GE(global_id_directive.start_time_usec(), 0);
@@ -104,14 +106,24 @@
         delete_directive.time_range_directive();
 
     DCHECK(!delete_directive.has_global_id_directive());
+    DCHECK(!delete_directive.has_url_directive());
     DCHECK(time_range_directive.has_start_time_usec());
     DCHECK(time_range_directive.has_end_time_usec());
     DCHECK_GE(time_range_directive.start_time_usec(), 0);
     DCHECK_GT(time_range_directive.end_time_usec(), 0);
     DCHECK_GT(time_range_directive.end_time_usec(),
               time_range_directive.start_time_usec());
+  } else if (delete_directive.has_url_directive()) {
+    const sync_pb::UrlDirective& url_directive =
+        delete_directive.url_directive();
+
+    DCHECK(!delete_directive.has_global_id_directive());
+    DCHECK(!delete_directive.has_time_range_directive());
+    DCHECK(url_directive.has_url());
+    DCHECK_GT(url_directive.end_time_usec(), 0);
   } else {
-    NOTREACHED() << "Delete directive has no time range or global ID directive";
+    NOTREACHED()
+        << "Delete directive has no time range, global ID or url directive";
   }
 }
 #endif  // !defined(NDEBUG)
@@ -151,6 +163,11 @@
       HistoryBackend* history_backend,
       const syncer::SyncDataList& time_range_directives);
 
+  // Process a list of url directives, all history entries matching the
+  // urls are deleted.
+  void ProcessUrlDeleteDirectives(HistoryBackend* history_backend,
+                                  const syncer::SyncDataList& url_directives);
+
   base::WeakPtr<DeleteDirectiveHandler> delete_directive_handler_;
   syncer::SyncDataList delete_directives_;
   DeleteDirectiveHandler::PostProcessingAction post_processing_action_;
@@ -161,15 +178,17 @@
     HistoryDatabase* db) {
   syncer::SyncDataList global_id_directives;
   syncer::SyncDataList time_range_directives;
-  for (syncer::SyncDataList::const_iterator it = delete_directives_.begin();
-       it != delete_directives_.end(); ++it) {
-    DCHECK_EQ(it->GetDataType(), syncer::HISTORY_DELETE_DIRECTIVES);
+  syncer::SyncDataList url_directives;
+  for (const auto& sync_data : delete_directives_) {
+    DCHECK_EQ(sync_data.GetDataType(), syncer::HISTORY_DELETE_DIRECTIVES);
     const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive =
-        it->GetSpecifics().history_delete_directive();
+        sync_data.GetSpecifics().history_delete_directive();
     if (delete_directive.has_global_id_directive()) {
-      global_id_directives.push_back(*it);
-    } else {
-      time_range_directives.push_back(*it);
+      global_id_directives.push_back(sync_data);
+    } else if (delete_directive.has_time_range_directive()) {
+      time_range_directives.push_back(sync_data);
+    } else if (delete_directive.has_url_directive()) {
+      url_directives.push_back(sync_data);
     }
   }
 
@@ -177,6 +196,7 @@
   std::sort(time_range_directives.begin(), time_range_directives.end(),
             TimeRangeLessThan);
   ProcessTimeRangeDeleteDirectives(backend, time_range_directives);
+  ProcessUrlDeleteDirectives(backend, url_directives);
   return true;
 }
 
@@ -291,6 +311,30 @@
   }
 }
 
+void DeleteDirectiveHandler::DeleteDirectiveTask::ProcessUrlDeleteDirectives(
+    HistoryBackend* history_backend,
+    const syncer::SyncDataList& url_directives) {
+  std::vector<std::pair<GURL, base::Time>> deletions;
+  for (const auto& sync_data : url_directives) {
+    const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive =
+        sync_data.GetSpecifics().history_delete_directive();
+    DVLOG(1) << "Processing url directive: "
+             << DeleteDirectiveToString(delete_directive);
+    const sync_pb::UrlDirective& url_directive =
+        delete_directive.url_directive();
+
+    if (!url_directive.has_url() || !url_directive.has_end_time_usec())
+      continue;
+
+    GURL url(url_directive.url());
+    base::Time end_time = UnixUsecToTime(url_directive.end_time_usec());
+    if (url.is_valid())
+      deletions.emplace_back(url, end_time);
+  }
+  if (!deletions.empty())
+    history_backend->DeleteURLsUntil(deletions);
+}
+
 DeleteDirectiveHandler::DeleteDirectiveHandler() : weak_ptr_factory_(this) {}
 
 DeleteDirectiveHandler::~DeleteDirectiveHandler() {
@@ -354,6 +398,19 @@
   return !error.IsSet();
 }
 
+bool DeleteDirectiveHandler::CreateUrlDeleteDirective(const GURL& url) {
+  DCHECK(url.is_valid());
+  sync_pb::HistoryDeleteDirectiveSpecifics delete_directive;
+
+  sync_pb::UrlDirective* url_directive =
+      delete_directive.mutable_url_directive();
+  url_directive->set_url(url.spec());
+  url_directive->set_end_time_usec(TimeToUnixUsec(base::Time::Now()));
+
+  syncer::SyncError error = ProcessLocalDeleteDirective(delete_directive);
+  return !error.IsSet();
+}
+
 syncer::SyncError DeleteDirectiveHandler::ProcessLocalDeleteDirective(
     const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/history/core/browser/sync/delete_directive_handler.h b/components/history/core/browser/sync/delete_directive_handler.h
index 61e0f07..84e0581 100644
--- a/components/history/core/browser/sync/delete_directive_handler.h
+++ b/components/history/core/browser/sync/delete_directive_handler.h
@@ -17,6 +17,8 @@
 #include "components/sync/model/sync_change_processor.h"
 #include "components/sync/model/sync_data.h"
 
+class GURL;
+
 namespace sync_pb {
 class HistoryDeleteDirectiveSpecifics;
 }
@@ -46,6 +48,8 @@
                               base::Time begin_time,
                               base::Time end_time);
 
+  bool CreateUrlDeleteDirective(const GURL& url);
+
   // Sends the given |delete_directive| to SyncChangeProcessor (if it exists).
   // Returns any error resulting from sending the delete directive to sync.
   // NOTE: the given |delete_directive| is not processed to remove local
diff --git a/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc b/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc
index faf0c23..ef960e1 100644
--- a/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc
+++ b/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc
@@ -18,10 +18,11 @@
     HistoryDeleteDirectivesModelTypeController(
         const base::RepeatingClosure& dump_stack,
         syncer::SyncService* sync_service,
+        syncer::ModelTypeStoreService* model_type_store_service,
         syncer::SyncClient* sync_client)
     : SyncableServiceBasedModelTypeController(
           syncer::HISTORY_DELETE_DIRECTIVES,
-          sync_client->GetModelTypeStoreService()->GetStoreFactory(),
+          model_type_store_service->GetStoreFactory(),
           base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
                          base::Unretained(sync_client),
                          syncer::HISTORY_DELETE_DIRECTIVES),
diff --git a/components/history/core/browser/sync/history_delete_directives_model_type_controller.h b/components/history/core/browser/sync/history_delete_directives_model_type_controller.h
index 07910a1..4c43cbb 100644
--- a/components/history/core/browser/sync/history_delete_directives_model_type_controller.h
+++ b/components/history/core/browser/sync/history_delete_directives_model_type_controller.h
@@ -11,6 +11,7 @@
 #include "components/sync/driver/syncable_service_based_model_type_controller.h"
 
 namespace syncer {
+class ModelTypeStoreService;
 class SyncClient;
 class SyncService;
 }  // namespace syncer
@@ -28,6 +29,7 @@
   HistoryDeleteDirectivesModelTypeController(
       const base::RepeatingClosure& dump_stack,
       syncer::SyncService* sync_service,
+      syncer::ModelTypeStoreService* model_type_store_service,
       syncer::SyncClient* sync_client);
   ~HistoryDeleteDirectivesModelTypeController() override;
 
diff --git a/components/invalidation/impl/fcm_invalidation_service_unittest.cc b/components/invalidation/impl/fcm_invalidation_service_unittest.cc
index 1945374..3f595c80 100644
--- a/components/invalidation/impl/fcm_invalidation_service_unittest.cc
+++ b/components/invalidation/impl/fcm_invalidation_service_unittest.cc
@@ -74,7 +74,7 @@
 
 class MockInstanceIDDriver : public InstanceIDDriver {
  public:
-  MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr){};
+  MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
   ~MockInstanceIDDriver() override = default;
 
   MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
diff --git a/components/invalidation/impl/fcm_network_handler_unittests.cc b/components/invalidation/impl/fcm_network_handler_unittests.cc
index 8da013c5..eb1b654 100644
--- a/components/invalidation/impl/fcm_network_handler_unittests.cc
+++ b/components/invalidation/impl/fcm_network_handler_unittests.cc
@@ -149,7 +149,7 @@
 
 class MockInstanceIDDriver : public InstanceIDDriver {
  public:
-  MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr){};
+  MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
   ~MockInstanceIDDriver() override = default;
 
   MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
diff --git a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
index 8d87f25..fd2db05b 100644
--- a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
@@ -90,7 +90,7 @@
   return response_status;
 }
 
-};  // namespace
+}  // namespace
 
 class RegistrationManagerStateObserver
     : public PerUserTopicRegistrationManager::Observer {
diff --git a/components/invalidation/impl/unacked_invalidation_set_test_util.cc b/components/invalidation/impl/unacked_invalidation_set_test_util.cc
index db0c67c..4f9f9b7 100644
--- a/components/invalidation/impl/unacked_invalidation_set_test_util.cc
+++ b/components/invalidation/impl/unacked_invalidation_set_test_util.cc
@@ -181,4 +181,4 @@
 
 }  // namespace test_util
 
-};
+}  // namespace syncer
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index 5ba9cdb9..53d277cd 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -11,9 +11,16 @@
 -->
 
 <grit-part>
+  <if expr="chromeos">
+    <message name="IDS_MANAGEMENT_TITLE" desc="Title of chrome://management page, which shows the administrator's capabilities in a managed environment">
+      <ph name="PRODUCT_NAME">$1<ex>Chrome OS</ex></ph> management
+    </message>
+  </if>
+  <if expr="not chromeos">
   <message name="IDS_MANAGEMENT_TITLE" desc="Title of chrome://management page, which shows the administrator's capabilities in a managed environment">
-    <ph name="PRODUCT_NAME">$1<ex>Chrome OS</ex></ph> management
-  </message>
+      Chrome Browser management
+    </message>
+  </if>
   <message name="IDS_MANAGEMENT_TITLE_BY" desc="Title of chrome://management page, shows when device managed by known organization">
     Device managed by <ph name="ENROLLMENT_DOMAIN">$1<ex>example.com</ex></ph>
   </message>
diff --git a/components/network_hints/renderer/dns_prefetch_queue_unittest.cc b/components/network_hints/renderer/dns_prefetch_queue_unittest.cc
index 4e8f3ae..d14ff72 100644
--- a/components/network_hints/renderer/dns_prefetch_queue_unittest.cc
+++ b/components/network_hints/renderer/dns_prefetch_queue_unittest.cc
@@ -263,4 +263,4 @@
   EXPECT_FALSE(tester.Pop());
 }
 
-};  // namespace network_hints
+}  // namespace network_hints
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
index 11fbcf9..317fe972 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
@@ -234,7 +234,7 @@
 }
 
 void SubscriptionManagerImpl::OnPrimaryAccountCleared(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   SigninStatusChanged();
 }
 
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.h b/components/ntp_snippets/breaking_news/subscription_manager_impl.h
index 1e769eaa..5090c464 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_impl.h
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl.h
@@ -69,7 +69,7 @@
  private:
   // identity:IdentityManager::Observer implementation.
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override;
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
 
   void SigninStatusChanged();
 
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc
index 33cdbba8..b38aee5 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -527,7 +527,7 @@
 }
 
 void ContentSuggestionsService::OnPrimaryAccountCleared(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   OnSignInStateChanged(/*has_signed_in=*/false);
 }
 
diff --git a/components/ntp_snippets/content_suggestions_service.h b/components/ntp_snippets/content_suggestions_service.h
index eb1954e..7e86d13 100644
--- a/components/ntp_snippets/content_suggestions_service.h
+++ b/components/ntp_snippets/content_suggestions_service.h
@@ -290,7 +290,7 @@
 
   // identity::IdentityManager::Observer implementation.
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override;
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
 
   // history::HistoryServiceObserver implementation.
   void OnURLsDeleted(history::HistoryService* history_service,
diff --git a/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc b/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
index c2be7aed..a139e12 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
+++ b/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
@@ -56,9 +56,9 @@
     : download_(false),
       delegate_called_(false),
       waiter_(base::WaitableEvent::ResetPolicy::MANUAL,
-              base::WaitableEvent::InitialState::NOT_SIGNALED){};
+              base::WaitableEvent::InitialState::NOT_SIGNALED) {}
 
-BackgroundLoaderContentsTest::~BackgroundLoaderContentsTest(){};
+BackgroundLoaderContentsTest::~BackgroundLoaderContentsTest() {}
 
 void BackgroundLoaderContentsTest::SetUp() {
   contents_.reset(new BackgroundLoaderContents());
diff --git a/components/offline_pages/core/offline_page_metadata_store_unittest.cc b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
index 3b400be..4eea0ca 100644
--- a/components/offline_pages/core/offline_page_metadata_store_unittest.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
@@ -539,7 +539,7 @@
         task_runner_handle_(task_runner_) {
     EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
   }
-  ~OfflinePageMetadataStoreTest() override{};
+  ~OfflinePageMetadataStoreTest() override {}
 
  protected:
   void TearDown() override {
diff --git a/components/password_manager/core/browser/import/csv_reader.cc b/components/password_manager/core/browser/import/csv_reader.cc
index 249ad094..8eb0d0eb 100644
--- a/components/password_manager/core/browser/import/csv_reader.cc
+++ b/components/password_manager/core/browser/import/csv_reader.cc
@@ -16,24 +16,27 @@
 namespace {
 
 // Returns all the characters from the start of |input| until the first '\n',
-// '\r' (exclusive) or the end of |input|. Cuts the returned part (inclusive the
-// line breaks) from |input|. Skips blocks of matching quotes. Examples:
+// "\r\n" (exclusive) or the end of |input|. Cuts the returned part (inclusive
+// the line breaks) from |input|. Skips blocks of matching quotes. Examples:
 // old input -> returned value, new input
 // "ab\ncd" -> "ab", "cd"
-// "\r\n" -> "", "\n"
+// "\r\n" -> "", ""
 // "abcd" -> "abcd", ""
+// "\r" -> "\r", ""
 // "a\"\n\"b" -> "a\"\n\"b", ""
 base::StringPiece ConsumeLine(base::StringPiece* input) {
   DCHECK(input);
   DCHECK(!input->empty());
 
   bool inside_quotes = false;
+  bool last_char_was_CR = false;
   for (size_t current = 0; current < input->size(); ++current) {
-    switch ((*input)[current]) {
+    char c = (*input)[current];
+    switch (c) {
       case '\n':
-      case '\r':
         if (!inside_quotes) {
-          base::StringPiece ret(input->data(), current);
+          const size_t eol_start = last_char_was_CR ? current - 1 : current;
+          base::StringPiece ret(input->data(), eol_start);
           *input = input->substr(current + 1);
           return ret;
         }
@@ -44,6 +47,7 @@
       default:
         break;
     }
+    last_char_was_CR = (c == '\r');
   }
 
   // The whole |*input| is one line.
@@ -296,12 +300,8 @@
   records_.clear();
   column_names_.clear();
 
-  // Normalize EOL sequences so that we uniformly use a single LF character.
-  std::string normalized_csv(csv);
-  base::ReplaceSubstringsAfterOffset(&normalized_csv, 0, "\r\n", "\n");
-
   // Read header row.
-  CSVParser parser(normalized_csv);
+  CSVParser parser(csv);
   if (!parser.HasMoreRows()) {
     // The empty CSV is a special case. It can be seen as having one row, with a
     // single field, which is an empty string.
@@ -316,10 +316,9 @@
   while (parser.HasMoreRows()) {
     if (!parser.ParseNextCSVRow(&fields))
       return false;
-    // If there are more line-breaking characters ('\r' or '\n') in sequence,
-    // the row parser will see an empty row in between each successive two of
-    // those. Discard such results, because those are useless for importing
-    // passwords.
+    // If there are more line-breaking characters in sequence, the row parser
+    // will see an empty row in between each successive two of those. Discard
+    // such results, because those are useless for importing passwords.
     if (fields.size() == 1 && fields[0].empty())
       continue;
 
diff --git a/components/password_manager/core/browser/import/csv_reader.h b/components/password_manager/core/browser/import/csv_reader.h
index d05c537d..48ebe5a 100644
--- a/components/password_manager/core/browser/import/csv_reader.h
+++ b/components/password_manager/core/browser/import/csv_reader.h
@@ -25,8 +25,7 @@
   // defined in RFC 4180, with the following limitations/relaxations:
   //   * The input should be UTF-8 encoded. No code points should be escaped.
   //   * The first line must be a header that contains the column names.
-  //   * Records may be separated by either LF or CRLF sequences. Each CRLF will
-  //     be converted to LF characters inside quotes.
+  //   * Records may be separated by either LF or CRLF sequences.
   //   * Inconsistent number of fields within records is handled gracefully.
   //     Extra fields are ignored. Missing fields will have no corresponding
   //     key-value pair in the record.
diff --git a/components/password_manager/core/browser/import/csv_reader_unittest.cc b/components/password_manager/core/browser/import/csv_reader_unittest.cc
index a69ccd6..f981540 100644
--- a/components/password_manager/core/browser/import/csv_reader_unittest.cc
+++ b/components/password_manager/core/browser/import/csv_reader_unittest.cc
@@ -104,7 +104,7 @@
           "\",\",\",,\"\n",
           {"left", "right"},
           {{{"left", "A\rB"}, {"right", "B\nC"}},
-           {{"left", "C\nD"}, {"right", "D\n"}},
+           {{"left", "C\r\nD"}, {"right", "D\n"}},
            {{"left", ","}, {"right", ",,"}}},
       },
       {
@@ -143,11 +143,19 @@
            {{"left", ""}, {"middle", ""}, {"right", "gamma"}}},
       },
       {
-          "CRLFTreatedAsAndConvertedToLF",
+          "CRLFTreatedAsLF",
           "left,right\r\n"
           "\"\r\",\"\r\n\"\r\n",
           {"left", "right"},
-          {{{"left", "\r"}, {"right", "\n"}}},
+          {{{"left", "\r"}, {"right", "\r\n"}}},
+      },
+      {
+          "CRAloneIgnored",
+          "left,right\r"
+          "A,B\r\n"
+          "1,2,3",
+          {"left", "right\rA", "B"},
+          {{{"B", "3"}, {"left", "1"}, {"right\rA", "2"}}},
       },
       {
           "LastValueForRepeatedColumnNamesIsPreserved",
@@ -167,13 +175,13 @@
           "foo,bar\n"
           "\n"
           "a,b\n"
-          "\r"
+          "\r\n"
           "c,d\r\r\r\r\r\r\r\r\n"
           "e,f",
           {"foo", "bar"},
           {
               {{"bar", "b"}, {"foo", "a"}},
-              {{"bar", "d"}, {"foo", "c"}},
+              {{"bar", "d\r\r\r\r\r\r\r"}, {"foo", "c"}},
               {{"bar", "f"}, {"foo", "e"}},
           },
       },
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.cc b/components/password_manager/core/browser/sync/password_model_type_controller.cc
index 71de60d8..db4dab36 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -4,6 +4,8 @@
 
 #include "components/password_manager/core/browser/sync/password_model_type_controller.h"
 
+#include <utility>
+
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/sync_client.h"
 #include "components/sync/driver/sync_service.h"
@@ -14,10 +16,10 @@
 PasswordModelTypeController::PasswordModelTypeController(
     std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk,
     syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client)
+    const base::RepeatingClosure& state_changed_callback)
     : ModelTypeController(syncer::PASSWORDS, std::move(delegate_on_disk)),
       sync_service_(sync_service),
-      sync_client_(sync_client) {}
+      state_changed_callback_(state_changed_callback) {}
 
 PasswordModelTypeController::~PasswordModelTypeController() = default;
 
@@ -27,7 +29,7 @@
   DCHECK(CalledOnValidThread());
   sync_service_->AddObserver(this);
   ModelTypeController::LoadModels(configure_context, model_load_callback);
-  sync_client_->GetPasswordStateChangedCallback().Run();
+  state_changed_callback_.Run();
 }
 
 void PasswordModelTypeController::Stop(syncer::ShutdownReason shutdown_reason,
@@ -35,12 +37,12 @@
   DCHECK(CalledOnValidThread());
   sync_service_->RemoveObserver(this);
   ModelTypeController::Stop(shutdown_reason, std::move(callback));
-  sync_client_->GetPasswordStateChangedCallback().Run();
+  state_changed_callback_.Run();
 }
 
 void PasswordModelTypeController::OnStateChanged(syncer::SyncService* sync) {
   DCHECK(CalledOnValidThread());
-  sync_client_->GetPasswordStateChangedCallback().Run();
+  state_changed_callback_.Run();
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.h b/components/password_manager/core/browser/sync/password_model_type_controller.h
index 3531bec..2593dab 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.h
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.h
@@ -5,13 +5,15 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_PASSWORD_MODEL_TYPE_CONTROLLER_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_PASSWORD_MODEL_TYPE_CONTROLLER_H_
 
+#include <memory>
+
+#include "base/callback.h"
 #include "base/macros.h"
 #include "components/sync/driver/model_type_controller.h"
 #include "components/sync/driver/sync_service_observer.h"
 
 namespace syncer {
 class ModelTypeControllerDelegate;
-class SyncClient;
 class SyncService;
 }  // namespace syncer
 
@@ -24,7 +26,7 @@
   PasswordModelTypeController(
       std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk,
       syncer::SyncService* sync_service,
-      syncer::SyncClient* sync_client);
+      const base::RepeatingClosure& state_changed_callback);
   ~PasswordModelTypeController() override;
 
   // DataTypeController overrides.
@@ -38,7 +40,7 @@
 
  private:
   syncer::SyncService* const sync_service_;
-  syncer::SyncClient* const sync_client_;
+  const base::RepeatingClosure state_changed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordModelTypeController);
 };
diff --git a/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.cc b/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.cc
index 4f866c6..0bc92f8 100644
--- a/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.cc
@@ -162,13 +162,15 @@
         const base::RepeatingClosure& dump_stack,
         scoped_refptr<PasswordStore> password_store,
         syncer::SyncService* sync_service,
-        syncer::SyncClient* sync_client)
+        syncer::SyncClient* sync_client,
+        const base::RepeatingClosure& state_changed_callback)
     : PasswordSyncableServiceBasedModelTypeController(
           std::move(store_factory),
           dump_stack,
           std::move(password_store),
           sync_service,
           sync_client,
+          state_changed_callback,
           base::MakeRefCounted<ModelCryptographerImpl>()) {}
 
 PasswordSyncableServiceBasedModelTypeController::
@@ -181,7 +183,7 @@
   sync_service_->AddObserver(this);
   NonUiSyncableServiceBasedModelTypeController::LoadModels(configure_context,
                                                            model_load_callback);
-  sync_client_->GetPasswordStateChangedCallback().Run();
+  state_changed_callback_.Run();
 }
 
 void PasswordSyncableServiceBasedModelTypeController::Stop(
@@ -191,7 +193,7 @@
   sync_service_->RemoveObserver(this);
   NonUiSyncableServiceBasedModelTypeController::Stop(shutdown_reason,
                                                      std::move(callback));
-  sync_client_->GetPasswordStateChangedCallback().Run();
+  state_changed_callback_.Run();
 }
 
 std::unique_ptr<syncer::SyncEncryptionHandler::Observer>
@@ -206,7 +208,7 @@
 void PasswordSyncableServiceBasedModelTypeController::OnStateChanged(
     syncer::SyncService* sync) {
   DCHECK(CalledOnValidThread());
-  sync_client_->GetPasswordStateChangedCallback().Run();
+  state_changed_callback_.Run();
 }
 
 PasswordSyncableServiceBasedModelTypeController::
@@ -216,6 +218,7 @@
         scoped_refptr<PasswordStore> password_store,
         syncer::SyncService* sync_service,
         syncer::SyncClient* sync_client,
+        const base::RepeatingClosure& state_changed_callback,
         scoped_refptr<ModelCryptographerImpl> model_cryptographer)
     : NonUiSyncableServiceBasedModelTypeController(
           syncer::PASSWORDS,
@@ -228,7 +231,8 @@
       background_task_runner_(password_store->GetBackgroundTaskRunner()),
       model_cryptographer_(model_cryptographer),
       sync_service_(sync_service),
-      sync_client_(sync_client) {
+      sync_client_(sync_client),
+      state_changed_callback_(state_changed_callback) {
   DCHECK(sync_service_);
   DCHECK(sync_client_);
   DCHECK(model_cryptographer_);
diff --git a/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.h b/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.h
index 67c5171..e25dd83 100644
--- a/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.h
+++ b/components/password_manager/core/browser/sync/password_syncable_service_based_model_type_controller.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "base/callback_forward.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "components/sync/driver/non_ui_syncable_service_based_model_type_controller.h"
 #include "components/sync/driver/sync_service_observer.h"
@@ -35,7 +35,8 @@
       const base::RepeatingClosure& dump_stack,
       scoped_refptr<PasswordStore> password_store,
       syncer::SyncService* sync_service,
-      syncer::SyncClient* sync_client);
+      syncer::SyncClient* sync_client,
+      const base::RepeatingClosure& state_changed_callback);
   ~PasswordSyncableServiceBasedModelTypeController() override;
 
   // DataTypeController overrides.
@@ -60,12 +61,14 @@
       scoped_refptr<PasswordStore> password_store,
       syncer::SyncService* sync_service,
       syncer::SyncClient* sync_client,
+      const base::RepeatingClosure& state_changed_callback,
       scoped_refptr<ModelCryptographerImpl> model_cryptographer);
 
   const scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
   const scoped_refptr<ModelCryptographerImpl> model_cryptographer_;
   syncer::SyncService* const sync_service_;
   syncer::SyncClient* const sync_client_;
+  const base::RepeatingClosure state_changed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordSyncableServiceBasedModelTypeController);
 };
diff --git a/components/previews/core/previews_logger_unittest.cc b/components/previews/core/previews_logger_unittest.cc
index 4e76854..4fe3cfd 100644
--- a/components/previews/core/previews_logger_unittest.cc
+++ b/components/previews/core/previews_logger_unittest.cc
@@ -70,7 +70,7 @@
   // Expose the received MessageLogs for testing.
   const std::vector<PreviewsLogger::MessageLog>& messages() const {
     return messages_;
-  };
+  }
 
   // Expose blacklist events info for testing.
   const std::unordered_map<std::string, base::Time>& blacklisted_hosts() {
diff --git a/components/search_engines/search_engine_data_type_controller_unittest.cc b/components/search_engines/search_engine_data_type_controller_unittest.cc
index acf765c9..52f9c3e3 100644
--- a/components/search_engines/search_engine_data_type_controller_unittest.cc
+++ b/components/search_engines/search_engine_data_type_controller_unittest.cc
@@ -18,9 +18,8 @@
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/data_type_controller_mock.h"
 #include "components/sync/driver/fake_generic_change_processor.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/fake_sync_service.h"
-#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/model/fake_syncable_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,25 +32,20 @@
 namespace browser_sync {
 namespace {
 
-class SyncSearchEngineDataTypeControllerTest : public testing::Test,
-                                               public syncer::FakeSyncClient {
+class SyncSearchEngineDataTypeControllerTest : public testing::Test {
  public:
   SyncSearchEngineDataTypeControllerTest()
-      : syncer::FakeSyncClient(&profile_sync_factory_),
-        template_url_service_(nullptr, 0),
+      : template_url_service_(nullptr, 0),
         search_engine_dtc_(base::RepeatingClosure(),
                            &sync_service_,
-                           this,
+                           &sync_client_,
                            &template_url_service_) {
     // Disallow the TemplateURLService from loading until
     // PreloadTemplateURLService() is called .
     template_url_service_.set_disable_load(true);
-  }
 
-  // FakeSyncClient overrides.
-  base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
-      syncer::ModelType type) override {
-    return syncable_service_.AsWeakPtr();
+    ON_CALL(sync_client_, GetSyncableServiceForType(syncer::SEARCH_ENGINES))
+        .WillByDefault(testing::Return(syncable_service_.AsWeakPtr()));
   }
 
   void TearDown() override {
@@ -86,11 +80,11 @@
   base::test::ScopedTaskEnvironment task_environment_;
   syncer::FakeSyncService sync_service_;
   TemplateURLService template_url_service_;
-  SearchEngineDataTypeController search_engine_dtc_;
-  syncer::SyncApiComponentFactoryMock profile_sync_factory_;
   syncer::FakeSyncableService syncable_service_;
+  testing::NiceMock<syncer::SyncClientMock> sync_client_;
   syncer::StartCallbackMock start_callback_;
   syncer::ModelLoadCallbackMock model_load_callback_;
+  SearchEngineDataTypeController search_engine_dtc_;
 };
 
 TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceReady) {
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc
index 1d055df..0cc9a34 100644
--- a/components/signin/core/browser/about_signin_internals.cc
+++ b/components/signin/core/browser/about_signin_internals.cc
@@ -440,7 +440,7 @@
 }
 
 void AboutSigninInternals::OnPrimaryAccountCleared(
-    const AccountInfo& primary_account_info) {
+    const CoreAccountInfo& primary_account_info) {
   NotifyObservers();
 }
 
diff --git a/components/signin/core/browser/about_signin_internals.h b/components/signin/core/browser/about_signin_internals.h
index 5eb722dc..fa974a9 100644
--- a/components/signin/core/browser/about_signin_internals.h
+++ b/components/signin/core/browser/about_signin_internals.h
@@ -219,7 +219,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& primary_account_info) override;
+      const CoreAccountInfo& primary_account_info) override;
 
   void NotifyTimedSigninFieldValueChanged(
       const signin_internals_util::TimedSigninStatusField& field,
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 57808ec..26dc4567 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -369,7 +369,7 @@
 }
 
 void AccountReconcilor::OnErrorStateOfRefreshTokenUpdatedForAccount(
-    const AccountInfo& account_info,
+    const CoreAccountInfo& account_info,
     const GoogleServiceAuthError& error) {
   // Gaia cookies may be invalidated server-side and the client does not get any
   // notification when this happens.
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index be934bf03..4fdeba0 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -279,7 +279,7 @@
   void OnEndBatchOfRefreshTokenStateChanges() override;
   void OnRefreshTokensLoaded() override;
   void OnErrorStateOfRefreshTokenUpdatedForAccount(
-      const AccountInfo& account_info,
+      const CoreAccountInfo& account_info,
       const GoogleServiceAuthError& error) override;
   void OnAddAccountToCookieCompleted(
       const std::string& account_id,
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 2ea9a77..5609213 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -152,14 +152,15 @@
     gaia::GaiaSource source)
     : request_type_(request_type), account_ids_(account_ids), source_(source) {}
 
-GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
-    const GaiaCookieManagerService::GaiaCookieRequest& other)
-    : request_type_(other.request_type()),
-      account_ids_(other.account_ids()),
-      source_(other.source()) {}
-
 GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {}
 
+GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
+    GaiaCookieRequest&&) = default;
+
+GaiaCookieManagerService::GaiaCookieRequest&
+GaiaCookieManagerService::GaiaCookieRequest::operator=(GaiaCookieRequest&&) =
+    default;
+
 const std::string GaiaCookieManagerService::GaiaCookieRequest::GetAccountID() {
   DCHECK_EQ(request_type_, GaiaCookieRequestType::ADD_ACCOUNT);
   DCHECK_EQ(1u, account_ids_.size());
@@ -614,7 +615,7 @@
 
       // Keep all requests except for ADD_ACCOUNTS.
       if (it->request_type() != GaiaCookieRequestType::ADD_ACCOUNT)
-        requests_to_keep.push_back(*it);
+        requests_to_keep.push_back(std::move(*it));
 
       // Verify a LOG_OUT isn't already queued.
       if (it->request_type() == GaiaCookieRequestType::LOG_OUT)
@@ -628,8 +629,9 @@
     // Remove all but the executing request. Re-add all requests being kept.
     if (requests_.size() > 1) {
       requests_.erase(requests_.begin() + 1, requests_.end());
-      requests_.insert(requests_.end(), requests_to_keep.begin(),
-                       requests_to_keep.end());
+      requests_.insert(requests_.end(),
+                       std::make_move_iterator(requests_to_keep.begin()),
+                       std::make_move_iterator(requests_to_keep.end()));
     }
   }
 
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.h b/components/signin/core/browser/gaia_cookie_manager_service.h
index b623d5a..cb7e4ff0 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -84,8 +84,9 @@
   // Contains the information and parameters for any request.
   class GaiaCookieRequest {
    public:
-    GaiaCookieRequest(const GaiaCookieRequest& other);
     ~GaiaCookieRequest();
+    GaiaCookieRequest(GaiaCookieRequest&&);
+    GaiaCookieRequest& operator=(GaiaCookieRequest&&);
 
     GaiaCookieRequestType request_type() const { return request_type_; }
     const std::vector<std::string>& account_ids() const { return account_ids_; }
@@ -109,9 +110,11 @@
                       const std::vector<std::string>& account_ids,
                       gaia::GaiaSource source);
 
-    const GaiaCookieRequestType request_type_;
-    const std::vector<std::string> account_ids_;
-    const gaia::GaiaSource source_;
+    GaiaCookieRequestType request_type_;
+    std::vector<std::string> account_ids_;
+    gaia::GaiaSource source_;
+
+    DISALLOW_COPY_AND_ASSIGN(GaiaCookieRequest);
   };
 
   class Observer {
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
index aa8fdfa..dec9591 100644
--- a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
+++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
@@ -67,7 +67,7 @@
 }
 
 void MirrorAccountReconcilorDelegate::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   reconcilor()->DisableReconcile(true /* logout_all_gaia_accounts */);
 }
 
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/components/signin/core/browser/mirror_account_reconcilor_delegate.h
index 30860f9..a1390475 100644
--- a/components/signin/core/browser/mirror_account_reconcilor_delegate.h
+++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -50,7 +50,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   identity::IdentityManager* identity_manager_;
 
diff --git a/components/signin/core/browser/resources/signin_index.html b/components/signin/core/browser/resources/signin_index.html
index 6d5db22..835d2d2c 100644
--- a/components/signin/core/browser/resources/signin_index.html
+++ b/components/signin/core/browser/resources/signin_index.html
@@ -5,7 +5,7 @@
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
-  <script src="chrome://signin-internals/strings.js"></script>
+  <script src="strings.js"></script>
   <if expr="is_ios">
     <!-- TODO(crbug.com/487000): Remove this once injected by the web layer. -->
     <script src="chrome://resources/js/ios/web_ui.js"></script>
@@ -109,8 +109,7 @@
     </div>
   </div>
 
-  <script src="chrome://resources/js/i18n_template.js"></script>
   <script src="chrome://resources/js/jstemplate_compiled.js"></script>
-  <script src="chrome://signin-internals/signin_internals.js"></script>
+  <script src="signin_internals.js"></script>
 </body>
 </html>
diff --git a/components/signin/core/browser/signin_error_controller.cc b/components/signin/core/browser/signin_error_controller.cc
index f478635d..21c5c29f 100644
--- a/components/signin/core/browser/signin_error_controller.cc
+++ b/components/signin/core/browser/signin_error_controller.cc
@@ -115,7 +115,7 @@
 }
 
 void SigninErrorController::OnErrorStateOfRefreshTokenUpdatedForAccount(
-    const AccountInfo& account_info,
+    const CoreAccountInfo& account_info,
     const GoogleServiceAuthError& error) {
   Update();
 }
@@ -130,7 +130,7 @@
 }
 
 void SigninErrorController::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   // Ignore updates to the primary account if not in PRIMARY_ACCOUNT mode.
   if (account_mode_ != AccountMode::PRIMARY_ACCOUNT)
     return;
diff --git a/components/signin/core/browser/signin_error_controller.h b/components/signin/core/browser/signin_error_controller.h
index f283eb0..6edab303 100644
--- a/components/signin/core/browser/signin_error_controller.h
+++ b/components/signin/core/browser/signin_error_controller.h
@@ -67,12 +67,12 @@
   // identity::IdentityManager::Observer:
   void OnEndBatchOfRefreshTokenStateChanges() override;
   void OnErrorStateOfRefreshTokenUpdatedForAccount(
-      const AccountInfo& account_info,
+      const CoreAccountInfo& account_info,
       const GoogleServiceAuthError& error) override;
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   const AccountMode account_mode_;
   identity::IdentityManager* identity_manager_;
diff --git a/components/signin/core/browser/signin_status_metrics_provider.cc b/components/signin/core/browser/signin_status_metrics_provider.cc
index 4e05689..3be467c 100644
--- a/components/signin/core/browser/signin_status_metrics_provider.cc
+++ b/components/signin/core/browser/signin_status_metrics_provider.cc
@@ -87,7 +87,7 @@
 }
 
 void SigninStatusMetricsProvider::OnPrimaryAccountCleared(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   SigninStatus recorded_signin_status = signin_status();
   if (recorded_signin_status == ALL_PROFILES_SIGNED_IN) {
     UpdateSigninStatus(MIXED_SIGNIN_STATUS);
diff --git a/components/signin/core/browser/signin_status_metrics_provider.h b/components/signin/core/browser/signin_status_metrics_provider.h
index 230fcde..1a027dc 100644
--- a/components/signin/core/browser/signin_status_metrics_provider.h
+++ b/components/signin/core/browser/signin_status_metrics_provider.h
@@ -71,7 +71,7 @@
 
   // IdentityManager::Observer:
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override;
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
 
   // Obtain sign-in status and add observers.
   void Initialize();
diff --git a/components/signin/ios/browser/account_consistency_service.h b/components/signin/ios/browser/account_consistency_service.h
index 19b4b11..87dd76d 100644
--- a/components/signin/ios/browser/account_consistency_service.h
+++ b/components/signin/ios/browser/account_consistency_service.h
@@ -158,7 +158,7 @@
   // IdentityManager::Observer implementation.
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_account_info) override;
+      const CoreAccountInfo& previous_account_info) override;
 
   // ActiveStateManager::Observer implementation.
   void OnActive() override;
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index c5c058b8..5ad66e2 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -497,7 +497,7 @@
 }
 
 void AccountConsistencyService::OnPrimaryAccountCleared(
-    const AccountInfo& previous_account_info) {
+    const CoreAccountInfo& previous_account_info) {
   // There is not need to remove CHROME_CONNECTED cookies on |GoogleSignedOut|
   // events as these cookies will be removed by the GaiaCookieManagerServer
   // right before fetching the Gaia logout request.
diff --git a/components/spellcheck/browser/spellcheck_host_metrics.cc b/components/spellcheck/browser/spellcheck_host_metrics.cc
index bfd92be..1565b64 100644
--- a/components/spellcheck/browser/spellcheck_host_metrics.cc
+++ b/components/spellcheck/browser/spellcheck_host_metrics.cc
@@ -8,6 +8,7 @@
 
 #include "base/md5.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
 
 SpellCheckHostMetrics::SpellCheckHostMetrics()
     : misspelled_word_count_(0),
@@ -18,7 +19,7 @@
       last_suggestion_show_count_(-1),
       replaced_word_count_(0),
       last_replaced_word_count_(-1),
-      last_unique_word_count_(-1),
+      last_unique_word_count_(0),
       start_time_(base::TimeTicks::Now()) {
   const uint64_t kHistogramTimerDurationInMinutes = 30;
   recording_timer_.Start(FROM_HERE,
@@ -32,7 +33,8 @@
 
 // static
 void SpellCheckHostMetrics::RecordCustomWordCountStats(size_t count) {
-  UMA_HISTOGRAM_COUNTS_1M("SpellCheck.CustomWords", count);
+  UMA_HISTOGRAM_COUNTS_1M("SpellCheck.CustomWords",
+                          base::saturated_cast<int>(count));
 }
 
 void SpellCheckHostMetrics::RecordEnabledStats(bool enabled) {
@@ -79,7 +81,7 @@
     size_t checked_words_per_hour = spellchecked_word_count_ *
         base::TimeDelta::FromHours(1).InSeconds() / since_start.InSeconds();
     UMA_HISTOGRAM_COUNTS_1M("SpellCheck.CheckedWordsPerHour",
-                            checked_words_per_hour);
+                            base::saturated_cast<int>(checked_words_per_hour));
   }
 }
 
@@ -133,10 +135,11 @@
     last_replaced_word_count_ = replaced_word_count_;
   }
 
-  if (((int)checked_word_hashes_.size()) != last_unique_word_count_) {
-    DCHECK((int)checked_word_hashes_.size() > last_unique_word_count_);
-    UMA_HISTOGRAM_COUNTS_1M("SpellCheck.UniqueWords",
-                            checked_word_hashes_.size());
+  if (checked_word_hashes_.size() != last_unique_word_count_) {
+    DCHECK(checked_word_hashes_.size() > last_unique_word_count_);
+    UMA_HISTOGRAM_COUNTS_1M(
+        "SpellCheck.UniqueWords",
+        base::saturated_cast<int>(checked_word_hashes_.size()));
     last_unique_word_count_ = checked_word_hashes_.size();
   }
 
diff --git a/components/spellcheck/browser/spellcheck_host_metrics.h b/components/spellcheck/browser/spellcheck_host_metrics.h
index 795e258..08e1e401 100644
--- a/components/spellcheck/browser/spellcheck_host_metrics.h
+++ b/components/spellcheck/browser/spellcheck_host_metrics.h
@@ -85,7 +85,7 @@
   int last_replaced_word_count_;
 
   // Last recorded number of unique words.
-  int last_unique_word_count_;
+  size_t last_unique_word_count_;
 
   // Time when first spellcheck happened.
   base::TimeTicks start_time_;
diff --git a/components/spellcheck/renderer/BUILD.gn b/components/spellcheck/renderer/BUILD.gn
index f5db20f..d993ecf 100644
--- a/components/spellcheck/renderer/BUILD.gn
+++ b/components/spellcheck/renderer/BUILD.gn
@@ -57,10 +57,6 @@
   if (!is_android) {
     deps += [ "//third_party/hunspell" ]
   }
-
-  if (is_win) {
-    cflags = [ "/wd4267" ]  # conversion from 'size_t' to 'int' on x64 (crbug.com/633312)
-  }
 }
 
 source_set("unit_tests") {
@@ -105,8 +101,4 @@
   if (is_mac && !is_ios) {
     deps += [ "//third_party/hunspell" ]
   }
-
-  if (is_win) {
-    cflags = [ "/wd4267" ]  # conversion from 'size_t' to 'int' on x64 (crbug.com/633312)
-  }
 }
diff --git a/components/spellcheck/renderer/custom_dictionary_engine.cc b/components/spellcheck/renderer/custom_dictionary_engine.cc
index e00b7ec..0e2fe22 100644
--- a/components/spellcheck/renderer/custom_dictionary_engine.cc
+++ b/components/spellcheck/renderer/custom_dictionary_engine.cc
@@ -35,15 +35,12 @@
     dictionary_.erase(base::UTF8ToUTF16(word));
 }
 
-bool CustomDictionaryEngine::SpellCheckWord(
-    const base::string16& text,
-    int misspelling_start,
-    int misspelling_len) {
+bool CustomDictionaryEngine::SpellCheckWord(const base::string16& text,
+                                            size_t misspelling_start,
+                                            size_t misspelling_len) {
   // The text to be checked is empty on OSX(async) right now.
   // TODO(groby): Fix as part of async hook-up. (http://crbug.com/178241)
-  return
-      misspelling_start >= 0 &&
-      misspelling_len > 0 &&
-      size_t(misspelling_start + misspelling_len) <= text.length() &&
-      dictionary_.count(text.substr(misspelling_start, misspelling_len)) > 0;
+  return misspelling_len > 0 &&
+         misspelling_start + misspelling_len <= text.length() &&
+         dictionary_.count(text.substr(misspelling_start, misspelling_len)) > 0;
 }
diff --git a/components/spellcheck/renderer/custom_dictionary_engine.h b/components/spellcheck/renderer/custom_dictionary_engine.h
index 52e37e6..33af501 100644
--- a/components/spellcheck/renderer/custom_dictionary_engine.h
+++ b/components/spellcheck/renderer/custom_dictionary_engine.h
@@ -26,8 +26,8 @@
   // |misspelling_start| and |misspelling_len| to indicate a misspelling.
   // Returns true if there are no misspellings, otherwise returns false.
   bool SpellCheckWord(const base::string16& text,
-                      int misspelling_start,
-                      int misspelling_len);
+                      size_t misspelling_start,
+                      size_t misspelling_len);
 
   // Update custom dictionary words.
   void OnCustomDictionaryChanged(const std::set<std::string>& words_added,
diff --git a/components/spellcheck/renderer/spellcheck.cc b/components/spellcheck/renderer/spellcheck.cc
index 67e8aa82..7ffa316 100644
--- a/components/spellcheck/renderer/spellcheck.cc
+++ b/components/spellcheck/renderer/spellcheck.cc
@@ -244,11 +244,11 @@
 
 bool SpellCheck::SpellCheckWord(
     const base::char16* text_begin,
-    int position_in_text,
-    int text_length,
+    size_t position_in_text,
+    size_t text_length,
     int tag,
-    int* misspelling_start,
-    int* misspelling_len,
+    size_t* misspelling_start,
+    size_t* misspelling_len,
     std::vector<base::string16>* optional_suggestions) {
   DCHECK(text_length >= position_in_text);
   DCHECK(misspelling_start && misspelling_len) << "Out vars must be given.";
@@ -260,10 +260,10 @@
 
   // These are for holding misspelling or skippable word positions and lengths
   // between calls to SpellcheckLanguage::SpellCheckWord.
-  int possible_misspelling_start;
-  int possible_misspelling_len;
+  size_t possible_misspelling_start;
+  size_t possible_misspelling_len;
   // The longest sequence of text that all languages agree is skippable.
-  int agreed_skippable_len;
+  size_t agreed_skippable_len;
   // A vector of vectors containing spelling suggestions from different
   // languages.
   std::vector<std::vector<base::string16>> suggestions_list;
@@ -356,8 +356,8 @@
   // position and length of the first misspelled word and returns false when
   // the text includes misspelled words. Therefore, we just repeat calling the
   // function until it returns true to check the whole text.
-  int misspelling_start = 0;
-  int misspelling_length = 0;
+  size_t misspelling_start = 0;
+  size_t misspelling_length = 0;
   while (position_in_text <= length) {
     if (SpellCheckWord(text.c_str(), position_in_text, length, kNoTag,
                        &misspelling_start, &misspelling_length, nullptr)) {
@@ -369,7 +369,8 @@
             text, misspelling_start, misspelling_length)) {
       textcheck_results.push_back(
           WebTextCheckingResult(blink::kWebTextDecorationTypeSpelling,
-                                misspelling_start, misspelling_length));
+                                base::checked_cast<int>(misspelling_start),
+                                base::checked_cast<int>(misspelling_length)));
     }
     position_in_text = misspelling_start + misspelling_length;
   }
@@ -485,8 +486,8 @@
       // Double-check misspelled words with out spellchecker and attach grammar
       // markers to them if our spellchecker tells us they are correct words,
       // i.e. they are probably contextually-misspelled words.
-      int unused_misspelling_start = 0;
-      int unused_misspelling_length = 0;
+      size_t unused_misspelling_start = 0;
+      size_t unused_misspelling_length = 0;
       if (decoration == SpellCheckResult::SPELLING &&
           SpellCheckWord(misspelled_word.c_str(), kNoOffset,
                          misspelled_word.length(), kNoTag,
diff --git a/components/spellcheck/renderer/spellcheck.h b/components/spellcheck/renderer/spellcheck.h
index 44c1168..e12e4f9 100644
--- a/components/spellcheck/renderer/spellcheck.h
+++ b/components/spellcheck/renderer/spellcheck.h
@@ -86,11 +86,11 @@
   // If optional_suggestions is NULL, suggested words will not be looked up.
   // Note that doing suggest lookups can be slow.
   bool SpellCheckWord(const base::char16* text_begin,
-                      int position_in_text,
-                      int text_length,
+                      size_t position_in_text,
+                      size_t text_length,
                       int tag,
-                      int* misspelling_start,
-                      int* misspelling_len,
+                      size_t* misspelling_start,
+                      size_t* misspelling_len,
                       std::vector<base::string16>* optional_suggestions);
 
   // SpellCheck a paragraph.
diff --git a/components/spellcheck/renderer/spellcheck_language.cc b/components/spellcheck/renderer/spellcheck_language.cc
index a518c43..391e36a 100644
--- a/components/spellcheck/renderer/spellcheck_language.cc
+++ b/components/spellcheck/renderer/spellcheck_language.cc
@@ -34,16 +34,16 @@
 
 SpellcheckLanguage::SpellcheckWordResult SpellcheckLanguage::SpellCheckWord(
     const base::char16* text_begin,
-    int position_in_text,
-    int text_length,
+    size_t position_in_text,
+    size_t text_length,
     int tag,
-    int* skip_or_misspelling_start,
-    int* skip_or_misspelling_len,
+    size_t* skip_or_misspelling_start,
+    size_t* skip_or_misspelling_len,
     std::vector<base::string16>* optional_suggestions) {
-  int remaining_text_len = text_length - position_in_text;
-  DCHECK(remaining_text_len >= 0);
+  DCHECK_GE(text_length, position_in_text);
   DCHECK(skip_or_misspelling_start && skip_or_misspelling_len)
       << "Out vars must be given.";
+  size_t remaining_text_len = text_length - position_in_text;
 
   // Do nothing if we need to delay initialization. (Rather than blocking,
   // report the word as correctly spelled.)
@@ -60,8 +60,8 @@
     return IS_CORRECT;  // No input means always spelled correctly.
 
   base::string16 word;
-  int word_start;
-  int word_length;
+  size_t word_start;
+  size_t word_length;
   if (!text_iterator_.IsInitialized() &&
       !text_iterator_.Initialize(&character_attributes_, true)) {
       // We failed to initialize text_iterator_, return as spelled correctly.
@@ -126,8 +126,8 @@
   contraction_iterator_.SetText(contraction.c_str(), contraction.length());
 
   base::string16 word;
-  int word_start;
-  int word_length;
+  size_t word_start;
+  size_t word_length;
 
   DCHECK(platform_spelling_engine_);
   for (SpellcheckWordIterator::WordIteratorStatus status =
diff --git a/components/spellcheck/renderer/spellcheck_language.h b/components/spellcheck/renderer/spellcheck_language.h
index 98bcf60..082ce80 100644
--- a/components/spellcheck/renderer/spellcheck_language.h
+++ b/components/spellcheck/renderer/spellcheck_language.h
@@ -58,15 +58,15 @@
   //   |skip_or_misspelling_start| and |skip_or_misspelling_len| are then set to
   //   the position and length of the misspelled word. In addition, finds the
   //   suggested words for a given misspelled word and puts them into
-  //   |*optional_suggestions|. If optional_suggestions is NULL, suggested words
-  //   will not be looked up. Note that doing suggest lookups can be slow.
+  //   |*optional_suggestions|. If optional_suggestions is nullptr, suggested
+  //   words will not be looked up. Note that doing suggest lookups can be slow.
   SpellcheckWordResult SpellCheckWord(
       const base::char16* text_begin,
-      int position_in_text,
-      int text_length,
+      size_t position_in_text,
+      size_t text_length,
       int tag,
-      int* skip_or_misspelling_start,
-      int* skip_or_misspelling_len,
+      size_t* skip_or_misspelling_start,
+      size_t* skip_or_misspelling_len,
       std::vector<base::string16>* optional_suggestions);
 
   // Initialize |spellcheck_| if that hasn't happened yet.
diff --git a/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc b/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
index f356798..62bbdac 100644
--- a/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
@@ -31,8 +31,8 @@
   // A string of text for checking.
   const wchar_t* input;
   // The position and the length of the first misspelled word, if any.
-  int expected_misspelling_start;
-  int expected_misspelling_length;
+  size_t expected_misspelling_start;
+  size_t expected_misspelling_length;
 };
 
 base::FilePath GetHunspellDirectory() {
@@ -82,8 +82,8 @@
     ReinitializeSpellCheck(languages);
 
     for (size_t i = 0; i < num_test_cases; ++i) {
-      int misspelling_start = 0;
-      int misspelling_length = 0;
+      size_t misspelling_start = 0;
+      size_t misspelling_length = 0;
       static_cast<blink::WebTextCheckClient*>(provider())
           ->CheckSpelling(blink::WebString::FromUTF16(
                               base::WideToUTF16(test_cases[i].input)),
@@ -225,8 +225,8 @@
     // A string of text for checking.
     const wchar_t* input;
     // The position and the length of the first invalid word.
-    int expected_misspelling_start;
-    int expected_misspelling_length;
+    size_t expected_misspelling_start;
+    size_t expected_misspelling_length;
     // A comma separated string of suggested words that should occur, in their
     // expected order.
     const wchar_t* expected_suggestions;
@@ -240,8 +240,8 @@
 
   for (size_t i = 0; i < base::size(kTestCases); ++i) {
     blink::WebVector<blink::WebString> suggestions;
-    int misspelling_start;
-    int misspelling_length;
+    size_t misspelling_start;
+    size_t misspelling_length;
     static_cast<blink::WebTextCheckClient*>(provider())
         ->CheckSpelling(
             blink::WebString::FromUTF16(base::WideToUTF16(kTestCases[i].input)),
diff --git a/components/spellcheck/renderer/spellcheck_provider.cc b/components/spellcheck/renderer/spellcheck_provider.cc
index 67b3a96e..ad3325e 100644
--- a/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/components/spellcheck/renderer/spellcheck_provider.cc
@@ -161,8 +161,8 @@
 
 void SpellCheckProvider::CheckSpelling(
     const WebString& text,
-    int& offset,
-    int& length,
+    size_t& offset,
+    size_t& length,
     WebVector<WebString>* optional_suggestions) {
   base::string16 word = text.Utf16();
   std::vector<base::string16> suggestions;
@@ -176,9 +176,11 @@
         suggestions.begin(), suggestions.end(), web_suggestions.begin(),
         [](const base::string16& s) { return WebString::FromUTF16(s); });
     *optional_suggestions = web_suggestions;
-    UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.check.suggestions", word.size());
+    UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.check.suggestions",
+                            base::saturated_cast<int>(word.size()));
   } else {
-    UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.check", word.size());
+    UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.check",
+                            base::saturated_cast<int>(word.size()));
     // If optional_suggestions is not requested, the API is called
     // for marking.  So we use this for counting markable words.
     GetSpellCheckHost().NotifyChecked(word, 0 < length);
@@ -189,7 +191,8 @@
     const WebString& text,
     WebTextCheckingCompletion* completion) {
   RequestTextChecking(text.Utf16(), completion);
-  UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.async", text.length());
+  UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.async",
+                          base::saturated_cast<int>(text.length()));
 }
 
 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
@@ -226,11 +229,10 @@
 }
 #endif
 
-bool SpellCheckProvider::HasWordCharacters(
-    const base::string16& text,
-    int index) const {
+bool SpellCheckProvider::HasWordCharacters(const base::string16& text,
+                                           size_t index) const {
   const base::char16* data = text.data();
-  int length = text.length();
+  size_t length = text.length();
   while (index < length) {
     uint32_t code = 0;
     U16_NEXT(data, index, length, code);
diff --git a/components/spellcheck/renderer/spellcheck_provider.h b/components/spellcheck/renderer/spellcheck_provider.h
index 2a5f671..392186a 100644
--- a/components/spellcheck/renderer/spellcheck_provider.h
+++ b/components/spellcheck/renderer/spellcheck_provider.h
@@ -90,8 +90,8 @@
   bool IsSpellCheckingEnabled() const override;
   void CheckSpelling(
       const blink::WebString& text,
-      int& offset,
-      int& length,
+      size_t& offset,
+      size_t& length,
       blink::WebVector<blink::WebString>* optional_suggestions) override;
   void RequestCheckingOfText(
       const blink::WebString& text,
@@ -106,7 +106,7 @@
 
   // Returns whether |text| has word characters, i.e. whether a spellchecker
   // needs to check this text.
-  bool HasWordCharacters(const base::string16& text, int index) const;
+  bool HasWordCharacters(const base::string16& text, size_t index) const;
 
 #if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
   void OnRespondTextCheck(
diff --git a/components/spellcheck/renderer/spellcheck_unittest.cc b/components/spellcheck/renderer/spellcheck_unittest.cc
index 12866ada..0d84e85 100644
--- a/components/spellcheck/renderer/spellcheck_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -188,8 +188,8 @@
     //   * false: the input string has one or more invalid words.
     bool expected_result;
     // The position and the length of the first invalid word.
-    int misspelling_start;
-    int misspelling_length;
+    size_t misspelling_start;
+    size_t misspelling_length;
   } kTestCases[] = {
     // Empty strings.
     {L"", true},
@@ -406,12 +406,11 @@
     size_t input_length = 0;
     if (kTestCases[i].input)
       input_length = wcslen(kTestCases[i].input);
-    int misspelling_start;
-    int misspelling_length;
+    size_t misspelling_start;
+    size_t misspelling_length;
     bool result = spell_check()->SpellCheckWord(
-        base::WideToUTF16(kTestCases[i].input).c_str(), kNoOffset,
-        static_cast<int>(input_length), kNoTag, &misspelling_start,
-        &misspelling_length, nullptr);
+        base::WideToUTF16(kTestCases[i].input).c_str(), kNoOffset, input_length,
+        kNoTag, &misspelling_start, &misspelling_length, nullptr);
 
     EXPECT_EQ(kTestCases[i].expected_result, result);
     EXPECT_EQ(kTestCases[i].misspelling_start, misspelling_start);
@@ -455,12 +454,11 @@
     size_t input_length = 0;
     if (test_case.input)
       input_length = wcslen(test_case.input);
-    int misspelling_start;
-    int misspelling_length;
+    size_t misspelling_start;
+    size_t misspelling_length;
     bool result = spell_check()->SpellCheckWord(
-        base::WideToUTF16(test_case.input).c_str(), kNoOffset,
-        static_cast<int>(input_length), kNoTag, &misspelling_start,
-        &misspelling_length, &suggestions);
+        base::WideToUTF16(test_case.input).c_str(), kNoOffset, input_length,
+        kNoTag, &misspelling_start, &misspelling_length, &suggestions);
 
     // Check for spelling.
     EXPECT_EQ(test_case.expected_result, result);
@@ -830,12 +828,11 @@
     if (kTestCases[i].input)
       input_length = wcslen(kTestCases[i].input);
 
-    int misspelling_start = 0;
-    int misspelling_length = 0;
+    size_t misspelling_start = 0;
+    size_t misspelling_length = 0;
     bool result = spell_check()->SpellCheckWord(
-        base::WideToUTF16(kTestCases[i].input).c_str(), kNoOffset,
-        static_cast<int>(input_length), kNoTag, &misspelling_start,
-        &misspelling_length, nullptr);
+        base::WideToUTF16(kTestCases[i].input).c_str(), kNoOffset, input_length,
+        kNoTag, &misspelling_start, &misspelling_length, nullptr);
 
     EXPECT_TRUE(result)
         << "\""
@@ -844,8 +841,8 @@
         << "\" is misspelled in "
         << kTestCases[i].language
         << ".";
-    EXPECT_EQ(0, misspelling_start);
-    EXPECT_EQ(0, misspelling_length);
+    EXPECT_EQ(0u, misspelling_start);
+    EXPECT_EQ(0u, misspelling_length);
   }
 }
 
@@ -887,14 +884,14 @@
     ReinitializeSpellCheck(kTestCases[i].language);
 
     base::string16 word(base::WideToUTF16(kTestCases[i].input));
-    int word_length = static_cast<int>(word.length());
-    int misspelling_start = 0;
-    int misspelling_length = 0;
+    size_t word_length = word.length();
+    size_t misspelling_start = 0;
+    size_t misspelling_length = 0;
     bool result = spell_check()->SpellCheckWord(
         word.c_str(), kNoOffset, word_length, kNoTag, &misspelling_start,
         &misspelling_length, nullptr);
     EXPECT_FALSE(result);
-    EXPECT_EQ(0, misspelling_start);
+    EXPECT_EQ(0u, misspelling_start);
     EXPECT_EQ(word_length, misspelling_length);
   }
 }
@@ -1298,12 +1295,12 @@
       if (kTestCases[i].input)
         input_length = strlen(kTestCases[i].input);
 
-      int misspelling_start = 0;
-      int misspelling_length = 0;
+      size_t misspelling_start = 0;
+      size_t misspelling_length = 0;
       bool result = spell_check()->SpellCheckWord(
           base::ASCIIToUTF16(kTestCases[i].input).c_str(), kNoOffset,
-          static_cast<int>(input_length), kNoTag, &misspelling_start,
-          &misspelling_length, nullptr);
+          input_length, kNoTag, &misspelling_start, &misspelling_length,
+          nullptr);
 
       EXPECT_EQ(kTestCases[i].should_pass, result) << kTestCases[i].input <<
           " in " << kLocales[j];
@@ -1342,12 +1339,12 @@
 
     // First check that the NOSUGGEST flag didn't mark this word as not being in
     // the dictionary.
-    int misspelling_start = 0;
-    int misspelling_length = 0;
+    size_t misspelling_start = 0;
+    size_t misspelling_length = 0;
     bool result = spell_check()->SpellCheckWord(
         base::ASCIIToUTF16(test_case.suggestion).c_str(), kNoOffset,
-        static_cast<int>(suggestion_length), kNoTag, &misspelling_start,
-        &misspelling_length, nullptr);
+        suggestion_length, kNoTag, &misspelling_start, &misspelling_length,
+        nullptr);
 
     EXPECT_EQ(test_case.should_pass, result)
         << test_case.suggestion << " in " << test_case.locale;
@@ -1360,7 +1357,7 @@
       input_length = strlen(test_case.input);
     result = spell_check()->SpellCheckWord(
         base::ASCIIToUTF16(test_case.input).c_str(), kNoOffset,
-        static_cast<int>(input_length), kNoTag, &misspelling_start,
+        input_length, kNoTag, &misspelling_start,
         &misspelling_length, &suggestions);
     // Input word should be a misspelling.
     EXPECT_FALSE(result) << test_case.input << " is not a misspelling in "
@@ -1443,8 +1440,8 @@
   };
 
   for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    int misspelling_start = 0;
-    int misspelling_length = 0;
+    size_t misspelling_start = 0;
+    size_t misspelling_length = 0;
     std::vector<base::string16> suggestions;
     EXPECT_FALSE(spell_check()->SpellCheckWord(
         base::ASCIIToUTF16(kTestCases[i].misspelled).c_str(),
diff --git a/components/spellcheck/renderer/spellcheck_worditerator.cc b/components/spellcheck/renderer/spellcheck_worditerator.cc
index 00351e19..8fe8a6d 100644
--- a/components/spellcheck/renderer/spellcheck_worditerator.cc
+++ b/components/spellcheck/renderer/spellcheck_worditerator.cc
@@ -364,8 +364,8 @@
 
 SpellcheckWordIterator::WordIteratorStatus SpellcheckWordIterator::GetNextWord(
     base::string16* word_string,
-    int* word_start,
-    int* word_length) {
+    size_t* word_start,
+    size_t* word_length) {
   DCHECK(!!text_);
 
   word_string->clear();
@@ -414,8 +414,8 @@
   iterator_.reset();
 }
 
-bool SpellcheckWordIterator::Normalize(int input_start,
-                                       int input_length,
+bool SpellcheckWordIterator::Normalize(size_t input_start,
+                                       size_t input_length,
                                        base::string16* output_string) const {
   // We use NFKC (Normalization Form, Compatible decomposition, followed by
   // canonical Composition) defined in Unicode Standard Annex #15 to normalize
@@ -424,7 +424,8 @@
   // spellchecker and we need manual normalization as well. The normalized
   // text does not have to be NUL-terminated since its characters are copied to
   // string16, which adds a NUL character when we need.
-  icu::UnicodeString input(FALSE, &text_[input_start], input_length);
+  icu::UnicodeString input(FALSE, &text_[input_start],
+                           base::checked_cast<int32_t>(input_length));
   UErrorCode status = U_ZERO_ERROR;
   icu::UnicodeString output;
   icu::Normalizer::normalize(input, UNORM_NFKC, 0, output, status);
diff --git a/components/spellcheck/renderer/spellcheck_worditerator.h b/components/spellcheck/renderer/spellcheck_worditerator.h
index ea2f038..cf3d6cf 100644
--- a/components/spellcheck/renderer/spellcheck_worditerator.h
+++ b/components/spellcheck/renderer/spellcheck_worditerator.h
@@ -165,8 +165,10 @@
   //    length into |word_string|, |word_start|, and |word_length| respectively.
   //
   //  - Returns IS_END_OF_TEXT if the iterator has reached the end of |text_|.
-  SpellcheckWordIterator::WordIteratorStatus
-  GetNextWord(base::string16* word_string, int* word_start, int* word_length);
+  SpellcheckWordIterator::WordIteratorStatus GetNextWord(
+      base::string16* word_string,
+      size_t* word_start,
+      size_t* word_length);
 
   // Releases all the resources attached to this object.
   void Reset();
@@ -179,8 +181,8 @@
   // alternative characters supported by our spellchecker. This function also
   // calls SpellcheckWordIterator::OutputChar() to filter out false-positive
   // characters.
-  bool Normalize(int input_start,
-                 int input_length,
+  bool Normalize(size_t input_start,
+                 size_t input_length,
                  base::string16* output_string) const;
 
   // The pointer to the input string from which we are extracting words.
diff --git a/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc b/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
index e415d5e..4ab4c4f3 100644
--- a/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
@@ -35,8 +35,8 @@
 
 WordIteratorStatus GetNextNonSkippableWord(SpellcheckWordIterator* iterator,
                                            base::string16* word_string,
-                                           int* word_start,
-                                           int* word_length) {
+                                           size_t* word_start,
+                                           size_t* word_length) {
   WordIteratorStatus status = SpellcheckWordIterator::IS_SKIPPABLE;
   while (status == SpellcheckWordIterator::IS_SKIPPABLE)
     status = iterator->GetNextWord(word_string, word_start, word_length);
@@ -174,7 +174,7 @@
         base::string16(1, ' '), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
     base::string16 actual_word;
-    int actual_start, actual_len;
+    size_t actual_start, actual_len;
     size_t index = 0;
     for (SpellcheckWordIterator::WordIteratorStatus status =
              iterator.GetNextWord(&actual_word, &actual_start, &actual_len);
@@ -210,13 +210,13 @@
   // iterator.GetNextWord() calls get stuck in an infinite loop. Therefore, this
   // test succeeds if this call returns without timeouts.
   base::string16 actual_word;
-  int actual_start, actual_len;
+  size_t actual_start, actual_len;
   WordIteratorStatus status = GetNextNonSkippableWord(
       &iterator, &actual_word, &actual_start, &actual_len);
 
   EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_END_OF_TEXT, status);
-  EXPECT_EQ(0, actual_start);
-  EXPECT_EQ(0, actual_len);
+  EXPECT_EQ(0u, actual_start);
+  EXPECT_EQ(0u, actual_len);
 }
 
 // Vertify our SpellcheckWordIterator can treat ASCII numbers as word characters
@@ -274,7 +274,7 @@
     EXPECT_TRUE(iterator.SetText(input_word.c_str(), input_word.length()));
 
     base::string16 actual_word;
-    int actual_start, actual_len;
+    size_t actual_start, actual_len;
     WordIteratorStatus status = GetNextNonSkippableWord(
         &iterator, &actual_word, &actual_start, &actual_len);
 
@@ -319,15 +319,14 @@
     EXPECT_TRUE(iterator.SetText(input_word.c_str(), input_word.length()));
 
     base::string16 actual_word;
-    int actual_start, actual_len;
+    size_t actual_start, actual_len;
     WordIteratorStatus status = GetNextNonSkippableWord(
         &iterator, &actual_word, &actual_start, &actual_len);
 
     EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_WORD, status);
     EXPECT_EQ(expected_word, actual_word);
-    EXPECT_LE(0, actual_start);
-    EXPECT_EQ(expected_word.length(),
-              static_cast<base::string16::size_type>(actual_len));
+    EXPECT_LE(0u, actual_start);
+    EXPECT_EQ(expected_word.length(), actual_len);
   }
 }
 
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index 8828d086..671afe9 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -725,7 +725,7 @@
     EXPECT_EQ(mojom::ActivationLevel::kDisabled,
               *observer()->GetPageActivationForLastCommittedLoad());
   }
-};
+}
 
 // Only main frames with http/https schemes should activate.
 TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
@@ -759,7 +759,7 @@
     EXPECT_EQ(test_data.expected_activation_level,
               *observer()->GetPageActivationForLastCommittedLoad());
   }
-};
+}
 
 TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
        ListNotMatched_NoActivation) {
diff --git a/components/supervised_user_error_page/supervised_user_error_page.cc b/components/supervised_user_error_page/supervised_user_error_page.cc
index 1aaa3bc7..bc630de1 100644
--- a/components/supervised_user_error_page/supervised_user_error_page.cc
+++ b/components/supervised_user_error_page/supervised_user_error_page.cc
@@ -34,7 +34,7 @@
     // Check if the URL already contains the monogram (-mo) option.
     // In that case, we must use the '-' separator, instead of '/'.
     std::string separator = result.substr(slash - 3, 3) == "/mo" ? "-" : "/";
-    result.insert(slash, separator + "s" + base::IntToString(size) + "-c");
+    result.insert(slash, separator + "s" + base::NumberToString(size) + "-c");
   }
   return result;
 }
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index a84bb0cf..8cc12a5 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -803,8 +803,6 @@
     "driver/fake_data_type_controller.h",
     "driver/fake_generic_change_processor.cc",
     "driver/fake_generic_change_processor.h",
-    "driver/fake_sync_client.cc",
-    "driver/fake_sync_client.h",
     "driver/fake_sync_service.cc",
     "driver/fake_sync_service.h",
     "driver/frontend_data_type_controller_mock.cc",
diff --git a/components/sync/base/data_type_histogram.h b/components/sync/base/data_type_histogram.h
index e0bf40d..4ac42ff 100644
--- a/components/sync/base/data_type_histogram.h
+++ b/components/sync/base/data_type_histogram.h
@@ -170,6 +170,9 @@
       case ::syncer::SEND_TAB_TO_SELF:                           \
         PER_DATA_TYPE_MACRO("SendTabToSelf");                    \
         break;                                                   \
+      case ::syncer::SECURITY_EVENTS:                            \
+        PER_DATA_TYPE_MACRO("SecurityEvents");                   \
+        break;                                                   \
       default:                                                   \
         NOTREACHED() << "Unknown datatype "                      \
                      << ::syncer::ModelTypeToString(datatype);   \
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h
index e4d6154d..fb78756 100644
--- a/components/sync/base/model_type.h
+++ b/components/sync/base/model_type.h
@@ -138,6 +138,8 @@
   USER_CONSENTS,
   // Tabs sent between devices.
   SEND_TAB_TO_SELF,
+  // Commit only security events.
+  SECURITY_EVENTS,
 
   // ---- Proxy types ----
   // Proxy types are excluded from the sync protocol, but are still considered
@@ -217,7 +219,7 @@
       DEPRECATED_SUPERVISED_USER_SHARED_SETTINGS, DEPRECATED_ARTICLES, APP_LIST,
       DEPRECATED_WIFI_CREDENTIALS, SUPERVISED_USER_WHITELISTS, ARC_PACKAGE,
       PRINTERS, READING_LIST, USER_EVENTS, NIGORI, EXPERIMENTS, MOUNTAIN_SHARES,
-      USER_CONSENTS, SEND_TAB_TO_SELF);
+      USER_CONSENTS, SEND_TAB_TO_SELF, SECURITY_EVENTS);
 }
 
 // These are the normal user-controlled types. This is to distinguish from
@@ -285,7 +287,7 @@
 
 // Types that may commit data, but should never be included in a GetUpdates.
 constexpr ModelTypeSet CommitOnlyTypes() {
-  return ModelTypeSet(USER_EVENTS, USER_CONSENTS);
+  return ModelTypeSet(USER_EVENTS, USER_CONSENTS, SECURITY_EVENTS);
 }
 
 ModelTypeNameMap GetUserSelectableTypeNameMap();
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index 0b4267b..ae0536a5 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -397,6 +397,7 @@
     case ARC_PACKAGE:
     case PRINTERS:
     case USER_EVENTS:
+    case SECURITY_EVENTS:
     case MOUNTAIN_SHARES:
     case USER_CONSENTS:
     case SEND_TAB_TO_SELF:
diff --git a/components/sync/driver/async_directory_type_controller_unittest.cc b/components/sync/driver/async_directory_type_controller_unittest.cc
index 14d2d99..fa8109a 100644
--- a/components/sync/driver/async_directory_type_controller_unittest.cc
+++ b/components/sync/driver/async_directory_type_controller_unittest.cc
@@ -22,9 +22,9 @@
 #include "components/sync/driver/async_directory_type_controller_mock.h"
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/data_type_controller_mock.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/fake_sync_service.h"
 #include "components/sync/driver/generic_change_processor_factory.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/engine/model_safe_worker.h"
 #include "components/sync/model/fake_syncable_service.h"
 #include "components/sync/model/sync_change.h"
@@ -32,9 +32,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
-
-class SyncClient;
-
 namespace {
 
 using base::WaitableEvent;
@@ -175,8 +172,7 @@
   DISALLOW_COPY_AND_ASSIGN(AsyncDirectoryTypeControllerFake);
 };
 
-class SyncAsyncDirectoryTypeControllerTest : public testing::Test,
-                                             public FakeSyncClient {
+class SyncAsyncDirectoryTypeControllerTest : public testing::Test {
  public:
   SyncAsyncDirectoryTypeControllerTest()
       : scoped_task_environment_(
@@ -190,7 +186,7 @@
     dtc_mock_ =
         std::make_unique<StrictMock<AsyncDirectoryTypeControllerMock>>();
     non_ui_dtc_ = std::make_unique<AsyncDirectoryTypeControllerFake>(
-        &sync_service_, this, dtc_mock_.get(), change_processor_.get(),
+        &sync_service_, &sync_client_, dtc_mock_.get(), change_processor_.get(),
         backend_thread_.task_runner());
   }
 
@@ -260,6 +256,7 @@
   StartCallbackMock start_callback_;
   ModelLoadCallbackMock model_load_callback_;
   FakeSyncService sync_service_;
+  testing::NiceMock<SyncClientMock> sync_client_;
   // Must be destroyed after non_ui_dtc_.
   FakeSyncableService syncable_service_;
   std::unique_ptr<AsyncDirectoryTypeControllerFake> non_ui_dtc_;
diff --git a/components/sync/driver/fake_sync_client.cc b/components/sync/driver/fake_sync_client.cc
deleted file mode 100644
index be5e1cf..0000000
--- a/components/sync/driver/fake_sync_client.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/driver/fake_sync_client.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "components/sync/base/extensions_activity.h"
-#include "components/sync/base/sync_prefs.h"
-
-namespace syncer {
-
-FakeSyncClient::FakeSyncClient() : factory_(nullptr) {
-  // Register sync preferences and set them to "Sync everything" state.
-  SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
-}
-
-FakeSyncClient::FakeSyncClient(SyncApiComponentFactory* factory)
-    : factory_(factory) {
-  SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
-}
-
-FakeSyncClient::~FakeSyncClient() {}
-
-PrefService* FakeSyncClient::GetPrefService() {
-  return &pref_service_;
-}
-
-base::FilePath FakeSyncClient::GetLocalSyncBackendFolder() {
-  return base::FilePath();
-}
-
-ModelTypeStoreService* FakeSyncClient::GetModelTypeStoreService() {
-  return nullptr;
-}
-
-DeviceInfoSyncService* FakeSyncClient::GetDeviceInfoSyncService() {
-  return nullptr;
-}
-
-bookmarks::BookmarkModel* FakeSyncClient::GetBookmarkModel() {
-  return nullptr;
-}
-
-favicon::FaviconService* FakeSyncClient::GetFaviconService() {
-  return nullptr;
-}
-
-history::HistoryService* FakeSyncClient::GetHistoryService() {
-  return nullptr;
-}
-
-sync_sessions::SessionSyncService* FakeSyncClient::GetSessionSyncService() {
-  return nullptr;
-}
-
-bool FakeSyncClient::HasPasswordStore() {
-  return false;
-}
-
-base::Closure FakeSyncClient::GetPasswordStateChangedCallback() {
-  return base::DoNothing();
-}
-
-DataTypeController::TypeVector FakeSyncClient::CreateDataTypeControllers(
-    SyncService* sync_service) {
-  DCHECK(factory_);
-  return factory_->CreateCommonDataTypeControllers(
-      /*disabled_types=*/ModelTypeSet(), sync_service);
-}
-
-autofill::PersonalDataManager* FakeSyncClient::GetPersonalDataManager() {
-  return nullptr;
-}
-
-BookmarkUndoService* FakeSyncClient::GetBookmarkUndoServiceIfExists() {
-  return nullptr;
-}
-
-invalidation::InvalidationService* FakeSyncClient::GetInvalidationService() {
-  return nullptr;
-}
-
-scoped_refptr<ExtensionsActivity> FakeSyncClient::GetExtensionsActivity() {
-  return scoped_refptr<ExtensionsActivity>();
-}
-
-base::WeakPtr<SyncableService> FakeSyncClient::GetSyncableServiceForType(
-    ModelType type) {
-  return base::WeakPtr<SyncableService>();
-}
-
-base::WeakPtr<ModelTypeControllerDelegate>
-FakeSyncClient::GetControllerDelegateForModelType(ModelType type) {
-  return nullptr;
-}
-
-scoped_refptr<ModelSafeWorker> FakeSyncClient::CreateModelWorkerForGroup(
-    ModelSafeGroup group) {
-  return scoped_refptr<ModelSafeWorker>();
-}
-
-SyncApiComponentFactory* FakeSyncClient::GetSyncApiComponentFactory() {
-  return factory_;
-}
-
-}  // namespace syncer
diff --git a/components/sync/driver/fake_sync_client.h b/components/sync/driver/fake_sync_client.h
deleted file mode 100644
index 81c7396..0000000
--- a/components/sync/driver/fake_sync_client.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SYNC_DRIVER_FAKE_SYNC_CLIENT_H_
-#define COMPONENTS_SYNC_DRIVER_FAKE_SYNC_CLIENT_H_
-
-#include <memory>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "components/sync/driver/sync_client.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
-
-namespace syncer {
-
-// Fake implementation of SyncClient interface for tests.
-class FakeSyncClient : public SyncClient {
- public:
-  FakeSyncClient();
-  explicit FakeSyncClient(SyncApiComponentFactory* factory);
-  ~FakeSyncClient() override;
-
-  PrefService* GetPrefService() override;
-  base::FilePath GetLocalSyncBackendFolder() override;
-  ModelTypeStoreService* GetModelTypeStoreService() override;
-  DeviceInfoSyncService* GetDeviceInfoSyncService() override;
-  bookmarks::BookmarkModel* GetBookmarkModel() override;
-  favicon::FaviconService* GetFaviconService() override;
-  history::HistoryService* GetHistoryService() override;
-  sync_sessions::SessionSyncService* GetSessionSyncService() override;
-  bool HasPasswordStore() override;
-  base::Closure GetPasswordStateChangedCallback() override;
-  DataTypeController::TypeVector CreateDataTypeControllers(
-      SyncService* sync_service) override;
-  autofill::PersonalDataManager* GetPersonalDataManager() override;
-  BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
-  invalidation::InvalidationService* GetInvalidationService() override;
-  scoped_refptr<ExtensionsActivity> GetExtensionsActivity() override;
-  base::WeakPtr<SyncableService> GetSyncableServiceForType(
-      ModelType type) override;
-  base::WeakPtr<ModelTypeControllerDelegate> GetControllerDelegateForModelType(
-      ModelType type) override;
-  scoped_refptr<ModelSafeWorker> CreateModelWorkerForGroup(
-      ModelSafeGroup group) override;
-  SyncApiComponentFactory* GetSyncApiComponentFactory() override;
-
- private:
-  sync_preferences::TestingPrefServiceSyncable pref_service_;
-  SyncApiComponentFactory* factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeSyncClient);
-};
-
-}  // namespace syncer
-
-#endif  // COMPONENTS_SYNC_DRIVER_FAKE_SYNC_CLIENT_H_
diff --git a/components/sync/driver/model_association_manager.cc b/components/sync/driver/model_association_manager.cc
index fc9cfc4..6996855c 100644
--- a/components/sync/driver/model_association_manager.cc
+++ b/components/sync/driver/model_association_manager.cc
@@ -47,7 +47,7 @@
     SUPERVISED_USER_WHITELISTS, DEPRECATED_WIFI_CREDENTIALS,
     DEPRECATED_SUPERVISED_USERS, MOUNTAIN_SHARES,
     DEPRECATED_SUPERVISED_USER_SHARED_SETTINGS, DEPRECATED_ARTICLES,
-    SEND_TAB_TO_SELF};
+    SEND_TAB_TO_SELF, SECURITY_EVENTS};
 
 static_assert(base::size(kStartOrder) ==
                   MODEL_TYPE_COUNT - FIRST_REAL_MODEL_TYPE,
diff --git a/components/sync/driver/resources/index.html b/components/sync/driver/resources/index.html
index b3c53e8..804cc0f 100644
--- a/components/sync/driver/resources/index.html
+++ b/components/sync/driver/resources/index.html
@@ -103,7 +103,6 @@
   </tabpanels>
 </tabbox>
 
-<script src="chrome://resources/js/i18n_template.js"></script>
 <script src="chrome://resources/js/jstemplate_compiled.js"></script>
 <script src="chrome://sync-internals/sync_index.js"></script>
 </body>
diff --git a/components/sync/driver/shared_change_processor.cc b/components/sync/driver/shared_change_processor.cc
index 01e3269..7b6e755 100644
--- a/components/sync/driver/shared_change_processor.cc
+++ b/components/sync/driver/shared_change_processor.cc
@@ -145,7 +145,8 @@
   base::WeakPtr<SyncableService> local_service =
       sync_client->GetSyncableServiceForType(type_);
   if (!local_service) {
-    LOG(WARNING) << "SyncableService destroyed before DTC was stopped.";
+    DLOG(WARNING) << "SyncableService destroyed before DTC was stopped for "
+                  << ModelTypeToString(type_);
     disconnected_ = true;
     return base::WeakPtr<SyncableService>();
   }
diff --git a/components/sync/driver/shared_change_processor_unittest.cc b/components/sync/driver/shared_change_processor_unittest.cc
index bcfd28b7..905e8ad 100644
--- a/components/sync/driver/shared_change_processor_unittest.cc
+++ b/components/sync/driver/shared_change_processor_unittest.cc
@@ -15,10 +15,9 @@
 #include "components/sync/base/model_type.h"
 #include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/driver/data_type_manager.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/generic_change_processor.h"
 #include "components/sync/driver/generic_change_processor_factory.h"
-#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_client_mock.h"
 #include "components/sync/engine/sync_engine.h"
 #include "components/sync/model/data_type_error_handler_mock.h"
 #include "components/sync/model/fake_syncable_service.h"
@@ -30,31 +29,31 @@
 
 namespace {
 
+using ::testing::_;
 using ::testing::NiceMock;
 using ::testing::StrictMock;
 
-class SyncSharedChangeProcessorTest : public testing::Test,
-                                      public FakeSyncClient {
+class SyncSharedChangeProcessorTest : public testing::Test {
  public:
   SyncSharedChangeProcessorTest()
-      : FakeSyncClient(&factory_),
-        model_thread_("dbthread"),
-        did_connect_(false) {}
+      : model_thread_("dbthread"), did_connect_(false) {}
 
   ~SyncSharedChangeProcessorTest() override {
     EXPECT_FALSE(db_syncable_service_);
   }
 
-  // FakeSyncClient override.
-  base::WeakPtr<SyncableService> GetSyncableServiceForType(
-      ModelType type) override {
+ protected:
+  base::WeakPtr<SyncableService> GetSyncableServiceForType(ModelType type) {
+    DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     return db_syncable_service_->AsWeakPtr();
   }
 
- protected:
   void SetUp() override {
     test_user_share_.SetUp();
     shared_change_processor_ = new SharedChangeProcessor(AUTOFILL);
+    ON_CALL(sync_client_, GetSyncableServiceForType(AUTOFILL))
+        .WillByDefault(testing::Invoke(
+            this, &SyncSharedChangeProcessorTest::GetSyncableServiceForType));
     ASSERT_TRUE(model_thread_.Start());
     ASSERT_TRUE(model_thread_.task_runner()->PostTask(
         FROM_HERE,
@@ -115,7 +114,7 @@
       const scoped_refptr<SharedChangeProcessor>& shared_change_processor) {
     DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     EXPECT_TRUE(shared_change_processor->Connect(
-        this, &processor_factory_, test_user_share_.user_share(),
+        &sync_client_, &processor_factory_, test_user_share_.user_share(),
         std::make_unique<DataTypeErrorHandlerMock>(),
         base::WeakPtr<SyncMergeResult>()));
     did_connect_ = true;
@@ -124,7 +123,6 @@
   base::test::ScopedTaskEnvironment task_environment_;
   base::Thread model_thread_;
   TestUserShare test_user_share_;
-  NiceMock<SyncApiComponentFactoryMock> factory_;
 
   scoped_refptr<SharedChangeProcessor> shared_change_processor_;
 
@@ -133,6 +131,8 @@
 
   // Used only on DB thread.
   std::unique_ptr<FakeSyncableService> db_syncable_service_;
+
+  testing::NiceMock<SyncClientMock> sync_client_;
 };
 
 // Simply connect the shared change processor.  It should succeed, and
diff --git a/components/sync/driver/sync_api_component_factory.h b/components/sync/driver/sync_api_component_factory.h
index 80ab038..c2f62bb 100644
--- a/components/sync/driver/sync_api_component_factory.h
+++ b/components/sync/driver/sync_api_component_factory.h
@@ -14,10 +14,6 @@
 #include "components/sync/model/data_type_error_handler.h"
 #include "components/sync/model/syncable_service.h"
 
-namespace base {
-class FilePath;
-}  // namespace base
-
 namespace invalidation {
 class InvalidationService;
 }  // namespace invalidation
@@ -32,8 +28,6 @@
 class DataTypeManagerObserver;
 class SyncEngine;
 class SyncPrefs;
-class SyncService;
-class SyncableService;
 struct UserShare;
 
 // This factory provides sync driver code with the model type specific sync/api
@@ -61,13 +55,6 @@
     std::unique_ptr<ChangeProcessor> change_processor;
   };
 
-  // Creates and returns enabled datatypes and their controllers.
-  // |disabled_types| allows callers to prevent certain types from being
-  // created (e.g. to honor command-line flags).
-  virtual DataTypeController::TypeVector CreateCommonDataTypeControllers(
-      ModelTypeSet disabled_types,
-      SyncService* sync_service) = 0;
-
   virtual std::unique_ptr<DataTypeManager> CreateDataTypeManager(
       ModelTypeSet initial_types,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
@@ -80,8 +67,7 @@
   virtual std::unique_ptr<SyncEngine> CreateSyncEngine(
       const std::string& name,
       invalidation::InvalidationService* invalidator,
-      const base::WeakPtr<SyncPrefs>& sync_prefs,
-      const base::FilePath& sync_folder) = 0;
+      const base::WeakPtr<SyncPrefs>& sync_prefs) = 0;
 
   // Legacy datatypes that need to be converted to the SyncableService API.
   virtual SyncComponents CreateBookmarkSyncComponents(
diff --git a/components/sync/driver/sync_api_component_factory_mock.h b/components/sync/driver/sync_api_component_factory_mock.h
index fe6167b..ce83228 100644
--- a/components/sync/driver/sync_api_component_factory_mock.h
+++ b/components/sync/driver/sync_api_component_factory_mock.h
@@ -27,9 +27,6 @@
   SyncApiComponentFactoryMock();
   ~SyncApiComponentFactoryMock() override;
 
-  MOCK_METHOD2(CreateCommonDataTypeControllers,
-               DataTypeController::TypeVector(ModelTypeSet disabled_types,
-                                              SyncService* sync_service));
   MOCK_METHOD6(CreateDataTypeManager,
                std::unique_ptr<DataTypeManager>(
                    ModelTypeSet,
@@ -38,12 +35,11 @@
                    const DataTypeEncryptionHandler*,
                    ModelTypeConfigurer*,
                    DataTypeManagerObserver*));
-  MOCK_METHOD4(CreateSyncEngine,
+  MOCK_METHOD3(CreateSyncEngine,
                std::unique_ptr<SyncEngine>(
                    const std::string& name,
                    invalidation::InvalidationService* invalidator,
-                   const base::WeakPtr<SyncPrefs>& sync_prefs,
-                   const base::FilePath& sync_folder));
+                   const base::WeakPtr<SyncPrefs>& sync_prefs));
   MOCK_METHOD2(
       CreateBookmarkSyncComponents,
       SyncComponents(std::unique_ptr<DataTypeErrorHandler> error_handler,
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h
index d38f986..fbeb7dc 100644
--- a/components/sync/driver/sync_client.h
+++ b/components/sync/driver/sync_client.h
@@ -6,34 +6,17 @@
 #define COMPONENTS_SYNC_DRIVER_SYNC_CLIENT_H_
 
 #include "base/callback_forward.h"
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "components/sync/base/extensions_activity.h"
 #include "components/sync/base/model_type.h"
-#include "components/sync/driver/sync_api_component_factory.h"
+#include "components/sync/driver/data_type_controller.h"
 #include "components/sync/engine/model_safe_worker.h"
-#include "components/sync/model/model_type_controller_delegate.h"
 
-class BookmarkUndoService;
 class PrefService;
 
-namespace autofill {
-class PersonalDataManager;
-}  // namespace autofill
-
-namespace bookmarks {
-class BookmarkModel;
-}  // namespace bookmarks
-
-namespace favicon {
-class FaviconService;
-}  // namespace favicon
-
-namespace history {
-class HistoryService;
-}  // namespace history
-
 namespace invalidation {
 class InvalidationService;
 }  // namespace invalidation
@@ -45,8 +28,9 @@
 namespace syncer {
 
 class DeviceInfoSyncService;
-class ModelTypeStoreService;
+class SyncApiComponentFactory;
 class SyncableService;
+class SyncService;
 
 // Interface for clients of the Sync API to plumb through necessary dependent
 // components. This interface is purely for abstracting dependencies, and
@@ -62,30 +46,22 @@
   // Returns the current profile's preference service.
   virtual PrefService* GetPrefService() = 0;
 
-  virtual ModelTypeStoreService* GetModelTypeStoreService() = 0;
+  virtual base::FilePath GetSyncDataPath() = 0;
 
   // Returns the path to the folder used for storing the local sync database.
   // It is only used when sync is running against a local backend.
   virtual base::FilePath GetLocalSyncBackendFolder() = 0;
 
-  // DataType specific service getters.
-  virtual DeviceInfoSyncService* GetDeviceInfoSyncService() = 0;
-  virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0;
-  virtual favicon::FaviconService* GetFaviconService() = 0;
-  virtual history::HistoryService* GetHistoryService() = 0;
+  // TODO(crbug.com/922971): Move this away elsewhere.
+  virtual syncer::DeviceInfoSyncService* GetDeviceInfoSyncService() = 0;
+
+  // TODO(crbug.com/915154): Move this away elsewhere.
   virtual sync_sessions::SessionSyncService* GetSessionSyncService() = 0;
-  virtual bool HasPasswordStore() = 0;
 
   // Returns a vector with all supported datatypes and their controllers.
   virtual DataTypeController::TypeVector CreateDataTypeControllers(
       SyncService* sync_service) = 0;
 
-  // Returns a callback that will be invoked when password sync state has
-  // potentially been changed.
-  virtual base::Closure GetPasswordStateChangedCallback() = 0;
-
-  virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
-  virtual BookmarkUndoService* GetBookmarkUndoServiceIfExists() = 0;
   virtual invalidation::InvalidationService* GetInvalidationService() = 0;
   virtual scoped_refptr<ExtensionsActivity> GetExtensionsActivity() = 0;
 
@@ -95,12 +71,6 @@
   virtual base::WeakPtr<SyncableService> GetSyncableServiceForType(
       ModelType type) = 0;
 
-  // Returns a weak pointer to the ModelTypeControllerDelegate specified by
-  // |type|. Weak pointer may be unset if service is already destroyed. Note:
-  // Should only be dereferenced from the model type thread.
-  virtual base::WeakPtr<ModelTypeControllerDelegate>
-  GetControllerDelegateForModelType(ModelType type) = 0;
-
   // Creates and returns a new ModelSafeWorker for the group, or null if one
   // cannot be created.
   // TODO(maxbogue): Move this inside SyncApiComponentFactory.
diff --git a/components/sync/driver/sync_client_mock.h b/components/sync/driver/sync_client_mock.h
index 3c4ac5d7..251224d 100644
--- a/components/sync/driver/sync_client_mock.h
+++ b/components/sync/driver/sync_client_mock.h
@@ -17,26 +17,18 @@
   ~SyncClientMock() override;
 
   MOCK_METHOD0(GetPrefService, PrefService*());
+  MOCK_METHOD0(GetSyncDataPath, base::FilePath());
   MOCK_METHOD0(GetLocalSyncBackendFolder, base::FilePath());
-  MOCK_METHOD0(GetModelTypeStoreService, syncer::ModelTypeStoreService*());
   MOCK_METHOD0(GetDeviceInfoSyncService, DeviceInfoSyncService*());
-  MOCK_METHOD0(GetBookmarkModel, bookmarks::BookmarkModel*());
-  MOCK_METHOD0(GetFaviconService, favicon::FaviconService*());
-  MOCK_METHOD0(GetHistoryService, history::HistoryService*());
-  MOCK_METHOD0(HasPasswordStore, bool());
   MOCK_METHOD0(GetSessionSyncService, sync_sessions::SessionSyncService*());
   MOCK_METHOD1(CreateDataTypeControllers,
                DataTypeController::TypeVector(SyncService* sync_service));
   MOCK_METHOD0(GetPasswordStateChangedCallback, base::RepeatingClosure());
 
-  MOCK_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*());
-  MOCK_METHOD0(GetBookmarkUndoServiceIfExists, BookmarkUndoService*());
   MOCK_METHOD0(GetInvalidationService, invalidation::InvalidationService*());
   MOCK_METHOD0(GetExtensionsActivity, scoped_refptr<ExtensionsActivity>());
   MOCK_METHOD1(GetSyncableServiceForType,
                base::WeakPtr<SyncableService>(ModelType type));
-  MOCK_METHOD1(GetControllerDelegateForModelType,
-               base::WeakPtr<ModelTypeControllerDelegate>(ModelType type));
   MOCK_METHOD1(CreateModelWorkerForGroup,
                scoped_refptr<ModelSafeWorker>(ModelSafeGroup group));
   MOCK_METHOD0(GetSyncApiComponentFactory, SyncApiComponentFactory*());
diff --git a/components/sync/driver/sync_session_durations_metrics_recorder.cc b/components/sync/driver/sync_session_durations_metrics_recorder.cc
index 6064ac24..b112019c 100644
--- a/components/sync/driver/sync_session_durations_metrics_recorder.cc
+++ b/components/sync/driver/sync_session_durations_metrics_recorder.cc
@@ -148,7 +148,7 @@
 
 void SyncSessionDurationsMetricsRecorder::
     OnErrorStateOfRefreshTokenUpdatedForAccount(
-        const AccountInfo& account_info,
+        const CoreAccountInfo& account_info,
         const GoogleServiceAuthError& error) {
   DVLOG(1) << __func__;
   HandleSyncAndAccountChange();
diff --git a/components/sync/driver/sync_session_durations_metrics_recorder.h b/components/sync/driver/sync_session_durations_metrics_recorder.h
index 6c14a6e..056152d 100644
--- a/components/sync/driver/sync_session_durations_metrics_recorder.h
+++ b/components/sync/driver/sync_session_durations_metrics_recorder.h
@@ -44,7 +44,7 @@
   void OnRefreshTokenRemovedForAccount(const std::string& account_id) override;
   void OnRefreshTokensLoaded() override;
   void OnErrorStateOfRefreshTokenUpdatedForAccount(
-      const AccountInfo& account_info,
+      const CoreAccountInfo& account_info,
       const GoogleServiceAuthError& error) override;
   void OnAccountsInCookieUpdated(
       const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
diff --git a/components/sync/engine_impl/model_type_registry.cc b/components/sync/engine_impl/model_type_registry.cc
index 704787b..4d68b02 100644
--- a/components/sync/engine_impl/model_type_registry.cc
+++ b/components/sync/engine_impl/model_type_registry.cc
@@ -192,7 +192,9 @@
   DCHECK(data_type_debug_info_emitter_map_.find(type) ==
          data_type_debug_info_emitter_map_.end());
   DCHECK_NE(GROUP_NON_BLOCKING, group);
-  DCHECK(workers_map_.find(group) != workers_map_.end());
+  DCHECK(workers_map_.find(group) != workers_map_.end())
+      << " for " << ModelTypeToString(type) << " group "
+      << ModelSafeGroupToString(group);
 
   auto worker = workers_map_.find(group)->second;
   DCHECK(GetEmitter(type) == nullptr);
diff --git a/components/sync/model/model_type_sync_bridge.h b/components/sync/model/model_type_sync_bridge.h
index 1d01a53..ac0b41c 100644
--- a/components/sync/model/model_type_sync_bridge.h
+++ b/components/sync/model/model_type_sync_bridge.h
@@ -36,6 +36,8 @@
   using DataCallback = base::OnceCallback<void(std::unique_ptr<DataBatch>)>;
   using StorageKeyList = std::vector<std::string>;
 
+  // TODO(crbug.com/863870): Remove this enum now the sessions has migrated
+  // away.
   enum class StopSyncResponse {
     kModelStillReadyToSync,
     kModelNoLongerReadyToSync
diff --git a/components/sync/protocol/proto_value_conversions_unittest.cc b/components/sync/protocol/proto_value_conversions_unittest.cc
index e1016be3..02859294 100644
--- a/components/sync/protocol/proto_value_conversions_unittest.cc
+++ b/components/sync/protocol/proto_value_conversions_unittest.cc
@@ -60,7 +60,7 @@
 
 DEFINE_SPECIFICS_TO_VALUE_TEST(encrypted);
 
-static_assert(43 == syncer::MODEL_TYPE_COUNT,
+static_assert(44 == syncer::MODEL_TYPE_COUNT,
               "When adding a new field, add a DEFINE_SPECIFICS_TO_VALUE_TEST "
               "for your field below, and optionally a test for the specific "
               "conversions.");
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index cdacea6..14d3936 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -368,7 +368,7 @@
 }
 
 VISIT_PROTO_FIELDS(const sync_pb::EntitySpecifics& proto) {
-  static_assert(43 == MODEL_TYPE_COUNT,
+  static_assert(44 == MODEL_TYPE_COUNT,
                 "When adding a new protocol type, you will likely need to add "
                 "it here as well.");
   VISIT(encrypted);
diff --git a/components/sync/syncable/model_type.cc b/components/sync/syncable/model_type.cc
index d1b6ef5..daab81ba 100644
--- a/components/sync/syncable/model_type.cc
+++ b/components/sync/syncable/model_type.cc
@@ -151,6 +151,8 @@
     {SEND_TAB_TO_SELF, "SEND_TAB_TO_SELF", "send_tab_to_self",
      "Send Tab To Self", sync_pb::EntitySpecifics::kSendTabToSelfFieldNumber,
      42},
+    {SECURITY_EVENTS, "SECURITY_EVENT", "security_events", "Security Events",
+     sync_pb::EntitySpecifics::kSecurityEventFieldNumber, 43},
     // ---- Proxy types ----
     {PROXY_TABS, "", "", "Tabs", -1, 25},
     // ---- Control Types ----
@@ -163,11 +165,11 @@
 static_assert(base::size(kModelTypeInfoMap) == MODEL_TYPE_COUNT,
               "kModelTypeInfoMap should have MODEL_TYPE_COUNT elements");
 
-static_assert(43 == syncer::MODEL_TYPE_COUNT,
+static_assert(44 == syncer::MODEL_TYPE_COUNT,
               "When adding a new type, update enum SyncModelTypes in enums.xml "
               "and suffix SyncModelType in histograms.xml.");
 
-static_assert(43 == syncer::MODEL_TYPE_COUNT,
+static_assert(44 == syncer::MODEL_TYPE_COUNT,
               "When adding a new type, update kAllocatorDumpNameWhitelist in "
               "base/trace_event/memory_infra_background_whitelist.cc.");
 
@@ -282,6 +284,9 @@
     case USER_EVENTS:
       specifics->mutable_user_event();
       break;
+    case SECURITY_EVENTS:
+      specifics->mutable_security_event();
+      break;
     case MOUNTAIN_SHARES:
       specifics->mutable_mountain_share();
       break;
@@ -355,7 +360,7 @@
 }
 
 ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
-  static_assert(43 == MODEL_TYPE_COUNT,
+  static_assert(44 == MODEL_TYPE_COUNT,
                 "When adding new protocol types, the following type lookup "
                 "logic must be updated.");
   if (specifics.has_bookmark())
@@ -438,6 +443,8 @@
     return EXPERIMENTS;
   if (specifics.has_send_tab_to_self())
     return SEND_TAB_TO_SELF;
+  if (specifics.has_security_event())
+    return SECURITY_EVENTS;
 
   return UNSPECIFIED;
 }
@@ -456,7 +463,7 @@
 }
 
 ModelTypeSet EncryptableUserTypes() {
-  static_assert(43 == MODEL_TYPE_COUNT,
+  static_assert(44 == MODEL_TYPE_COUNT,
                 "If adding an unencryptable type, remove from "
                 "encryptable_user_types below.");
   ModelTypeSet encryptable_user_types = UserTypes();
@@ -489,6 +496,7 @@
   // server-side.
   encryptable_user_types.Remove(USER_EVENTS);
   encryptable_user_types.Remove(USER_CONSENTS);
+  encryptable_user_types.Remove(SECURITY_EVENTS);
   // Proxy types have no sync representation and are therefore not encrypted.
   // Note however that proxy types map to one or more protocol types, which
   // may or may not be encrypted themselves.
diff --git a/components/sync/syncable/nigori_util.cc b/components/sync/syncable/nigori_util.cc
index 7c25678..e331b4a 100644
--- a/components/sync/syncable/nigori_util.cc
+++ b/components/sync/syncable/nigori_util.cc
@@ -246,7 +246,7 @@
                                     bool encrypt_everything,
                                     sync_pb::NigoriSpecifics* nigori) {
   nigori->set_encrypt_everything(encrypt_everything);
-  static_assert(43 == MODEL_TYPE_COUNT,
+  static_assert(44 == MODEL_TYPE_COUNT,
                 "If adding an encryptable type, update handling below.");
   nigori->set_encrypt_bookmarks(encrypted_types.Has(BOOKMARKS));
   nigori->set_encrypt_preferences(encrypted_types.Has(PREFERENCES));
@@ -283,7 +283,7 @@
     return ModelTypeSet::All();
 
   ModelTypeSet encrypted_types;
-  static_assert(43 == MODEL_TYPE_COUNT,
+  static_assert(44 == MODEL_TYPE_COUNT,
                 "If adding an encryptable type, update handling below.");
   if (nigori.encrypt_bookmarks())
     encrypted_types.Put(BOOKMARKS);
diff --git a/components/sync_bookmarks/bookmark_change_processor.cc b/components/sync_bookmarks/bookmark_change_processor.cc
index 32cbf98..acb064f 100644
--- a/components/sync_bookmarks/bookmark_change_processor.cc
+++ b/components/sync_bookmarks/bookmark_change_processor.cc
@@ -20,7 +20,6 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/favicon/core/favicon_service.h"
-#include "components/sync/driver/sync_client.h"
 #include "components/sync/syncable/change_record.h"
 #include "components/sync/syncable/entry.h"  // TODO(tim): Investigating bug 121587.
 #include "components/sync/syncable/read_node.h"
@@ -42,15 +41,12 @@
 static const char kMobileBookmarksTag[] = "synced_bookmarks";
 
 BookmarkChangeProcessor::BookmarkChangeProcessor(
-    syncer::SyncClient* sync_client,
     BookmarkModelAssociator* model_associator,
     std::unique_ptr<syncer::DataTypeErrorHandler> err_handler)
     : syncer::ChangeProcessor(std::move(err_handler)),
       bookmark_model_(nullptr),
-      sync_client_(sync_client),
       model_associator_(model_associator) {
   DCHECK(model_associator);
-  DCHECK(sync_client);
   DCHECK(error_handler());
 }
 
@@ -62,7 +58,7 @@
 void BookmarkChangeProcessor::StartImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!bookmark_model_);
-  bookmark_model_ = sync_client_->GetBookmarkModel();
+  bookmark_model_ = model_associator_->GetBookmarkModel();
   DCHECK(bookmark_model_->loaded());
   bookmark_model_->AddObserver(this);
 }
@@ -584,7 +580,7 @@
 
   // Changes made to the bookmark model due to sync should not be undoable.
   ScopedSuspendBookmarkUndo suspend_undo(
-      sync_client_->GetBookmarkUndoServiceIfExists());
+      model_associator_->GetBookmarkUndoService());
 
   // Notify UI intensive observers of BookmarkModel that we are about to make
   // potentially significant changes to it, so the updates may be batched. For
@@ -702,7 +698,8 @@
     if (dst) {
       DCHECK(it->action == ChangeRecord::ACTION_UPDATE)
           << "ACTION_UPDATE should be seen if and only if the node is known.";
-      UpdateBookmarkWithSyncData(src, model, dst, sync_client_);
+      UpdateBookmarkWithSyncData(src, model, dst,
+                                 model_associator_->GetFaviconService());
 
       // Move all modified entries to the right.  We'll fix it later.
       model->Move(dst, parent, parent->child_count());
@@ -710,7 +707,8 @@
       DCHECK(it->action == ChangeRecord::ACTION_ADD)
           << "ACTION_ADD should be seen if and only if the node is unknown.";
 
-      dst = CreateBookmarkNode(&src, parent, model, sync_client_,
+      dst = CreateBookmarkNode(&src, parent, model,
+                               model_associator_->GetFaviconService(),
                                parent->child_count());
       if (!dst) {
         // We ignore bookmarks we can't add. Chances are this is caused by
@@ -763,7 +761,7 @@
     const syncer::BaseNode& sync_node,
     BookmarkModel* model,
     const BookmarkNode* node,
-    syncer::SyncClient* sync_client) {
+    favicon::FaviconService* favicon_service) {
   DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder());
   const sync_pb::BookmarkSpecifics& specifics =
       sync_node.GetBookmarkSpecifics();
@@ -775,7 +773,7 @@
         node,
         base::Time::FromInternalValue(specifics.creation_time_us()));
   }
-  SetBookmarkFavicon(&sync_node, node, sync_client);
+  SetBookmarkFavicon(&sync_node, node, favicon_service);
   model->SetNodeMetaInfoMap(node, *GetBookmarkMetaInfo(&sync_node));
 }
 
@@ -799,11 +797,11 @@
     const syncer::BaseNode* sync_node,
     const BookmarkNode* parent,
     BookmarkModel* model,
-    syncer::SyncClient* sync_client,
+    favicon::FaviconService* favicon_service,
     int index) {
   return CreateBookmarkNode(base::UTF8ToUTF16(sync_node->GetTitle()),
                             GURL(sync_node->GetBookmarkSpecifics().url()),
-                            sync_node, parent, model, sync_client, index);
+                            sync_node, parent, model, favicon_service, index);
 }
 
 // static
@@ -815,7 +813,7 @@
     const syncer::BaseNode* sync_node,
     const BookmarkNode* parent,
     BookmarkModel* model,
-    syncer::SyncClient* sync_client,
+    favicon::FaviconService* favicon_service,
     int index) {
   DCHECK(parent);
 
@@ -834,7 +832,7 @@
         parent, index, title, url, create_time,
         GetBookmarkMetaInfo(sync_node).get());
     if (node)
-      SetBookmarkFavicon(sync_node, node, sync_client);
+      SetBookmarkFavicon(sync_node, node, favicon_service);
   }
 
   return node;
@@ -845,7 +843,7 @@
 void BookmarkChangeProcessor::SetBookmarkFavicon(
     const syncer::BaseNode* sync_node,
     const BookmarkNode* bookmark_node,
-    syncer::SyncClient* sync_client) {
+    favicon::FaviconService* favicon_service) {
   const sync_pb::BookmarkSpecifics& specifics =
       sync_node->GetBookmarkSpecifics();
   const std::string& icon_bytes_str = specifics.favicon();
@@ -853,8 +851,8 @@
       new base::RefCountedString());
   icon_bytes->data().assign(icon_bytes_str);
 
-  ApplyBookmarkFavicon(bookmark_node, sync_client, GURL(specifics.icon_url()),
-                       icon_bytes);
+  ApplyBookmarkFavicon(bookmark_node, favicon_service,
+                       GURL(specifics.icon_url()), icon_bytes);
 }
 
 // static
@@ -921,12 +919,10 @@
 // static
 void BookmarkChangeProcessor::ApplyBookmarkFavicon(
     const BookmarkNode* bookmark_node,
-    syncer::SyncClient* sync_client,
+    favicon::FaviconService* favicon_service,
     const GURL& icon_url,
     const scoped_refptr<base::RefCountedMemory>& bitmap_data) {
-  favicon::FaviconService* favicon_service = sync_client->GetFaviconService();
-
-  // Some tests (that use FakeSyncClient) use no services.
+  // Some tests use no services.
   if (favicon_service == nullptr)
     return;
 
diff --git a/components/sync_bookmarks/bookmark_change_processor.h b/components/sync_bookmarks/bookmark_change_processor.h
index 72234f5..e11a2dd 100644
--- a/components/sync_bookmarks/bookmark_change_processor.h
+++ b/components/sync_bookmarks/bookmark_change_processor.h
@@ -25,11 +25,14 @@
 }  // namespace base
 
 namespace syncer {
-class SyncClient;
 class WriteNode;
 class WriteTransaction;
 }  // namespace syncer
 
+namespace favicon {
+class FaviconService;
+}  // namespace favicon
+
 namespace sync_bookmarks {
 
 // This class is responsible for taking changes from the BookmarkModel
@@ -40,7 +43,6 @@
                                 public syncer::ChangeProcessor {
  public:
   BookmarkChangeProcessor(
-      syncer::SyncClient* sync_client,
       BookmarkModelAssociator* model_associator,
       std::unique_ptr<syncer::DataTypeErrorHandler> error_handler);
   ~BookmarkChangeProcessor() override;
@@ -92,10 +94,11 @@
 
   // Updates the title, URL, creation time and favicon of the bookmark |node|
   // with data taken from the |sync_node| sync node.
-  static void UpdateBookmarkWithSyncData(const syncer::BaseNode& sync_node,
-                                         bookmarks::BookmarkModel* model,
-                                         const bookmarks::BookmarkNode* node,
-                                         syncer::SyncClient* sync_client);
+  static void UpdateBookmarkWithSyncData(
+      const syncer::BaseNode& sync_node,
+      bookmarks::BookmarkModel* model,
+      const bookmarks::BookmarkNode* node,
+      favicon::FaviconService* favicon_service);
 
   // Creates a bookmark node under the given parent node from the given sync
   // node. Returns the newly created node.  The created node is placed at the
@@ -104,7 +107,7 @@
       const syncer::BaseNode* sync_node,
       const bookmarks::BookmarkNode* parent,
       bookmarks::BookmarkModel* model,
-      syncer::SyncClient* sync_client,
+      favicon::FaviconService* favicon_service,
       int index);
 
   // Overload of CreateBookmarkNode function above that helps to avoid
@@ -115,20 +118,20 @@
       const syncer::BaseNode* sync_node,
       const bookmarks::BookmarkNode* parent,
       bookmarks::BookmarkModel* model,
-      syncer::SyncClient* sync_client,
+      favicon::FaviconService* favicon_service,
       int index);
 
   // Sets the favicon of the given bookmark node from the given sync node.
   static void SetBookmarkFavicon(const syncer::BaseNode* sync_node,
                                  const bookmarks::BookmarkNode* bookmark_node,
-                                 syncer::SyncClient* sync_client);
+                                 favicon::FaviconService* favicon_service);
 
   // Applies the 1x favicon |bitmap_data| and |icon_url| to |bookmark_node|.
   // |profile| is the profile that contains the HistoryService and BookmarkModel
   // for the bookmark in question.
   static void ApplyBookmarkFavicon(
       const bookmarks::BookmarkNode* bookmark_node,
-      syncer::SyncClient* sync_client,
+      favicon::FaviconService* favicon_service,
       const GURL& icon_url,
       const scoped_refptr<base::RefCountedMemory>& bitmap_data);
 
@@ -241,8 +244,6 @@
   // |running_| is true.
   bookmarks::BookmarkModel* bookmark_model_;
 
-  syncer::SyncClient* sync_client_;
-
   // The two models should be associated according to this ModelAssociator.
   BookmarkModelAssociator* model_associator_;
 
diff --git a/components/sync_bookmarks/bookmark_data_type_controller.cc b/components/sync_bookmarks/bookmark_data_type_controller.cc
index 24f358a1..709c6c6 100644
--- a/components/sync_bookmarks/bookmark_data_type_controller.cc
+++ b/components/sync_bookmarks/bookmark_data_type_controller.cc
@@ -11,7 +11,6 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/sync/driver/model_associator.h"
 #include "components/sync/driver/sync_api_component_factory.h"
-#include "components/sync/driver/sync_client.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/model/change_processor.h"
 
@@ -20,13 +19,17 @@
 namespace sync_bookmarks {
 
 BookmarkDataTypeController::BookmarkDataTypeController(
-    const base::Closure& dump_stack,
+    const base::RepeatingClosure& dump_stack,
     syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client)
+    bookmarks::BookmarkModel* bookmark_model,
+    history::HistoryService* history_service,
+    syncer::SyncApiComponentFactory* component_factory)
     : syncer::FrontendDataTypeController(syncer::BOOKMARKS,
                                          dump_stack,
                                          sync_service),
-      sync_client_(sync_client),
+      bookmark_model_(bookmark_model),
+      history_service_(history_service),
+      component_factory_(component_factory),
       history_service_observer_(this),
       bookmark_model_observer_(this) {}
 
@@ -35,11 +38,8 @@
 bool BookmarkDataTypeController::StartModels() {
   DCHECK(CalledOnValidThread());
   if (!DependentsLoaded()) {
-    BookmarkModel* bookmark_model = sync_client_->GetBookmarkModel();
-    bookmark_model_observer_.Add(bookmark_model);
-    history::HistoryService* history_service =
-        sync_client_->GetHistoryService();
-    history_service_observer_.Add(history_service);
+    bookmark_model_observer_.Add(bookmark_model_);
+    history_service_observer_.Add(history_service_);
     return false;
   }
   return true;
@@ -54,7 +54,7 @@
 void BookmarkDataTypeController::CreateSyncComponents() {
   DCHECK(CalledOnValidThread());
   syncer::SyncApiComponentFactory::SyncComponents sync_components =
-      sync_client_->GetSyncApiComponentFactory()->CreateBookmarkSyncComponents(
+      component_factory_->CreateBookmarkSyncComponents(
           CreateErrorHandler(), sync_service()->GetUserShare());
   set_model_associator(std::move(sync_components.model_associator));
   set_change_processor(std::move(sync_components.change_processor));
@@ -85,12 +85,10 @@
 // are loaded.
 bool BookmarkDataTypeController::DependentsLoaded() {
   DCHECK(CalledOnValidThread());
-  BookmarkModel* bookmark_model = sync_client_->GetBookmarkModel();
-  if (!bookmark_model || !bookmark_model->loaded())
+  if (!bookmark_model_ || !bookmark_model_->loaded())
     return false;
 
-  history::HistoryService* history_service = sync_client_->GetHistoryService();
-  if (!history_service || !history_service->BackendLoaded())
+  if (!history_service_ || !history_service_->BackendLoaded())
     return false;
 
   // All necessary services are loaded.
diff --git a/components/sync_bookmarks/bookmark_data_type_controller.h b/components/sync_bookmarks/bookmark_data_type_controller.h
index bb78735..febbeec2 100644
--- a/components/sync_bookmarks/bookmark_data_type_controller.h
+++ b/components/sync_bookmarks/bookmark_data_type_controller.h
@@ -14,7 +14,7 @@
 #include "components/sync/driver/frontend_data_type_controller.h"
 
 namespace syncer {
-class SyncClient;
+class SyncApiComponentFactory;
 class SyncService;
 }  // namespace syncer
 
@@ -26,9 +26,12 @@
                                    public history::HistoryServiceObserver {
  public:
   // |dump_stack| is called when an unrecoverable error occurs.
-  BookmarkDataTypeController(const base::Closure& dump_stack,
-                             syncer::SyncService* sync_service,
-                             syncer::SyncClient* sync_client);
+  BookmarkDataTypeController(
+      const base::RepeatingClosure& dump_stack,
+      syncer::SyncService* sync_service,
+      bookmarks::BookmarkModel* bookmark_model,
+      history::HistoryService* history_service,
+      syncer::SyncApiComponentFactory* component_factory);
   ~BookmarkDataTypeController() override;
 
  private:
@@ -52,7 +55,9 @@
   void HistoryServiceBeingDeleted(
       history::HistoryService* history_service) override;
 
-  syncer::SyncClient* const sync_client_;
+  bookmarks::BookmarkModel* const bookmark_model_;
+  history::HistoryService* const history_service_;
+  syncer::SyncApiComponentFactory* const component_factory_;
 
   ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
       history_service_observer_;
diff --git a/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc b/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
index 1f56d6e..b89dbfc 100644
--- a/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
+++ b/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
@@ -20,7 +20,6 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/data_type_controller_mock.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/fake_sync_service.h"
 #include "components/sync/driver/model_associator_mock.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
@@ -55,20 +54,10 @@
 
 }  // namespace
 
-class SyncBookmarkDataTypeControllerTest : public testing::Test,
-                                           public syncer::FakeSyncClient {
+class SyncBookmarkDataTypeControllerTest : public testing::Test {
  public:
   SyncBookmarkDataTypeControllerTest() {}
 
-  // FakeSyncClient overrides.
-  BookmarkModel* GetBookmarkModel() override { return bookmark_model_.get(); }
-  history::HistoryService* GetHistoryService() override {
-    return history_service_.get();
-  }
-  syncer::SyncApiComponentFactory* GetSyncApiComponentFactory() override {
-    return &components_factory_;
-  }
-
   void SetUp() override {
     model_associator_deleter_ =
         std::make_unique<NiceMock<ModelAssociatorMock>>();
@@ -76,9 +65,12 @@
         std::make_unique<NiceMock<ChangeProcessorMock>>();
     model_associator_ = model_associator_deleter_.get();
     change_processor_ = change_processor_deleter_.get();
+    bookmark_model_ = std::make_unique<BookmarkModel>(
+        std::make_unique<bookmarks::TestBookmarkClient>());
     history_service_ = std::make_unique<HistoryMock>();
     bookmark_dtc_ = std::make_unique<BookmarkDataTypeController>(
-        base::DoNothing(), &service_, this);
+        base::DoNothing(), &service_, bookmark_model_.get(),
+        history_service_.get(), &components_factory_);
 
     ON_CALL(components_factory_, CreateBookmarkSyncComponents(_, _))
         .WillByDefault(testing::InvokeWithoutArgs([=]() {
@@ -90,21 +82,12 @@
   }
 
  protected:
-  enum BookmarkLoadPolicy {
-    DONT_LOAD_MODEL,
-    LOAD_MODEL,
-  };
-
-  void CreateBookmarkModel(BookmarkLoadPolicy bookmark_load_policy) {
-    bookmark_model_ = std::make_unique<BookmarkModel>(
-        std::make_unique<bookmarks::TestBookmarkClient>());
-    if (bookmark_load_policy == LOAD_MODEL) {
-      TestingPrefServiceSimple prefs;
-      bookmark_model_->Load(&prefs, base::FilePath(),
-                            base::SequencedTaskRunnerHandle::Get(),
-                            base::SequencedTaskRunnerHandle::Get());
-      bookmarks::test::WaitForBookmarkModelToLoad(bookmark_model_.get());
-    }
+  void LoadBookmarkModel() {
+    TestingPrefServiceSimple prefs;
+    bookmark_model_->Load(&prefs, base::FilePath(),
+                          base::SequencedTaskRunnerHandle::Get(),
+                          base::SequencedTaskRunnerHandle::Get());
+    bookmarks::test::WaitForBookmarkModelToLoad(bookmark_model_.get());
   }
 
   void SetStartExpectations() {
@@ -157,7 +140,7 @@
 };
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartDependentsReady) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   SetAssociateExpectations();
 
@@ -169,7 +152,6 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartBookmarkModelNotReady) {
-  CreateBookmarkModel(DONT_LOAD_MODEL);
   SetStartExpectations();
   SetAssociateExpectations();
 
@@ -196,7 +178,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartHistoryServiceNotReady) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   EXPECT_CALL(*history_service_.get(), BackendLoaded())
       .WillRepeatedly(Return(false));
@@ -217,7 +199,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartFirstRun) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   SetAssociateExpectations();
   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_))
@@ -227,7 +209,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartBusy) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   EXPECT_CALL(*history_service_.get(), BackendLoaded())
       .WillRepeatedly(Return(false));
 
@@ -243,7 +225,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartOk) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   SetAssociateExpectations();
   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_))
@@ -254,7 +236,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartAssociationFailed) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   // Set up association to fail.
   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
@@ -275,7 +257,7 @@
 
 TEST_F(SyncBookmarkDataTypeControllerTest,
        StartAssociationTriggersUnrecoverableError) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   // Set up association to fail with an unrecoverable error.
   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
@@ -289,7 +271,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, StartAborted) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   EXPECT_CALL(*history_service_.get(), BackendLoaded())
       .WillRepeatedly(Return(false));
 
@@ -303,7 +285,7 @@
 }
 
 TEST_F(SyncBookmarkDataTypeControllerTest, Stop) {
-  CreateBookmarkModel(LOAD_MODEL);
+  LoadBookmarkModel();
   SetStartExpectations();
   SetAssociateExpectations();
   SetStopExpectations();
diff --git a/components/sync_bookmarks/bookmark_model_associator.cc b/components/sync_bookmarks/bookmark_model_associator.cc
index 7508dd7..958a6ffa6 100644
--- a/components/sync_bookmarks/bookmark_model_associator.cc
+++ b/components/sync_bookmarks/bookmark_model_associator.cc
@@ -20,7 +20,6 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/sync/base/cryptographer.h"
 #include "components/sync/base/data_type_histogram.h"
-#include "components/sync/driver/sync_client.h"
 #include "components/sync/engine/engine_util.h"
 #include "components/sync/model/sync_error.h"
 #include "components/sync/model/sync_merge_result.h"
@@ -297,12 +296,14 @@
 
 BookmarkModelAssociator::BookmarkModelAssociator(
     BookmarkModel* bookmark_model,
-    syncer::SyncClient* sync_client,
+    BookmarkUndoService* bookmark_undo_service,
+    favicon::FaviconService* favicon_service,
     syncer::UserShare* user_share,
     std::unique_ptr<syncer::DataTypeErrorHandler> unrecoverable_error_handler,
     bool expect_mobile_bookmarks_folder)
     : bookmark_model_(bookmark_model),
-      sync_client_(sync_client),
+      bookmark_undo_service_(bookmark_undo_service),
+      favicon_service_(favicon_service),
       user_share_(user_share),
       unrecoverable_error_handler_(std::move(unrecoverable_error_handler)),
       expect_mobile_bookmarks_folder_(expect_mobile_bookmarks_folder),
@@ -316,6 +317,18 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 }
 
+bookmarks::BookmarkModel* BookmarkModelAssociator::GetBookmarkModel() {
+  return bookmark_model_;
+}
+
+favicon::FaviconService* BookmarkModelAssociator::GetFaviconService() {
+  return favicon_service_;
+}
+
+BookmarkUndoService* BookmarkModelAssociator::GetBookmarkUndoService() {
+  return bookmark_undo_service_;
+}
+
 syncer::SyncError BookmarkModelAssociator::DisassociateModels() {
   id_map_.clear();
   id_map_inverse_.clear();
@@ -436,8 +449,7 @@
     syncer::SyncMergeResult* syncer_merge_result) {
   // Since any changes to the bookmark model made here are not user initiated,
   // these change should not be undoable and so suspend the undo tracking.
-  ScopedSuspendBookmarkUndo suspend_undo(
-      sync_client_->GetBookmarkUndoServiceIfExists());
+  ScopedSuspendBookmarkUndo suspend_undo(bookmark_undo_service_);
 
   Context context(local_merge_result, syncer_merge_result);
 
@@ -681,7 +693,7 @@
                         (parent_node->GetChild(index) == child_node);
       if (!is_in_sync) {
         BookmarkChangeProcessor::UpdateBookmarkWithSyncData(
-            sync_child_node, bookmark_model_, child_node, sync_client_);
+            sync_child_node, bookmark_model_, child_node, favicon_service_);
         bookmark_model_->Move(child_node, parent_node, index);
         context->IncrementLocalItemsModified();
         context->MarkForVersionUpdate(child_node);
@@ -755,7 +767,7 @@
   base::string16 bookmark_title = base::UTF8ToUTF16(sync_title);
   const BookmarkNode* child_node = BookmarkChangeProcessor::CreateBookmarkNode(
       bookmark_title, url, sync_child_node, parent_node, bookmark_model_,
-      sync_client_, bookmark_index);
+      favicon_service_, bookmark_index);
   if (!child_node) {
     *error = unrecoverable_error_handler_->CreateAndUploadError(
         FROM_HERE, "Failed to create bookmark node with title " + sync_title +
diff --git a/components/sync_bookmarks/bookmark_model_associator.h b/components/sync_bookmarks/bookmark_model_associator.h
index bbf21979..70873dc 100644
--- a/components/sync_bookmarks/bookmark_model_associator.h
+++ b/components/sync_bookmarks/bookmark_model_associator.h
@@ -26,20 +26,24 @@
 #include "components/sync/driver/model_associator.h"
 #include "components/sync/model/data_type_error_handler.h"
 
+class BookmarkUndoService;
 class GURL;
 
 namespace bookmarks {
 class BookmarkModel;
 class BookmarkNode;
-}
+}  // namespace bookmarks
+
+namespace favicon {
+class FaviconService;
+}  // namespace favicon
 
 namespace syncer {
 class BaseNode;
 class BaseTransaction;
-class SyncClient;
 class WriteTransaction;
 struct UserShare;
-}
+}  // namespace syncer
 
 namespace sync_bookmarks {
 
@@ -50,17 +54,23 @@
 class BookmarkModelAssociator : public syncer::AssociatorInterface {
  public:
   static syncer::ModelType model_type() { return syncer::BOOKMARKS; }
+
   // |expect_mobile_bookmarks_folder| controls whether or not we
   // expect the mobile bookmarks permanent folder to be created.
   // Should be set to true only by mobile clients.
   BookmarkModelAssociator(
       bookmarks::BookmarkModel* bookmark_model,
-      syncer::SyncClient* sync_client,
+      BookmarkUndoService* bookmark_undo_service,
+      favicon::FaviconService* favicon_service,
       syncer::UserShare* user_share,
       std::unique_ptr<syncer::DataTypeErrorHandler> unrecoverable_error_handler,
       bool expect_mobile_bookmarks_folder);
   ~BookmarkModelAssociator() override;
 
+  bookmarks::BookmarkModel* GetBookmarkModel();
+  favicon::FaviconService* GetFaviconService();
+  BookmarkUndoService* GetBookmarkUndoService();
+
   // AssociatorInterface implementation.
   //
   // AssociateModels iterates through both the sync and the browser
@@ -282,9 +292,10 @@
   syncer::SyncError CheckModelSyncState(Context* context) const;
 
   base::ThreadChecker thread_checker_;
-  bookmarks::BookmarkModel* bookmark_model_;
-  syncer::SyncClient* sync_client_;
-  syncer::UserShare* user_share_;
+  bookmarks::BookmarkModel* const bookmark_model_;
+  BookmarkUndoService* const bookmark_undo_service_;
+  favicon::FaviconService* const favicon_service_;
+  syncer::UserShare* const user_share_;
   std::unique_ptr<syncer::DataTypeErrorHandler> unrecoverable_error_handler_;
   const bool expect_mobile_bookmarks_folder_;
   BookmarkIdToSyncIdMap id_map_;
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index 45617bb..fb52574 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -15,7 +15,6 @@
 #include "components/bookmarks/test/test_bookmark_client.h"
 #include "components/favicon/core/test/mock_favicon_service.h"
 #include "components/sync/base/unique_position.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/model/data_type_activation_request.h"
 #include "components/undo/bookmark_undo_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/sync_sessions/favicon_cache.cc b/components/sync_sessions/favicon_cache.cc
index 35faa80..bae2883e 100644
--- a/components/sync_sessions/favicon_cache.cc
+++ b/components/sync_sessions/favicon_cache.cc
@@ -519,6 +519,10 @@
   }
 }
 
+base::WeakPtr<FaviconCache> FaviconCache::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 size_t FaviconCache::NumFaviconsForTest() const {
   return synced_favicons_.size();
 }
diff --git a/components/sync_sessions/favicon_cache.h b/components/sync_sessions/favicon_cache.h
index 292636a..08946fb 100644
--- a/components/sync_sessions/favicon_cache.h
+++ b/components/sync_sessions/favicon_cache.h
@@ -106,6 +106,8 @@
   void UpdateMappingsFromForeignTab(const sync_pb::SessionTab& tab,
                                     base::Time visit_time);
 
+  base::WeakPtr<FaviconCache> GetWeakPtr();
+
   // For testing only.
   size_t NumFaviconsForTest() const;
   size_t NumTasksForTest() const;
diff --git a/components/sync_sessions/session_store.cc b/components/sync_sessions/session_store.cc
index d91625e0..935b76d 100644
--- a/components/sync_sessions/session_store.cc
+++ b/components/sync_sessions/session_store.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/pickle.h"
 #include "base/strings/stringprintf.h"
@@ -100,122 +101,31 @@
   }
 }
 
-class FactoryImpl : public base::SupportsWeakPtr<FactoryImpl> {
- public:
-  // Raw pointers must not be null and must outlive this object.
-  FactoryImpl(SyncSessionsClient* sessions_client,
-              const SessionStore::RestoredForeignTabCallback&
-                  restored_foreign_tab_callback)
-      : sessions_client_(sessions_client),
-        restored_foreign_tab_callback_(restored_foreign_tab_callback) {
-    DCHECK(sessions_client);
-  }
-
-  ~FactoryImpl() {}
-
-  void Create(const syncer::DeviceInfo& device_info,
-              SessionStore::FactoryCompletionCallback callback) {
-    const std::string& cache_guid = device_info.guid();
-    DCHECK(!cache_guid.empty());
-
-    SessionStore::SessionInfo session_info;
-    session_info.client_name = device_info.client_name();
-    session_info.device_type = device_info.device_type();
-    session_info.session_tag = GetSessionTagWithPrefs(
-        cache_guid, sessions_client_->GetSessionSyncPrefs());
-
-    DVLOG(1) << "Initiating creation of session store";
-
-    sessions_client_->GetStoreFactory().Run(
-        syncer::SESSIONS,
-        base::BindOnce(&FactoryImpl::OnStoreCreated, base::AsWeakPtr(this),
-                       session_info, std::move(callback)));
-  }
-
- private:
-  void OnStoreCreated(const SessionStore::SessionInfo& session_info,
-                      SessionStore::FactoryCompletionCallback callback,
-                      const base::Optional<syncer::ModelError>& error,
-                      std::unique_ptr<ModelTypeStore> store) {
-    if (error) {
-      std::move(callback).Run(error, /*store=*/nullptr,
-                              /*metadata_batch=*/nullptr);
-      return;
-    }
-
-    DCHECK(store);
-    ModelTypeStore* store_copy = store.get();
-    store_copy->ReadAllData(
-        base::BindOnce(&FactoryImpl::OnReadAllData, base::AsWeakPtr(this),
-                       session_info, std::move(callback), std::move(store)));
-  }
-
-  void OnReadAllData(const SessionStore::SessionInfo& session_info,
-                     SessionStore::FactoryCompletionCallback callback,
-                     std::unique_ptr<ModelTypeStore> store,
-                     const base::Optional<syncer::ModelError>& error,
-                     std::unique_ptr<ModelTypeStore::RecordList> record_list) {
-    if (error) {
-      std::move(callback).Run(error, /*store=*/nullptr,
-                              /*metadata_batch=*/nullptr);
-      return;
-    }
-
-    ModelTypeStore* store_raw = store.get();
-    store_raw->ReadAllMetadata(base::BindOnce(
-        &FactoryImpl::OnReadAllMetadata, base::AsWeakPtr(this), session_info,
-        std::move(callback), std::move(store), std::move(record_list)));
-  }
-
-  void OnReadAllMetadata(
-      const SessionStore::SessionInfo& session_info,
-      SessionStore::FactoryCompletionCallback callback,
-      std::unique_ptr<ModelTypeStore> store,
-      std::unique_ptr<ModelTypeStore::RecordList> record_list,
-      const base::Optional<syncer::ModelError>& error,
-      std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
-    // Remove after fixing https://crbug.com/902203.
-    TRACE_EVENT0("browser", "FactoryImpl::OnReadAllMetadata");
-    if (error) {
-      std::move(callback).Run(error, /*store=*/nullptr,
-                              /*metadata_batch=*/nullptr);
-      return;
-    }
-
-    std::map<std::string, sync_pb::SessionSpecifics> initial_data;
-    for (ModelTypeStore::Record& record : *record_list) {
-      const std::string& storage_key = record.id;
-      SessionSpecifics specifics;
-      if (storage_key.empty() ||
-          !specifics.ParseFromString(std::move(record.value))) {
-        DVLOG(1) << "Ignoring corrupt database entry with key: " << storage_key;
-        continue;
-      }
-      initial_data[storage_key].Swap(&specifics);
-    }
-
-    auto session_store = std::make_unique<SessionStore>(
-        sessions_client_, session_info, std::move(store),
-        std::move(initial_data), metadata_batch->GetAllMetadata(),
-        restored_foreign_tab_callback_);
-
-    std::move(callback).Run(/*error=*/base::nullopt, std::move(session_store),
-                            std::move(metadata_batch));
-  }
-
-  SyncSessionsClient* const sessions_client_;
-  const SessionStore::RestoredForeignTabCallback restored_foreign_tab_callback_;
-};
-
 }  // namespace
 
 // static
-SessionStore::Factory SessionStore::CreateFactory(
+void SessionStore::Open(
+    const syncer::DeviceInfo& device_info,
+    const RestoredForeignTabCallback& restored_foreign_tab_callback,
     SyncSessionsClient* sessions_client,
-    const RestoredForeignTabCallback& restored_foreign_tab_callback) {
-  auto factory = std::make_unique<FactoryImpl>(sessions_client,
-                                               restored_foreign_tab_callback);
-  return base::BindRepeating(&FactoryImpl::Create, std::move(factory));
+    OpenCallback callback) {
+  DCHECK(sessions_client);
+  DCHECK(!device_info.guid().empty());
+
+  SessionStore::SessionInfo session_info;
+  session_info.client_name = device_info.client_name();
+  session_info.device_type = device_info.device_type();
+  session_info.session_tag = GetSessionTagWithPrefs(
+      device_info.guid(), sessions_client->GetSessionSyncPrefs());
+
+  DVLOG(1) << "Opening session store";
+  // WrapUnique() used because constructor is private.
+  auto session_store = base::WrapUnique(new SessionStore(
+      session_info, restored_foreign_tab_callback, sessions_client));
+  sessions_client->GetStoreFactory().Run(
+      syncer::SESSIONS,
+      base::BindOnce(&OnStoreCreated, std::move(session_store),
+                     std::move(callback)));
 }
 
 SessionStore::WriteBatch::WriteBatch(
@@ -380,27 +290,110 @@
   return TabNodeIdToClientTag(session_tag, tab_node_id);
 }
 
+// static
+void SessionStore::OnStoreCreated(
+    std::unique_ptr<SessionStore> session_store,
+    OpenCallback callback,
+    const base::Optional<syncer::ModelError>& error,
+    std::unique_ptr<ModelTypeStore> underlying_store) {
+  if (error) {
+    std::move(callback).Run(error, /*store=*/nullptr,
+                            /*metadata_batch=*/nullptr);
+    return;
+  }
+
+  DCHECK(underlying_store);
+  ModelTypeStore* underlying_store_copy = underlying_store.get();
+  underlying_store_copy->ReadAllMetadata(
+      base::BindOnce(&OnReadAllMetadata, std::move(session_store),
+                     std::move(callback), std::move(underlying_store)));
+}
+
+// static
+void SessionStore::OnReadAllMetadata(
+    std::unique_ptr<SessionStore> session_store,
+    OpenCallback callback,
+    std::unique_ptr<ModelTypeStore> underlying_store,
+    const base::Optional<syncer::ModelError>& error,
+    std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
+  if (error) {
+    std::move(callback).Run(error, /*store=*/nullptr,
+                            /*metadata_batch=*/nullptr);
+    return;
+  }
+
+  ModelTypeStore* underlying_store_copy = underlying_store.get();
+  underlying_store_copy->ReadAllData(base::BindOnce(
+      &OnReadAllData, std::move(session_store), std::move(callback),
+      std::move(underlying_store), std::move(metadata_batch)));
+}
+
+// static
+void SessionStore::OnReadAllData(
+    std::unique_ptr<SessionStore> session_store,
+    OpenCallback callback,
+    std::unique_ptr<ModelTypeStore> underlying_store,
+    std::unique_ptr<syncer::MetadataBatch> metadata_batch,
+    const base::Optional<syncer::ModelError>& error,
+    std::unique_ptr<ModelTypeStore::RecordList> record_list) {
+  // Remove after fixing https://crbug.com/902203.
+  TRACE_EVENT0("browser", "OnReadAllMetadata");
+  if (error) {
+    std::move(callback).Run(error, /*store=*/nullptr,
+                            /*metadata_batch=*/nullptr);
+    return;
+  }
+
+  std::map<std::string, sync_pb::SessionSpecifics> initial_data;
+  for (ModelTypeStore::Record& record : *record_list) {
+    const std::string& storage_key = record.id;
+    SessionSpecifics specifics;
+    if (storage_key.empty() ||
+        !specifics.ParseFromString(std::move(record.value))) {
+      DVLOG(1) << "Ignoring corrupt database entry with key: " << storage_key;
+      continue;
+    }
+    initial_data[storage_key].Swap(&specifics);
+  }
+
+  // We avoid initialization of the store if the callback was cancelled, in
+  // case dependencies (SessionSyncClient) are already destroyed, even though
+  // the current implementation doesn't seem to crash otherwise.
+  if (callback.IsCancelled()) {
+    return;
+  }
+
+  session_store->Init(std::move(underlying_store), std::move(initial_data),
+                      metadata_batch->GetAllMetadata());
+
+  std::move(callback).Run(/*error=*/base::nullopt, std::move(session_store),
+                          std::move(metadata_batch));
+}
+
 SessionStore::SessionStore(
-    SyncSessionsClient* sessions_client,
     const SessionInfo& local_session_info,
-    std::unique_ptr<ModelTypeStore> store,
-    std::map<std::string, sync_pb::SessionSpecifics> initial_data,
-    const syncer::EntityMetadataMap& initial_metadata,
-    const RestoredForeignTabCallback& restored_foreign_tab_callback)
-    : store_(std::move(store)),
-      local_session_info_(local_session_info),
+    const RestoredForeignTabCallback& restored_foreign_tab_callback,
+    SyncSessionsClient* sessions_client)
+    : local_session_info_(local_session_info),
+      restored_foreign_tab_callback_(restored_foreign_tab_callback),
       session_tracker_(sessions_client),
       weak_ptr_factory_(this) {
-  DCHECK(store_);
+  session_tracker_.InitLocalSession(local_session_info_.session_tag,
+                                    local_session_info_.client_name,
+                                    local_session_info_.device_type);
+}
 
-  DVLOG(1) << "Constructed session store with " << initial_data.size()
+void SessionStore::Init(
+    std::unique_ptr<ModelTypeStore> store,
+    std::map<std::string, sync_pb::SessionSpecifics> initial_data,
+    const syncer::EntityMetadataMap& initial_metadata) {
+  DCHECK(store);
+  store_ = std::move(store);
+
+  DVLOG(1) << "Initializing session store with " << initial_data.size()
            << " restored entities and " << initial_metadata.size()
            << " metadata entries.";
 
-  session_tracker_.InitLocalSession(local_session_info.session_tag,
-                                    local_session_info.client_name,
-                                    local_session_info.device_type);
-
   bool found_local_header = false;
 
   for (auto& storage_key_and_specifics : initial_data) {
@@ -424,13 +417,13 @@
     const base::Time mtime =
         syncer::ProtoTimeToTime(metadata_it->second.modification_time());
 
-    if (specifics.session_tag() != local_session_info.session_tag) {
+    if (specifics.session_tag() != local_session_info_.session_tag) {
       UpdateTrackerWithSpecifics(specifics, mtime, &session_tracker_);
 
       // Notify listeners. In practice, this has the goal to load the URLs and
       // visit times into the in-memory favicon cache.
       if (specifics.has_tab()) {
-        restored_foreign_tab_callback.Run(specifics.tab(), mtime);
+        restored_foreign_tab_callback_.Run(specifics.tab(), mtime);
       }
     } else if (specifics.has_header()) {
       // This is previously stored local header information. Restoring the local
@@ -529,7 +522,12 @@
 
 void SessionStore::DeleteAllDataAndMetadata() {
   session_tracker_.Clear();
-  return store_->DeleteAllDataAndMetadata(base::DoNothing());
+  store_->DeleteAllDataAndMetadata(base::DoNothing());
+
+  // At all times, the local session must be tracked.
+  session_tracker_.InitLocalSession(local_session_info_.session_tag,
+                                    local_session_info_.client_name,
+                                    local_session_info_.device_type);
 }
 
 }  // namespace sync_sessions
diff --git a/components/sync_sessions/session_store.h b/components/sync_sessions/session_store.h
index 80d9544..7c9f102 100644
--- a/components/sync_sessions/session_store.h
+++ b/components/sync_sessions/session_store.h
@@ -38,25 +38,23 @@
     sync_pb::SyncEnums::DeviceType device_type = sync_pb::SyncEnums::TYPE_UNSET;
   };
 
-  // Creation factory. The instantiation process is quite complex because it
-  // loads state from disk.
-  using FactoryCompletionCallback = base::OnceCallback<void(
+  using OpenCallback = base::OnceCallback<void(
       const base::Optional<syncer::ModelError>& error,
       std::unique_ptr<SessionStore> store,
       std::unique_ptr<syncer::MetadataBatch> metadata_batch)>;
-  using Factory =
-      base::RepeatingCallback<void(const syncer::DeviceInfo& device_info,
-                                   FactoryCompletionCallback callback)>;
   // Mimics signature of FaviconCache::UpdateMappingsFromForeignTab().
   using RestoredForeignTabCallback =
       base::RepeatingCallback<void(const sync_pb::SessionTab&, base::Time)>;
 
-  // Creates a factory object that is capable of constructing instances of type
-  // |SessionStore| and handling the involved IO. |sessions_client| must not be
-  // null and must outlive the factory as well as the instantiated stores.
-  static Factory CreateFactory(
+  // Opens a SessionStore instance, which involves IO to load previous state
+  // from disk. |sessions_client| must not be null and must outlive the
+  // SessionStore instance returned via |callback|, or until the callback is
+  // cancelled.
+  static void Open(
+      const syncer::DeviceInfo& device_info,
+      const RestoredForeignTabCallback& restored_foreign_tab_callback,
       SyncSessionsClient* sessions_client,
-      const RestoredForeignTabCallback& restored_foreign_tab_callback);
+      OpenCallback callback);
 
   // Verifies whether a proto is malformed (e.g. required fields are missing).
   static bool AreValidSpecifics(const sync_pb::SessionSpecifics& specifics);
@@ -120,15 +118,6 @@
     DISALLOW_COPY_AND_ASSIGN(WriteBatch);
   };
 
-  // Construction once all data and metadata has been loaded from disk. Use
-  // the factory above to take care of the IO. |sessions_client| must not be
-  // null and must outlive this object.
-  SessionStore(SyncSessionsClient* sessions_client,
-               const SessionInfo& local_session_info,
-               std::unique_ptr<syncer::ModelTypeStore> store,
-               std::map<std::string, sync_pb::SessionSpecifics> initial_data,
-               const syncer::EntityMetadataMap& initial_metadata,
-               const RestoredForeignTabCallback& restored_foreign_tab_callback);
   ~SessionStore();
 
   const SessionInfo& local_session_info() const { return local_session_info_; }
@@ -155,10 +144,43 @@
   const SyncedSessionTracker* tracker() const { return &session_tracker_; }
 
  private:
+  static void OnStoreCreated(
+      std::unique_ptr<SessionStore> session_store,
+      OpenCallback callback,
+      const base::Optional<syncer::ModelError>& error,
+      std::unique_ptr<syncer::ModelTypeStore> underlying_store);
+  static void OnReadAllMetadata(
+      std::unique_ptr<SessionStore> session_store,
+      OpenCallback callback,
+      std::unique_ptr<syncer::ModelTypeStore> underlying_store,
+      const base::Optional<syncer::ModelError>& error,
+      std::unique_ptr<syncer::MetadataBatch> metadata_batch);
+  static void OnReadAllData(
+      std::unique_ptr<SessionStore> session_store,
+      OpenCallback callback,
+      std::unique_ptr<syncer::ModelTypeStore> underlying_store,
+      std::unique_ptr<syncer::MetadataBatch> metadata_batch,
+      const base::Optional<syncer::ModelError>& error,
+      std::unique_ptr<syncer::ModelTypeStore::RecordList> record_list);
+
+  // Construction prior to any data being read from disk. Callers are expected
+  // to read state from disk and call Init(). |sessions_client| must not be null
+  // and must outlive this object.
+  SessionStore(const SessionInfo& local_session_info,
+               const RestoredForeignTabCallback& restored_foreign_tab_callback,
+               SyncSessionsClient* sessions_client);
+
+  // Initialization once IO is completed.
+  void Init(std::unique_ptr<syncer::ModelTypeStore> store,
+            std::map<std::string, sync_pb::SessionSpecifics> initial_data,
+            const syncer::EntityMetadataMap& initial_metadata);
+
+  const SessionInfo local_session_info_;
+  const RestoredForeignTabCallback restored_foreign_tab_callback_;
+
   // In charge of actually persisting changes to disk.
   std::unique_ptr<syncer::ModelTypeStore> store_;
 
-  const SessionInfo local_session_info_;
 
   SyncedSessionTracker session_tracker_;
 
diff --git a/components/sync_sessions/session_store_unittest.cc b/components/sync_sessions/session_store_unittest.cc
index 981a443..19566f3 100644
--- a/components/sync_sessions/session_store_unittest.cc
+++ b/components/sync_sessions/session_store_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/cancelable_callback.h"
 #include "base/run_loop.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
@@ -55,16 +56,16 @@
 
 // A mock callback that a) can be used as mock to verify call expectations and
 // b) conveniently exposes the last instantiated session store.
-class MockFactoryCompletionCallback {
+class MockOpenCallback {
  public:
   MOCK_METHOD3(Run,
                void(const base::Optional<syncer::ModelError>& error,
                     SessionStore* store,
                     MetadataBatch* metadata_batch));
 
-  SessionStore::FactoryCompletionCallback Get() {
+  SessionStore::OpenCallback Get() {
     return base::BindOnce(
-        [](MockFactoryCompletionCallback* callback,
+        [](MockOpenCallback* callback,
            const base::Optional<syncer::ModelError>& error,
            std::unique_ptr<SessionStore> store,
            std::unique_ptr<MetadataBatch> metadata_batch) {
@@ -153,9 +154,9 @@
   return result;
 }
 
-class SessionStoreFactoryTest : public ::testing::Test {
+class SessionStoreOpenTest : public ::testing::Test {
  protected:
-  SessionStoreFactoryTest()
+  SessionStoreOpenTest()
       : local_device_info_(kCacheGuid,
                            kClientName,
                            "Chromium 10k",
@@ -168,39 +169,39 @@
                 syncer::SESSIONS)) {
     SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry());
 
-    ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs())
+    mock_sync_sessions_client_ =
+        std::make_unique<testing::NiceMock<MockSyncSessionsClient>>();
+
+    ON_CALL(*mock_sync_sessions_client_, GetSessionSyncPrefs())
         .WillByDefault(Return(&session_sync_prefs_));
-    ON_CALL(mock_sync_sessions_client_, GetStoreFactory())
+    ON_CALL(*mock_sync_sessions_client_, GetStoreFactory())
         .WillByDefault(
             Return(syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(
                 underlying_store_.get())));
-
-    factory_ = SessionStore::CreateFactory(
-        &mock_sync_sessions_client_, mock_restored_foreign_tab_callback_.Get());
   }
 
-  ~SessionStoreFactoryTest() override {}
+  ~SessionStoreOpenTest() override {}
 
   base::test::ScopedTaskEnvironment task_environment_;
   const syncer::DeviceInfo local_device_info_;
   TestingPrefServiceSimple pref_service_;
   SessionSyncPrefs session_sync_prefs_;
-  testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
+  std::unique_ptr<MockSyncSessionsClient> mock_sync_sessions_client_;
   testing::NiceMock<
       base::MockCallback<SessionStore::RestoredForeignTabCallback>>
       mock_restored_foreign_tab_callback_;
-
   std::unique_ptr<ModelTypeStore> underlying_store_;
-  SessionStore::Factory factory_;
 };
 
-TEST_F(SessionStoreFactoryTest, ShouldCreateStore) {
+TEST_F(SessionStoreOpenTest, ShouldCreateStore) {
   ASSERT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), IsEmpty());
 
-  MockFactoryCompletionCallback completion;
+  MockOpenCallback completion;
   EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(),
                               MetadataBatchContains(_, IsEmpty())));
-  factory_.Run(local_device_info_, completion.Get());
+  SessionStore::Open(local_device_info_,
+                     mock_restored_foreign_tab_callback_.Get(),
+                     mock_sync_sessions_client_.get(), completion.Get());
   completion.Wait();
   ASSERT_THAT(completion.GetResult(), NotNull());
   EXPECT_THAT(completion.GetResult()->local_session_info().client_name,
@@ -209,12 +210,14 @@
               Eq(std::string("session_sync") + kCacheGuid));
 }
 
-TEST_F(SessionStoreFactoryTest, ShouldReadSessionsGuidFromPrefs) {
+TEST_F(SessionStoreOpenTest, ShouldReadSessionsGuidFromPrefs) {
   const std::string kCachedGuid = "cachedguid1";
   session_sync_prefs_.SetSyncSessionsGUID(kCachedGuid);
 
-  NiceMock<MockFactoryCompletionCallback> completion;
-  factory_.Run(local_device_info_, completion.Get());
+  NiceMock<MockOpenCallback> completion;
+  SessionStore::Open(local_device_info_,
+                     mock_restored_foreign_tab_callback_.Get(),
+                     mock_sync_sessions_client_.get(), completion.Get());
   completion.Wait();
   ASSERT_THAT(completion.GetResult(), NotNull());
   EXPECT_THAT(completion.GetResult()->local_session_info().session_tag,
@@ -222,8 +225,47 @@
   EXPECT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), Eq(kCachedGuid));
 }
 
+TEST_F(SessionStoreOpenTest, ShouldNotUseClientIfCancelled) {
+  // Mimics a caller that uses a weak pointer.
+  class Caller {
+   public:
+    explicit Caller(SessionStore::OpenCallback cb)
+        : cb_(std::move(cb)), weak_ptr_factory_(this) {}
+
+    SessionStore::OpenCallback GetCancelableCallback() {
+      return base::BindOnce(&Caller::Completed, weak_ptr_factory_.GetWeakPtr());
+    }
+
+   private:
+    void Completed(const base::Optional<syncer::ModelError>& error,
+                   std::unique_ptr<SessionStore> store,
+                   std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
+      std::move(cb_).Run(error, std::move(store), std::move(metadata_batch));
+    }
+
+    SessionStore::OpenCallback cb_;
+    base::WeakPtrFactory<Caller> weak_ptr_factory_;
+  };
+
+  NiceMock<MockOpenCallback> mock_completion;
+  auto caller = std::make_unique<Caller>(mock_completion.Get());
+
+  EXPECT_CALL(mock_completion, Run(_, _, _)).Times(0);
+
+  SessionStore::Open(
+      local_device_info_, mock_restored_foreign_tab_callback_.Get(),
+      mock_sync_sessions_client_.get(), caller->GetCancelableCallback());
+
+  // The client gets destroyed before callback completion.
+  mock_sync_sessions_client_.reset();
+  caller.reset();
+
+  // Run until idle to test for crashes due to use-after-free.
+  base::RunLoop().RunUntilIdle();
+}
+
 // Test fixture that creates an initial session store.
-class SessionStoreTest : public SessionStoreFactoryTest {
+class SessionStoreTest : public SessionStoreOpenTest {
  protected:
   const std::string kLocalSessionTag = "localsessiontag";
 
@@ -233,8 +275,10 @@
   }
 
   std::unique_ptr<SessionStore> CreateSessionStore() {
-    NiceMock<MockFactoryCompletionCallback> completion;
-    factory_.Run(local_device_info_, completion.Get());
+    NiceMock<MockOpenCallback> completion;
+    SessionStore::Open(local_device_info_,
+                       mock_restored_foreign_tab_callback_.Get(),
+                       mock_sync_sessions_client_.get(), completion.Get());
     completion.Wait();
     EXPECT_THAT(completion.GetResult(), NotNull());
     return completion.StealResult();
@@ -297,12 +341,14 @@
                                     ElementsAre(Pair(kStorageKey1, _))));
 
   // Create second session store.
-  NiceMock<MockFactoryCompletionCallback> completion;
+  NiceMock<MockOpenCallback> completion;
   EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(),
                               MetadataBatchContains(
                                   HasEncryptionKeyName(kEncryptionKeyName1),
                                   ElementsAre(Pair(kStorageKey1, _)))));
-  factory_.Run(local_device_info_, completion.Get());
+  SessionStore::Open(local_device_info_,
+                     mock_restored_foreign_tab_callback_.Get(),
+                     mock_sync_sessions_client_.get(), completion.Get());
   completion.Wait();
   EXPECT_THAT(completion.GetResult(), NotNull());
   EXPECT_NE(session_store(), completion.GetResult());
diff --git a/components/sync_sessions/session_sync_bridge.cc b/components/sync_sessions/session_sync_bridge.cc
index b9956b5b..2536229 100644
--- a/components/sync_sessions/session_sync_bridge.cc
+++ b/components/sync_sessions/session_sync_bridge.cc
@@ -112,10 +112,6 @@
       favicon_cache_(sessions_client->GetFaviconService(),
                      sessions_client->GetHistoryService(),
                      kMaxSyncFavicons),
-      session_store_factory_(SessionStore::CreateFactory(
-          sessions_client,
-          base::BindRepeating(&FaviconCache::UpdateMappingsFromForeignTab,
-                              base::Unretained(&favicon_cache_)))),
       weak_ptr_factory_(this) {
   DCHECK(sessions_client_);
   DCHECK(local_session_event_router_);
@@ -159,7 +155,7 @@
 base::Optional<syncer::ModelError> SessionSyncBridge::MergeSyncData(
     std::unique_ptr<MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_data) {
-  DCHECK(syncing_);
+  DCHECK(!syncing_);
   DCHECK(change_processor()->IsTrackingMetadata());
 
   StartLocalSessionEventHandler();
@@ -170,14 +166,22 @@
 
 void SessionSyncBridge::StartLocalSessionEventHandler() {
   // We should be ready to propagate local state to sync.
-  DCHECK(syncing_);
-  DCHECK(!syncing_->local_session_event_handler);
   DCHECK(change_processor()->IsTrackingMetadata());
+  DCHECK(!syncing_);
 
+  syncing_.emplace();
+
+  // Constructing LocalSessionEventHandlerImpl takes care of the "merge" logic,
+  // that is, associating the local windows and tabs with the state in the
+  // store.
   syncing_->local_session_event_handler =
       std::make_unique<LocalSessionEventHandlerImpl>(
-          /*delegate=*/this, sessions_client_,
-          syncing_->store->mutable_tracker());
+          /*delegate=*/this, sessions_client_, store_->mutable_tracker());
+
+  syncing_->open_tabs_ui_delegate = std::make_unique<OpenTabsUIDelegateImpl>(
+      sessions_client_, store_->tracker(), &favicon_cache_,
+      base::BindRepeating(&SessionSyncBridge::DeleteForeignSessionFromUI,
+                          base::Unretained(this)));
 
   // Start processing local changes, which will be propagated to the store as
   // well as the processor.
@@ -203,8 +207,7 @@
         // Deletions are all or nothing (since we only ever delete entire
         // sessions). Therefore we don't care if it's a tab node or meta node,
         // and just ensure we've disassociated.
-        if (syncing_->store->StorageKeyMatchesLocalSession(
-                change.storage_key())) {
+        if (store_->StorageKeyMatchesLocalSession(change.storage_key())) {
           // Another client has attempted to delete our local data (possibly by
           // error or a clock is inaccurate). Just ignore the deletion for now.
           DLOG(WARNING) << "Local session data deleted. Ignoring until next "
@@ -227,8 +230,7 @@
       case syncer::EntityChange::ACTION_UPDATE: {
         const SessionSpecifics& specifics = change.data().specifics.session();
 
-        if (syncing_->store->StorageKeyMatchesLocalSession(
-                change.storage_key())) {
+        if (store_->StorageKeyMatchesLocalSession(change.storage_key())) {
           // We should only ever receive a change to our own machine's session
           // info if encryption was turned on. In that case, the data is still
           // the same, so we can ignore.
@@ -272,12 +274,12 @@
 void SessionSyncBridge::GetData(StorageKeyList storage_keys,
                                 DataCallback callback) {
   DCHECK(syncing_);
-  std::move(callback).Run(syncing_->store->GetSessionDataForKeys(storage_keys));
+  std::move(callback).Run(store_->GetSessionDataForKeys(storage_keys));
 }
 
 void SessionSyncBridge::GetAllDataForDebugging(DataCallback callback) {
   DCHECK(syncing_);
-  std::move(callback).Run(syncing_->store->GetAllSessionData());
+  std::move(callback).Run(store_->GetAllSessionData());
 }
 
 std::string SessionSyncBridge::GetClientTag(
@@ -298,12 +300,13 @@
 
 ModelTypeSyncBridge::StopSyncResponse SessionSyncBridge::ApplyStopSyncChanges(
     std::unique_ptr<MetadataChangeList> delete_metadata_change_list) {
+  DCHECK(store_);
   local_session_event_router_->Stop();
-  if (syncing_ && delete_metadata_change_list) {
-    syncing_->store->DeleteAllDataAndMetadata();
+  if (delete_metadata_change_list) {
+    store_->DeleteAllDataAndMetadata();
   }
   syncing_.reset();
-  return StopSyncResponse::kModelNoLongerReadyToSync;
+  return StopSyncResponse::kModelStillReadyToSync;
 }
 
 std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
@@ -323,13 +326,13 @@
   }
 
   return std::make_unique<LocalSessionWriteBatch>(
-      syncing_->store->local_session_info(), CreateSessionStoreWriteBatch(),
+      store_->local_session_info(), CreateSessionStoreWriteBatch(),
       change_processor());
 }
 
 bool SessionSyncBridge::IsTabNodeUnsynced(int tab_node_id) {
   const std::string storage_key = SessionStore::GetTabStorageKey(
-      syncing_->store->local_session_info().session_tag, tab_node_id);
+      store_->local_session_info().session_tag, tab_node_id);
   return change_processor()->IsEntityUnsynced(storage_key);
 }
 
@@ -351,6 +354,17 @@
     const syncer::DataTypeActivationRequest& request) {
   DCHECK(!syncing_);
 
+  // |store_| may be already initialized if sync was previously started and
+  // then stopped.
+  if (store_) {
+    // If initial sync was already done, MergeSyncData() will never be called so
+    // we need to start syncing local changes.
+    if (change_processor()->IsTrackingMetadata()) {
+      StartLocalSessionEventHandler();
+    }
+    return;
+  }
+
   const syncer::DeviceInfo* device_info =
       sessions_client_->GetLocalDeviceInfo();
 
@@ -359,9 +373,14 @@
   DCHECK(device_info);
   DCHECK_EQ(device_info->guid(), request.cache_guid);
 
-  session_store_factory_.Run(
-      *device_info, base::BindOnce(&SessionSyncBridge::OnStoreInitialized,
-                                   weak_ptr_factory_.GetWeakPtr()));
+  // Open the store and read state from disk if it exists.
+  SessionStore::Open(
+      *device_info,
+      base::BindRepeating(&FaviconCache::UpdateMappingsFromForeignTab,
+                          favicon_cache_.GetWeakPtr()),
+      sessions_client_,
+      base::BindOnce(&SessionSyncBridge::OnStoreInitialized,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void SessionSyncBridge::OnStoreInitialized(
@@ -378,12 +397,7 @@
   DCHECK(store);
   DCHECK(metadata_batch);
 
-  syncing_.emplace();
-  syncing_->store = std::move(store);
-  syncing_->open_tabs_ui_delegate = std::make_unique<OpenTabsUIDelegateImpl>(
-      sessions_client_, syncing_->store->tracker(), &favicon_cache_,
-      base::BindRepeating(&SessionSyncBridge::DeleteForeignSessionFromUI,
-                          base::Unretained(this)));
+  store_ = std::move(store);
 
   change_processor()->ModelReadyToSync(std::move(metadata_batch));
 
@@ -416,8 +430,7 @@
   // Iterate through all the sessions and delete any with age older than
   // |kStaleSessionThreshold|.
   for (const auto* session :
-       syncing_->store->tracker()->LookupAllForeignSessions(
-           SyncedSessionTracker::RAW)) {
+       store_->tracker()->LookupAllForeignSessions(SyncedSessionTracker::RAW)) {
     const base::TimeDelta session_age =
         base::Time::Now() - session->modified_time;
     if (session_age > kStaleSessionThreshold) {
@@ -437,7 +450,7 @@
   DCHECK(syncing_);
   DCHECK(change_processor()->IsTrackingMetadata());
 
-  if (session_tag == syncing_->store->local_session_info().session_tag) {
+  if (session_tag == store_->local_session_info().session_tag) {
     DLOG(ERROR) << "Attempting to delete local session. This is not currently "
                 << "supported.";
     return;
@@ -459,7 +472,7 @@
 SessionSyncBridge::CreateSessionStoreWriteBatch() {
   DCHECK(syncing_);
 
-  return syncing_->store->CreateWriteBatch(base::BindOnce(
+  return store_->CreateWriteBatch(base::BindOnce(
       &SessionSyncBridge::ReportError, weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -470,11 +483,10 @@
 
   std::unique_ptr<SessionStore::WriteBatch> write_batch =
       CreateSessionStoreWriteBatch();
-  std::unique_ptr<syncer::DataBatch> read_batch =
-      syncing_->store->GetAllSessionData();
+  std::unique_ptr<syncer::DataBatch> read_batch = store_->GetAllSessionData();
   while (read_batch->HasNext()) {
     syncer::KeyAndData key_and_data = read_batch->Next();
-    if (syncing_->store->StorageKeyMatchesLocalSession(key_and_data.first)) {
+    if (store_->StorageKeyMatchesLocalSession(key_and_data.first)) {
       change_processor()->Put(key_and_data.first,
                               std::move(key_and_data.second),
                               write_batch->GetMetadataChangeList());
diff --git a/components/sync_sessions/session_sync_bridge.h b/components/sync_sessions/session_sync_bridge.h
index 6bd112c3..ac726fc 100644
--- a/components/sync_sessions/session_sync_bridge.h
+++ b/components/sync_sessions/session_sync_bridge.h
@@ -97,14 +97,13 @@
 
   FaviconCache favicon_cache_;
   SessionsGlobalIdMapper global_id_mapper_;
-  SessionStore::Factory session_store_factory_;
+  std::unique_ptr<SessionStore> store_;
 
   // All data dependent on sync being starting or started.
   struct SyncingState {
     SyncingState();
     ~SyncingState();
 
-    std::unique_ptr<SessionStore> store;
     std::unique_ptr<OpenTabsUIDelegateImpl> open_tabs_ui_delegate;
     std::unique_ptr<LocalSessionEventHandlerImpl> local_session_event_handler;
 
@@ -118,6 +117,7 @@
     bool local_data_out_of_sync = false;
   };
 
+  // TODO(mastiz): We should rather rename this to |syncing_state_|.
   base::Optional<SyncingState> syncing_;
 
   base::WeakPtrFactory<SessionSyncBridge> weak_ptr_factory_;
diff --git a/components/sync_sessions/session_sync_bridge_unittest.cc b/components/sync_sessions/session_sync_bridge_unittest.cc
index 47a81ff..e0204fe 100644
--- a/components/sync_sessions/session_sync_bridge_unittest.cc
+++ b/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -983,7 +983,6 @@
   EXPECT_CALL(mock_processor(), ModelReadyToSync(_)).Times(0);
   real_processor()->OnSyncStopping(syncer::CLEAR_METADATA);
 
-  EXPECT_CALL(mock_processor(), ModelReadyToSync(IsEmptyMetadataBatch()));
   StartSyncing();
   ASSERT_THAT(GetData(header_storage_key),
               EntityDataHasSpecifics(
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc
index 6fc8b603..956bc38 100644
--- a/components/unified_consent/unified_consent_service.cc
+++ b/components/unified_consent/unified_consent_service.cc
@@ -80,7 +80,7 @@
 }
 
 void UnifiedConsentService::OnPrimaryAccountCleared(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   // By design, clearing the primary account disables URL-keyed data collection.
   pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
                             false);
diff --git a/components/unified_consent/unified_consent_service.h b/components/unified_consent/unified_consent_service.h
index fcb60906..8a30d51 100644
--- a/components/unified_consent/unified_consent_service.h
+++ b/components/unified_consent/unified_consent_service.h
@@ -64,7 +64,7 @@
 
   // IdentityManager::Observer:
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
  private:
   friend class UnifiedConsentServiceTest;
diff --git a/components/version_ui/resources/about_version.html b/components/version_ui/resources/about_version.html
index a6ddaff..83e5252 100644
--- a/components/version_ui/resources/about_version.html
+++ b/components/version_ui/resources/about_version.html
@@ -145,6 +145,5 @@
         </tr>
       </table>
     </div>
-    <script src="chrome://resources/js/i18n_template.js"></script>
   </body>
 </html>
diff --git a/components/viz/common/gl_scaler.cc b/components/viz/common/gl_scaler.cc
index a05d958..78b5725 100644
--- a/components/viz/common/gl_scaler.cc
+++ b/components/viz/common/gl_scaler.cc
@@ -1389,6 +1389,7 @@
   // It would be better to stash the existing parameter values, and restore them
   // back later. However, glGetTexParameteriv() currently requires a blocking
   // call to the GPU service, which is extremely costly performance-wise.
+  gl_->ActiveTexture(GL_TEXTURE0);
   gl_->BindTexture(GL_TEXTURE_2D, src_texture);
   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
diff --git a/components/viz/service/display/gl_renderer_copier.cc b/components/viz/service/display/gl_renderer_copier.cc
index 19a25fc..72ca221 100644
--- a/components/viz/service/display/gl_renderer_copier.cc
+++ b/components/viz/service/display/gl_renderer_copier.cc
@@ -212,7 +212,7 @@
       // requires that the result be accessed via a task in the same task runner
       // sequence as the GLRendererCopier. Since I420_PLANES requests are meant
       // to be VIZ-internal, this is an acceptable limitation to enforce.
-      DCHECK(request->SendsResultsInCurrentSequence());
+      DCHECK(request->SendsResultsInCurrentSequence() || async_gl_task_runner_);
 
       const gfx::Rect aligned_rect = RenderI420Textures(
           *request, flipped_source, color_space, source_texture,
@@ -610,17 +610,41 @@
  public:
   // |aligned_rect| identifies the region of result pixels in the pixel buffer,
   // while the |result_rect| is the subregion that is exposed to the client.
-  GLPixelBufferI420Result(const gfx::Rect& aligned_rect,
-                          const gfx::Rect& result_rect,
-                          scoped_refptr<ContextProvider> context_provider,
-                          GLuint transfer_buffer)
+  GLPixelBufferI420Result(
+      const gfx::Rect& aligned_rect,
+      const gfx::Rect& result_rect,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      scoped_refptr<ContextProvider> context_provider,
+      GLuint transfer_buffer)
       : CopyOutputResult(CopyOutputResult::Format::I420_PLANES, result_rect),
         aligned_rect_(aligned_rect),
+        task_runner_(task_runner),
         context_provider_(std::move(context_provider)),
-        transfer_buffer_(transfer_buffer) {}
+        transfer_buffer_(transfer_buffer) {
+    auto* const gl = context_provider_->ContextGL();
+    gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
+    pixels_ = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
+        GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+    gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+  }
 
   ~GLPixelBufferI420Result() final {
-    context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_);
+    auto cleanup = base::BindOnce(
+        [](scoped_refptr<ContextProvider> context_provider,
+           GLuint transfer_buffer) {
+          auto* const gl = context_provider->ContextGL();
+          gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+                         transfer_buffer);
+          gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
+          gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+          gl->DeleteBuffers(1, &transfer_buffer);
+        },
+        context_provider_, transfer_buffer_);
+    if (task_runner_) {
+      task_runner_->PostTask(FROM_HERE, std::move(cleanup));
+    } else {
+      std::move(cleanup).Run();
+    }
   }
 
   bool ReadI420Planes(uint8_t* y_out,
@@ -634,10 +658,7 @@
     DCHECK_GE(u_out_stride, chroma_row_bytes);
     DCHECK_GE(v_out_stride, chroma_row_bytes);
 
-    auto* const gl = context_provider_->ContextGL();
-    gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
-    const uint8_t* pixels = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
-        GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+    uint8_t* pixels = pixels_;
     if (pixels) {
       const auto CopyPlane = [](const uint8_t* src, int src_stride,
                                 int row_bytes, int num_rows, uint8_t* out,
@@ -664,18 +685,16 @@
       pixels += chroma_stride * (aligned_rect_.height() / 2);
       CopyPlane(pixels + chroma_start_offset, chroma_stride, chroma_row_bytes,
                 chroma_height, v_out, v_out_stride);
-      gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
     }
-    gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
-
     return !!pixels;
   }
 
  private:
   const gfx::Rect aligned_rect_;
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   const scoped_refptr<ContextProvider> context_provider_;
   const GLuint transfer_buffer_;
-  const gfx::Vector2d i420_offset_;
+  uint8_t* pixels_;
 };
 
 // Like the ReadPixelsWorkflow, except for I420 planes readback. Because there
@@ -692,13 +711,16 @@
 class ReadI420PlanesWorkflow
     : public base::RefCountedThreadSafe<ReadI420PlanesWorkflow> {
  public:
-  ReadI420PlanesWorkflow(std::unique_ptr<CopyOutputRequest> copy_request,
-                         const gfx::Rect& aligned_rect,
-                         const gfx::Rect& result_rect,
-                         scoped_refptr<ContextProvider> context_provider)
+  ReadI420PlanesWorkflow(
+      std::unique_ptr<CopyOutputRequest> copy_request,
+      const gfx::Rect& aligned_rect,
+      const gfx::Rect& result_rect,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      scoped_refptr<ContextProvider> context_provider)
       : copy_request_(std::move(copy_request)),
         aligned_rect_(aligned_rect),
         result_rect_(result_rect),
+        task_runner_(std::move(task_runner)),
         context_provider_(std::move(context_provider)) {
     // Create a buffer for the pixel transfer: A single buffer is used and will
     // contain the Y plane, then the U plane, then the V plane.
@@ -779,7 +801,8 @@
     // If all three readbacks have completed, send the result.
     if (queries_ == std::array<GLuint, 3>{{0, 0, 0}}) {
       copy_request_->SendResult(std::make_unique<GLPixelBufferI420Result>(
-          aligned_rect_, result_rect_, context_provider_, transfer_buffer_));
+          aligned_rect_, result_rect_, task_runner_, context_provider_,
+          transfer_buffer_));
       transfer_buffer_ = 0;  // Ownership was transferred to the result.
     }
   }
@@ -787,6 +810,7 @@
   const std::unique_ptr<CopyOutputRequest> copy_request_;
   const gfx::Rect aligned_rect_;
   const gfx::Rect result_rect_;
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   const scoped_refptr<ContextProvider> context_provider_;
   GLuint transfer_buffer_;
   std::array<int, 3> data_offsets_;
@@ -810,7 +834,8 @@
   // CopyOutputRequest is passed to the ReadI420PlanesWorkflow, which will send
   // the CopyOutputResult once all readback operations are complete.
   const auto workflow = base::MakeRefCounted<ReadI420PlanesWorkflow>(
-      std::move(request), aligned_rect, result_rect, context_provider_);
+      std::move(request), aligned_rect, result_rect, async_gl_task_runner_,
+      context_provider_);
   workflow->BindTransferBuffer();
   for (int plane = 0; plane < 3; ++plane) {
     gl->BindFramebuffer(GL_FRAMEBUFFER,
diff --git a/components/viz/service/display/gl_renderer_copier.h b/components/viz/service/display/gl_renderer_copier.h
index 4d89ed24..4038994 100644
--- a/components/viz/service/display/gl_renderer_copier.h
+++ b/components/viz/service/display/gl_renderer_copier.h
@@ -14,11 +14,15 @@
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
 #include "base/unguessable_token.h"
 #include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
 #include "ui/gfx/geometry/size.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
 namespace gfx {
 class ColorSpace;
 class Rect;
@@ -61,6 +65,11 @@
 // "source" has ended.
 class VIZ_SERVICE_EXPORT GLRendererCopier {
  public:
+  // Define types to avoid pulling in command buffer GL headers, which conflict
+  // the ui/gl/gl_bindings.h
+  using GLuint = unsigned int;
+  using GLenum = unsigned int;
+
   // |texture_deleter| must outlive this instance.
   GLRendererCopier(scoped_refptr<ContextProvider> context_provider,
                    TextureDeleter* texture_deleter);
@@ -95,6 +104,11 @@
   // finished drawing (after all copy requests have been executed).
   void FreeUnusedCachedResources();
 
+  void set_async_gl_task_runner(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    async_gl_task_runner_ = task_runner;
+  }
+
  private:
   friend class GLRendererCopierTest;
 
@@ -108,7 +122,7 @@
     // Texture containing a copy of the source framebuffer, if the source
     // framebuffer cannot be used directly.
     GLuint fb_copy_texture = 0;
-    GLenum fb_copy_texture_internal_format = static_cast<GLenum>(GL_NONE);
+    GLenum fb_copy_texture_internal_format = static_cast<GLenum>(0 /*GL_NONE*/);
     gfx::Size fb_copy_texture_size;
 
     // RGBA requests: Scaling, and texture/framebuffer for readback.
@@ -262,7 +276,7 @@
   // efficiently using GL_RGBA or GL_BGRA_EXT format. This starts out as
   // GL_NONE, which means "unknown," and will be determined at the time the
   // first readback request is made.
-  GLenum optimal_readback_format_ = static_cast<GLenum>(GL_NONE);
+  GLenum optimal_readback_format_ = static_cast<GLenum>(0 /*GL_NONE*/);
 
   // Purge cache entries that have not been used after this many calls to
   // FreeUnusedCachedResources(). The choice of 60 is arbitrary, but on most
@@ -270,6 +284,12 @@
   // things to be auto-purged after approx. 1-2 seconds of not being used.
   static constexpr int kKeepalivePeriod = 60;
 
+  // The task runner that is being used to call into GLRendererCopier. This
+  // allows for CopyOutputResults, owned by external entities, to execute
+  // post-destruction clean-up tasks. If null, assume CopyOutputResults are
+  // always destroyed from the same task runner
+  scoped_refptr<base::SingleThreadTaskRunner> async_gl_task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(GLRendererCopier);
 };
 
diff --git a/components/viz/service/display/gl_renderer_copier_pixeltest.cc b/components/viz/service/display/gl_renderer_copier_pixeltest.cc
index 9e7de024c..5f5edba 100644
--- a/components/viz/service/display/gl_renderer_copier_pixeltest.cc
+++ b/components/viz/service/display/gl_renderer_copier_pixeltest.cc
@@ -25,6 +25,7 @@
 #include "components/viz/common/frame_sinks/copy_output_util.h"
 #include "components/viz/service/display/gl_renderer.h"
 #include "components/viz/test/paths.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
diff --git a/components/viz/service/display_embedder/DEPS b/components/viz/service/display_embedder/DEPS
index 1246dfd..34132c6 100644
--- a/components/viz/service/display_embedder/DEPS
+++ b/components/viz/service/display_embedder/DEPS
@@ -36,11 +36,13 @@
   "+ui/ozone/public",
 
   # TODO(danakj): Double check the layering for these dependencies.
+  "+components/viz/service/display/gl_renderer_copier.h",
   "+components/viz/service/display/overlay_processor.h",
   "+components/viz/service/display/overlay_strategy_fullscreen.h",
   "+components/viz/service/display/overlay_strategy_single_on_top.h",
   "+components/viz/service/display/overlay_strategy_underlay_cast.h",
   "+components/viz/service/display/overlay_strategy_underlay.h",
+  "+components/viz/service/display/texture_deleter.h",
 ]
 
 specific_include_rules = {
diff --git a/components/viz/service/display_embedder/direct_context_provider.cc b/components/viz/service/display_embedder/direct_context_provider.cc
index aaf1862..e315b82 100644
--- a/components/viz/service/display_embedder/direct_context_provider.cc
+++ b/components/viz/service/display_embedder/direct_context_provider.cc
@@ -113,6 +113,12 @@
 
 void DirectContextProvider::Destroy() {
   DCHECK(decoder_);
+  bool have_context = !decoder_->WasContextLost();
+  if (have_context && framebuffer_id_ != 0) {
+    gles2_implementation_->DeleteFramebuffers(1, &framebuffer_id_);
+    framebuffer_id_ = 0;
+  }
+
   // The client gl interface might still be set to current global
   // interface. This will be cleaned up in ApplyContextReleased
   // with AutoCurrentContextRestore.
@@ -122,16 +128,33 @@
   gles2_cmd_helper_.reset();
   command_buffer_.reset();
 
-  bool have_context = !decoder_->WasContextLost();
   decoder_->Destroy(have_context);
   decoder_.reset();
 }
 
-void DirectContextProvider::SetGLRendererCopierRequiredState() {
+void DirectContextProvider::SetGLRendererCopierRequiredState(
+    GLuint texture_client_id) {
+  // Get into known state (see
+  // SkiaOutputSurfaceImplOnGpu::ScopedUseContextProvider).
   gles2_implementation_->BindFramebuffer(GL_FRAMEBUFFER, 0);
   gles2_implementation_->Disable(GL_SCISSOR_TEST);
   gles2_implementation_->Disable(GL_STENCIL_TEST);
   gles2_implementation_->Disable(GL_BLEND);
+
+  if (texture_client_id) {
+    if (!framebuffer_id_)
+      gles2_implementation_->GenFramebuffers(1, &framebuffer_id_);
+    gles2_implementation_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
+    gles2_implementation_->FramebufferTexture2D(
+        GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_client_id,
+        0);
+    DCHECK_EQ(gles2_implementation_->CheckFramebufferStatus(GL_FRAMEBUFFER),
+              static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE));
+  }
+}
+
+gpu::gles2::TextureManager* DirectContextProvider::texture_manager() {
+  return decoder_->GetContextGroup()->texture_manager();
 }
 
 void DirectContextProvider::AddRef() const {
@@ -287,4 +310,17 @@
   return false;
 }
 
+GLuint DirectContextProvider::GenClientTextureId() {
+  const auto& share_group = gles2_implementation_->share_group();
+  auto* id_handler =
+      share_group->GetIdHandler(gpu::gles2::SharedIdNamespaces::kTextures);
+  GLuint client_id;
+  id_handler->MakeIds(gles2_implementation_.get(), 0, 1, &client_id);
+  return client_id;
+}
+
+void DirectContextProvider::DeleteClientTextureId(GLuint client_id) {
+  gles2_implementation_->DeleteTextures(1, &client_id);
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/direct_context_provider.h b/components/viz/service/display_embedder/direct_context_provider.h
index f460ae9..77ece27 100644
--- a/components/viz/service/display_embedder/direct_context_provider.h
+++ b/components/viz/service/display_embedder/direct_context_provider.h
@@ -35,6 +35,7 @@
 class GLES2CmdHelper;
 class GLES2Implementation;
 class GLES2Interface;
+class TextureManager;
 }  // namespace gles2
 }  // namespace gpu
 
@@ -60,7 +61,14 @@
                         const gpu::GpuPreferences& gpu_preferences,
                         gpu::gles2::FeatureInfo* feature_info);
   gpu::DecoderContext* decoder() { return decoder_.get(); }
-  void SetGLRendererCopierRequiredState();
+
+  // Set required state, including texture_client_id as color attachment 0
+  // of a currently bound framebuffer. If texture_client_id == 0, set FBO0 as
+  // current.
+  void SetGLRendererCopierRequiredState(GLuint texture_client_id);
+  gpu::gles2::TextureManager* texture_manager();
+  GLuint GenClientTextureId();
+  void DeleteClientTextureId(GLuint client_id);
 
   // ContextProvider implementation.
   void AddRef() const override;
@@ -133,6 +141,8 @@
   scoped_refptr<gl::GLContext> gl_context_;
   std::unique_ptr<gpu::gles2::GLES2Implementation> gles2_implementation_;
 
+  GLuint framebuffer_id_ = 0;
+
   base::ObserverList<ContextLostObserver>::Unchecked observers_;
 };
 
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 97cd4779..c7c1f9d 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -12,7 +12,9 @@
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_util.h"
 #include "components/viz/common/skia_helper.h"
+#include "components/viz/service/display/gl_renderer_copier.h"
 #include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/display/texture_deleter.h"
 #include "components/viz/service/display_embedder/direct_context_provider.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
@@ -119,6 +121,99 @@
   return nullptr;
 }
 
+class ScopedSurfaceToTexture {
+ public:
+  ScopedSurfaceToTexture(scoped_refptr<DirectContextProvider> context_provider,
+                         SkSurface* surface)
+      : context_provider_(context_provider) {
+    GrBackendTexture skia_texture =
+        surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
+    GrGLTextureInfo gl_texture_info;
+    skia_texture.getGLTextureInfo(&gl_texture_info);
+    GLuint client_id = context_provider_->GenClientTextureId();
+    auto* texture_manager = context_provider_->texture_manager();
+    texture_ref_ =
+        texture_manager->CreateTexture(client_id, gl_texture_info.fID);
+    texture_manager->SetTarget(texture_ref_.get(), gl_texture_info.fTarget);
+    texture_manager->SetLevelInfo(
+        texture_ref_.get(), gl_texture_info.fTarget,
+        /*level=*/0,
+        /*internal_format=*/GL_RGBA, surface->width(), surface->height(),
+        /*depth=*/1, /*border=*/0,
+        /*format=*/GL_RGBA, /*type=*/GL_UNSIGNED_BYTE,
+        /*cleared_rect=*/gfx::Rect(surface->width(), surface->height()));
+  }
+
+  ~ScopedSurfaceToTexture() {
+    context_provider_->DeleteClientTextureId(client_id());
+
+    // Skia owns the texture. It will delete it when it is done.
+    texture_ref_->ForceContextLost();
+  }
+
+  GLuint client_id() { return texture_ref_->client_id(); }
+
+ private:
+  scoped_refptr<DirectContextProvider> context_provider_;
+  scoped_refptr<gpu::gles2::TextureRef> texture_ref_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSurfaceToTexture);
+};
+
+// This SingleThreadTaskRunner runs tasks on the GPU main thread, where
+// DirectContextProvider can safely service calls. It wraps all posted tasks to
+// ensure that |impl_on_gpu_->context_provider_| is made current and in a known
+// state when the task is run. If |impl_on_gpu| is destructed, pending tasks are
+// no-oped when they are run.
+class ContextCurrentTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  explicit ContextCurrentTaskRunner(SkiaOutputSurfaceImplOnGpu* impl_on_gpu)
+      : real_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+        impl_on_gpu_(impl_on_gpu) {}
+
+  bool PostDelayedTask(const base::Location& from_here,
+                       base::OnceClosure task,
+                       base::TimeDelta delay) override {
+    return real_task_runner_->PostDelayedTask(
+        from_here, WrapClosure(std::move(task)), delay);
+  }
+
+  bool PostNonNestableDelayedTask(const base::Location& from_here,
+                                  base::OnceClosure task,
+                                  base::TimeDelta delay) override {
+    return real_task_runner_->PostNonNestableDelayedTask(
+        from_here, WrapClosure(std::move(task)), delay);
+  }
+
+  bool RunsTasksInCurrentSequence() const override {
+    return real_task_runner_->RunsTasksInCurrentSequence();
+  }
+
+ private:
+  base::OnceClosure WrapClosure(base::OnceClosure task) {
+    return base::BindOnce(
+        [](base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
+           base::OnceClosure task) {
+          if (!impl_on_gpu)
+            return;
+          SkiaOutputSurfaceImplOnGpu::ScopedUseContextProvider scoped_use(
+              impl_on_gpu.get(), /*texture_client_id=*/0);
+          if (!scoped_use.valid())
+            return;
+
+          std::move(task).Run();
+        },
+        impl_on_gpu_->weak_ptr(), std::move(task));
+  }
+
+  ~ContextCurrentTaskRunner() override = default;
+
+  scoped_refptr<base::SingleThreadTaskRunner> real_task_runner_;
+  SkiaOutputSurfaceImplOnGpu* const impl_on_gpu_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContextCurrentTaskRunner);
+};
+
 }  // namespace
 
 SkiaOutputSurfaceImplOnGpu::OffscreenSurface::OffscreenSurface() = default;
@@ -140,7 +235,8 @@
     OffscreenSurface&& offscreen_surface) = default;
 
 SkiaOutputSurfaceImplOnGpu::ScopedUseContextProvider::ScopedUseContextProvider(
-    SkiaOutputSurfaceImplOnGpu* impl_on_gpu)
+    SkiaOutputSurfaceImplOnGpu* impl_on_gpu,
+    GLuint texture_client_id)
     : impl_on_gpu_(impl_on_gpu) {
   if (!impl_on_gpu_->MakeCurrent()) {
     valid_ = false;
@@ -149,14 +245,15 @@
 
   // GLRendererCopier uses context_provider_->ContextGL(), which caches GL state
   // and removes state setting calls that it considers redundant. To get to a
-  // safe known GL state, we first call the client side to set the cached state,
-  // then we make driver GL state consistent with that.
-  impl_on_gpu_->context_provider_->SetGLRendererCopierRequiredState();
+  // known GL state, we first set driver GL state and then make client side
+  // consistent with that.
   auto* api = impl_on_gpu_->api_;
   api->glBindFramebufferEXTFn(GL_FRAMEBUFFER, 0);
   api->glDisableFn(GL_SCISSOR_TEST);
   api->glDisableFn(GL_STENCIL_TEST);
   api->glDisableFn(GL_BLEND);
+  impl_on_gpu_->context_provider_->SetGLRendererCopierRequiredState(
+      texture_client_id);
 }
 
 SkiaOutputSurfaceImplOnGpu::ScopedUseContextProvider::
@@ -250,6 +347,7 @@
 
   // ~DirectContextProvider wants either the context to be lost or made current.
   MakeCurrent();
+  context_provider_.reset();
 
 #if BUILDFLAG(ENABLE_VULKAN)
   if (vulkan_surface_) {
@@ -481,7 +579,6 @@
     const copy_output::RenderPassGeometry& geometry,
     const gfx::ColorSpace& color_space,
     std::unique_ptr<CopyOutputRequest> request) {
-  // TODO(crbug.com/914502): Do this on the GPU instead of CPU with GL.
   // TODO(crbug.com/898595): Do this on the GPU instead of CPU with Vulkan.
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!MakeCurrent())
@@ -492,22 +589,50 @@
       id ? offscreen_surfaces_[id].surface.get() : sk_surface_.get();
 
   if (!is_using_vulkan()) {
-    if (!context_provider_) {
+    // Lazy initialize GLRendererCopier.
+    if (!copier_) {
       context_provider_ = base::MakeRefCounted<DirectContextProvider>(
           context_state_->context(), gl_surface_, supports_alpha_,
           gpu_preferences_, feature_info_.get());
-      context_provider_->BindToCurrentThread();
+      auto result = context_provider_->BindToCurrentThread();
+      if (result != gpu::ContextResult::kSuccess) {
+        DLOG(ERROR) << "Couldn't initialize GLRendererCopier";
+        context_provider_ = nullptr;
+        return;
+      }
+      context_current_task_runner_ =
+          base::MakeRefCounted<ContextCurrentTaskRunner>(this);
+      texture_deleter_ =
+          std::make_unique<TextureDeleter>(context_current_task_runner_);
+      copier_ = std::make_unique<GLRendererCopier>(context_provider_,
+                                                   texture_deleter_.get());
+      copier_->set_async_gl_task_runner(context_current_task_runner_);
     }
-    ScopedUseContextProvider use_context_provider(this);
+    surface->flush();
 
-    // TODO(crbug.com/914502): Do this on the GPU instead of CPU with GL.
-    // copier_->CopyFromTextureOrFramebuffer(
-    //     std::move(request), output_rect,
-    //     internal_format, gl_id, surface_size, flipped, color_space);
+    GLuint gl_id = 0;
+    GLenum internal_format = supports_alpha_ ? GL_RGBA : GL_RGB;
+    // TODO(https://crbug.com/929790): This seems to be because sk_surface_ for
+    // GL has kBottomLeft_kBottomLeft_GrSurfaceOrigin.
+    bool flipped = true;
 
-    // GLRendererCopier may have kicked off a glQuery.
+    base::Optional<ScopedSurfaceToTexture> texture_mapper;
+    if (id) {
+      texture_mapper.emplace(context_provider_.get(), surface);
+      gl_id = texture_mapper.value().client_id();
+      internal_format = GL_RGBA;
+      flipped = false;
+    }
+    gfx::Size surface_size(surface->width(), surface->height());
+    ScopedUseContextProvider use_context_provider(this, gl_id);
+    copier_->CopyFromTextureOrFramebuffer(std::move(request), geometry,
+                                          internal_format, gl_id, surface_size,
+                                          flipped, color_space);
+
     if (decoder()->HasMoreIdleWork() || decoder()->HasPendingQueries())
       ScheduleDelayedWork();
+
+    return;
   }
 
   SkBitmap bitmap;
@@ -590,7 +715,7 @@
 
 void SkiaOutputSurfaceImplOnGpu::PerformDelayedWork() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  ScopedUseContextProvider use_context_provider(this);
+  ScopedUseContextProvider use_context_provider(this, /*texture_client_id=*/0);
 
   delayed_work_pending_ = false;
   if (MakeCurrent()) {
@@ -892,6 +1017,9 @@
     if (!context_state_->MakeCurrent(gl_surface_.get())) {
       LOG(ERROR) << "Failed to make current.";
       context_lost_callback_.Run();
+      if (context_provider_)
+        context_provider_->decoder()->MarkContextLost(
+            gpu::error::kMakeCurrentFailed);
       return false;
     }
     context_state_->set_need_context_state_reset(true);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 63b715d6..25bc782 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -61,7 +61,9 @@
 namespace viz {
 
 class DirectContextProvider;
+class GLRendererCopier;
 class GpuServiceImpl;
+class TextureDeleter;
 
 namespace copy_output {
 struct RenderPassGeometry;
@@ -167,7 +169,8 @@
   // will keep cached state consistent with driver GL state.
   class ScopedUseContextProvider {
    public:
-    explicit ScopedUseContextProvider(SkiaOutputSurfaceImplOnGpu* impl_on_gpu);
+    explicit ScopedUseContextProvider(SkiaOutputSurfaceImplOnGpu* impl_on_gpu,
+                                      GLuint texture_client_id);
     ~ScopedUseContextProvider();
     bool valid() { return valid_; }
 
@@ -278,7 +281,11 @@
 
   ui::LatencyTracker latency_tracker_;
 
+  scoped_refptr<base::SingleThreadTaskRunner> context_current_task_runner_;
   scoped_refptr<DirectContextProvider> context_provider_;
+  std::unique_ptr<TextureDeleter> texture_deleter_;
+  std::unique_ptr<GLRendererCopier> copier_;
+
   bool delayed_work_pending_ = false;
 
   gl::GLApi* api_ = nullptr;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
index 70b1350..ee12fcff 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
@@ -192,7 +192,8 @@
 }
 
 TEST_F(SkiaOutputSurfaceImplTest, SubmitPaint) {
-  output_surface_->Reshape(gfx::Size(100.0, 100.0), 1, gfx::ColorSpace(), true,
+  const gfx::Rect surface_rect(0, 0, 100, 100);
+  output_surface_->Reshape(surface_rect.size(), 1, gfx::ColorSpace(), true,
                            false);
   SkCanvas* root_canvas = output_surface_->BeginPaintCurrentFrame();
   SkPaint paint;
@@ -224,10 +225,15 @@
                      color_space));
   request->set_result_task_runner(gpu_thread_->task_runner());
   copy_output::RenderPassGeometry geometry;
-  geometry.result_bounds = output_rect;
+  geometry.result_bounds = surface_rect;
   geometry.result_selection = output_rect;
-  geometry.sampling_bounds = output_rect;
-  geometry.readback_offset = gfx::Vector2d(0, 0);
+  geometry.sampling_bounds = surface_rect;
+  // TODO(https://crbug.com/929790): The need to change the value of
+  // readback_offset when using GLRendererCopier suggests a bug that needs
+  // further investigation because we will still have software readback for
+  // SkiaRenderer with Vulkan.
+  geometry.readback_offset = gfx::Vector2d(0, 90);
+
   output_surface_->CopyOutput(0, geometry, color_space, std::move(request));
   BlockMainThread();
 }
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index 4a4dd72..6abb9ff 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -76,8 +76,9 @@
 
   // All SurfaceClients and their surfaces are supposed to be
   // destroyed before SurfaceManager.
-  DCHECK(surface_map_.empty());
-  DCHECK(surfaces_to_destroy_.empty());
+  // TODO(crbug.com/823043): The following two DCHECKs don't hold.
+  // DCHECK(surface_map_.empty());
+  // DCHECK(surfaces_to_destroy_.empty());
 }
 
 #if DCHECK_IS_ON()
diff --git a/components/web_resource/web_resource_service_unittest.cc b/components/web_resource/web_resource_service_unittest.cc
index 2017e9aa1..6b7faed 100644
--- a/components/web_resource/web_resource_service_unittest.cc
+++ b/components/web_resource/web_resource_service_unittest.cc
@@ -87,7 +87,7 @@
                                [](network::NetworkConnectionTracker* tracker) {
                                  return tracker;
                                },
-                               network_connection_tracker)){};
+                               network_connection_tracker)) {}
 
   void Unpack(const base::DictionaryValue& parsed_json) override {}
 };
diff --git a/content/browser/child_process_launcher_browsertest.cc b/content/browser/child_process_launcher_browsertest.cc
index 293a49f4..2949aacb 100644
--- a/content/browser/child_process_launcher_browsertest.cc
+++ b/content/browser/child_process_launcher_browsertest.cc
@@ -27,11 +27,11 @@
       client_->OnProcessLaunchFailed(content::LAUNCH_RESULT_FAILURE);
     else
       client_->OnProcessLaunched();
-  };
+  }
 
   void OnProcessLaunchFailed(int error_code) override {
     client_->OnProcessLaunchFailed(error_code);
-  };
+  }
 
   content::ChildProcessLauncher::Client* client_;
   bool simulate_failure_;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 36b893e..a9252104 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2171,16 +2171,15 @@
       frame_tree_node()->frame_tree()->root()->current_origin());
   ScopedCommitStateResetter commit_state_resetter(this);
 
-  // If we're waiting for an unload ack from this frame and we receive a commit
-  // message, then the frame was navigating before it received the unload
-  // request.  It will either respond to the unload request soon or our timer
-  // will expire.  Either way, we should ignore this message, because we have
-  // already committed to destroying this RenderFrameHost.  Note that we
-  // intentionally do not ignore commits that happen while the current tab is
-  // being closed - see https://crbug.com/805705.
+  // When the frame is pending deletion, the browser is waiting for it to unload
+  // properly. In the meantime, because of race conditions, it might tries to
+  // commit a same-document navigation before unloading. Similarly to what is
+  // done with cross-document navigations, such navigation are ignored. The
+  // browser already committed to destroying this RenderFrameHost.
+  // See https://crbug.com/805705 and https://crbug.com/930132.
   // TODO(ahemery): Investigate to see if this can be removed when the
   // NavigationClient interface is implemented.
-  if (is_waiting_for_swapout_ack_)
+  if (!is_active())
     return;
 
   TRACE_EVENT2("navigation",
diff --git a/content/browser/loader/mock_resource_loader.cc b/content/browser/loader/mock_resource_loader.cc
index 066995d..a6e1719 100644
--- a/content/browser/loader/mock_resource_loader.cc
+++ b/content/browser/loader/mock_resource_loader.cc
@@ -116,7 +116,7 @@
   }
 
   return status_;
-};
+}
 
 MockResourceLoader::Status MockResourceLoader::OnReadCompleted(
     base::StringPiece bytes) {
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index 6af5d5d..45587bf 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -1420,7 +1420,7 @@
 
   url_loader_client_.RunUntilComplete();
   EXPECT_FALSE(url_loader_client_.completion_status().ssl_info);
-};
+}
 
 // Test that SSLInfo is attached to OnResponseComplete when there is the
 // kURLLoadOptionsSendSSLInfoForCertificateError option.
@@ -1438,7 +1438,7 @@
 
   url_loader_client_.RunUntilComplete();
   EXPECT_TRUE(url_loader_client_.completion_status().ssl_info);
-};
+}
 
 // Test that SSLInfo is not attached to OnResponseComplete when there is the
 // kURLLoadOptionsSendSSLInfoForCertificateError option and a minor SSL error.
@@ -1455,7 +1455,7 @@
             mock_loader_->OnResponseCompleted(net::URLRequestStatus()));
   url_loader_client_.RunUntilComplete();
   EXPECT_FALSE(url_loader_client_.completion_status().ssl_info);
-};
+}
 
 TEST_F(MojoAsyncResourceHandlerTest,
        TransferSizeUpdateCalledForNonBlockedResponse) {
diff --git a/content/browser/loader/test_resource_handler.h b/content/browser/loader/test_resource_handler.h
index d99196a1..21ea03c 100644
--- a/content/browser/loader/test_resource_handler.h
+++ b/content/browser/loader/test_resource_handler.h
@@ -145,7 +145,7 @@
 
   network::ResourceResponse* resource_response() {
     return resource_response_.get();
-  };
+  }
 
   const std::string& body() const { return body_; }
   net::URLRequestStatus final_status() const { return final_status_; }
diff --git a/content/browser/oop_browsertest.cc b/content/browser/oop_browsertest.cc
index afd053fc..83c7223 100644
--- a/content/browser/oop_browsertest.cc
+++ b/content/browser/oop_browsertest.cc
@@ -90,7 +90,7 @@
       ASSERT_EQ(snapshot.getColor(i, j), SK_ColorBLUE);
     }
   }
-};
+}
 #endif
 
 }  // namespace
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index a0096ef..44534b1 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -80,7 +80,7 @@
 
   UpdatePlayPauseButtonVisibility();
   window_->SetSkipAdButtonVisibility(media_session_action_skip_ad_handled_);
-  window_->Show();
+  window_->ShowInactive();
   initiator_->SetHasPictureInPictureVideo(true);
 
   return window_->GetBounds().size();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index dc734dc..3b46665 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -6649,7 +6649,7 @@
       public ui::InputMethodObserver {
  public:
   RenderWidgetHostViewAuraInputMethodTest() = default;
-  ~RenderWidgetHostViewAuraInputMethodTest() override{};
+  ~RenderWidgetHostViewAuraInputMethodTest() override {}
   void SetUp() override {
     input_method_ = new ui::MockInputMethod(nullptr);
     // transfers ownership.
diff --git a/content/browser/resources/net/network_errors_listing.html b/content/browser/resources/net/network_errors_listing.html
index ebc4bbb..f990b33 100644
--- a/content/browser/resources/net/network_errors_listing.html
+++ b/content/browser/resources/net/network_errors_listing.html
@@ -21,7 +21,5 @@
 <body>
   <h1>Network errors</h1>
   <div id="pages" class="list"></div>
-
-  <script src="chrome://resources/js/i18n_template.js"></script>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 26b9b6f..5f589a99 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -631,6 +631,21 @@
   DISALLOW_COPY_AND_ASSIGN(UpdateViewportIntersectionMessageFilter);
 };
 
+// Observes navigation start.
+class DidStartNavigationObserver : public WebContentsObserver {
+ public:
+  explicit DidStartNavigationObserver(WebContents* web_contents)
+      : WebContentsObserver(web_contents) {}
+  void DidStartNavigation(NavigationHandle* navigation_handle) override {
+    observed_ = true;
+  }
+  bool observed() { return observed_; }
+
+ private:
+  bool observed_ = false;
+  DISALLOW_COPY_AND_ASSIGN(DidStartNavigationObserver);
+};
+
 }  // namespace
 
 //
@@ -14064,6 +14079,36 @@
   EXPECT_TRUE(delete_c.deleted());
 }
 
+// A same document commit from the renderer process is received while the
+// RenderFrameHost is pending deletion.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       SameDocumentCommitWhilePendingDeletion) {
+  GURL url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  RenderFrameHostImpl* rfh_a = web_contents()->GetMainFrame();
+  RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
+
+  // Frame B has a unload handler. The browser process needs to wait before
+  // deleting it.
+  EXPECT_TRUE(ExecJs(rfh_b, "onunload=function(){}"));
+
+  RenderFrameDeletedObserver deleted_observer(rfh_b);
+  DidStartNavigationObserver did_start_navigation_observer(web_contents());
+
+  // Start a same-document navigation on B.
+  ExecuteScriptAsync(rfh_b, "location.href='#fragment'");
+
+  // Simulate A deleting B.
+  // It starts before receiving the same-document navigation. The detach ACK is
+  // received after.
+  rfh_b->DetachFromProxy();
+  deleted_observer.WaitUntilDeleted();
+
+  // The navigation was ignored.
+  EXPECT_FALSE(did_start_navigation_observer.observed());
+}
+
 // This test verifies that when scrolling an OOPIF in a pinched-zoomed page,
 // that the scroll-delta matches the distance between TouchStart/End as seen
 // by the oopif, i.e. the oopif content 'sticks' to the finger during scrolling.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 58b809a1a..5d505aa 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3267,7 +3267,7 @@
 
   bool IsActive() const override { return false; }
   void Close() override {}
-  void Show() override {}
+  void ShowInactive() override {}
   void Hide() override {}
   void SetPictureInPictureCustomControls(
       const std::vector<blink::PictureInPictureControlInfo>& controls)
diff --git a/content/public/browser/overlay_window.h b/content/public/browser/overlay_window.h
index 8eeeafd..2c33071 100644
--- a/content/public/browser/overlay_window.h
+++ b/content/public/browser/overlay_window.h
@@ -47,7 +47,7 @@
 
   virtual bool IsActive() const = 0;
   virtual void Close() = 0;
-  virtual void Show() = 0;
+  virtual void ShowInactive() = 0;
   virtual void Hide() = 0;
   virtual bool IsVisible() const = 0;
   virtual bool IsAlwaysOnTop() const = 0;
diff --git a/content/renderer/loader/navigation_body_loader.cc b/content/renderer/loader/navigation_body_loader.cc
index 16b063e..399a730 100644
--- a/content/renderer/loader/navigation_body_loader.cc
+++ b/content/renderer/loader/navigation_body_loader.cc
@@ -122,6 +122,11 @@
 
 void NavigationBodyLoader::OnReceiveCachedMetadata(
     const std::vector<uint8_t>& data) {
+  // Even if IsolatedCodeCaching is landed, this code is still used by
+  // ServiceWorker.
+  // TODO(horo, kinuko): Make a test to cover this function.
+  // TODO(https://crbug.com/930000): Add support for inline script code caching
+  // with the service worker service.
   client_->BodyCodeCacheReceived(data);
 }
 
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 6e674dd..0b5c55c 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -1019,7 +1019,7 @@
   service_manager::mojom::InterfaceProviderRequest
   interface_request_for_initial_empty_document() {
     return std::move(interface_request_for_initial_empty_document_);
-  };
+  }
 
   blink::mojom::DocumentInterfaceBrokerRequest
   document_interface_broker_request_for_initial_empty_document() {
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc
index 61cb65a..e0ee6a84 100644
--- a/content/shell/browser/web_test/web_test_content_browser_client.cc
+++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -65,7 +65,7 @@
 
   bool IsActive() const override { return false; }
   void Close() override {}
-  void Show() override {}
+  void ShowInactive() override {}
   void Hide() override {}
   void SetPictureInPictureCustomControls(
       const std::vector<blink::PictureInPictureControlInfo>& controls)
diff --git a/content/shell/test_runner/mock_spell_check.cc b/content/shell/test_runner/mock_spell_check.cc
index db07974..3b7c9e1 100644
--- a/content/shell/test_runner/mock_spell_check.cc
+++ b/content/shell/test_runner/mock_spell_check.cc
@@ -32,8 +32,8 @@
 MockSpellCheck::~MockSpellCheck() {}
 
 bool MockSpellCheck::SpellCheckWord(const blink::WebString& text,
-                                    int* misspelled_offset,
-                                    int* misspelled_length) {
+                                    size_t* misspelled_offset,
+                                    size_t* misspelled_length) {
   DCHECK(misspelled_offset);
   DCHECK(misspelled_length);
 
diff --git a/content/shell/test_runner/mock_spell_check.h b/content/shell/test_runner/mock_spell_check.h
index 160c638..6e361ba 100644
--- a/content/shell/test_runner/mock_spell_check.h
+++ b/content/shell/test_runner/mock_spell_check.h
@@ -38,8 +38,8 @@
   // For example, when the given text is "   zz zz", this function sets 3 to
   // misspelledOffset and 2 to misspelledLength, respectively.
   bool SpellCheckWord(const blink::WebString& text,
-                      int* misspelled_offset,
-                      int* misspelled_length);
+                      size_t* misspelled_offset,
+                      size_t* misspelled_length);
 
   // Checks whether the specified text can be spell checked immediately using
   // the spell checker cache.
diff --git a/content/shell/test_runner/spell_check_client.cc b/content/shell/test_runner/spell_check_client.cc
index 25857c99..effb4e8 100644
--- a/content/shell/test_runner/spell_check_client.cc
+++ b/content/shell/test_runner/spell_check_client.cc
@@ -50,8 +50,8 @@
 
 void SpellCheckClient::CheckSpelling(
     const blink::WebString& text,
-    int& misspelled_offset,
-    int& misspelled_length,
+    size_t& misspelled_offset,
+    size_t& misspelled_length,
     blink::WebVector<blink::WebString>* optional_suggestions) {
   if (!enabled_) {
     misspelled_offset = 0;
@@ -94,13 +94,13 @@
   if (!last_requested_text_checking_completion_)
     return;
   std::vector<blink::WebTextCheckingResult> results;
-  int offset = 0;
+  size_t offset = 0;
   if (!spell_check_.IsMultiWordMisspelling(last_requested_text_check_string_,
                                            &results)) {
     base::string16 text = last_requested_text_check_string_.Utf16();
     while (text.length()) {
-      int misspelled_position = 0;
-      int misspelled_length = 0;
+      size_t misspelled_position = 0;
+      size_t misspelled_length = 0;
       spell_check_.SpellCheckWord(blink::WebString::FromUTF16(text),
                                   &misspelled_position, &misspelled_length);
       if (!misspelled_length)
diff --git a/content/shell/test_runner/spell_check_client.h b/content/shell/test_runner/spell_check_client.h
index 1145cf3f5..53a9295 100644
--- a/content/shell/test_runner/spell_check_client.h
+++ b/content/shell/test_runner/spell_check_client.h
@@ -44,8 +44,8 @@
   bool IsSpellCheckingEnabled() const override;
   void CheckSpelling(
       const blink::WebString& text,
-      int& offset,
-      int& length,
+      size_t& offset,
+      size_t& length,
       blink::WebVector<blink::WebString>* optional_suggestions) override;
   void RequestCheckingOfText(
       const blink::WebString& text,
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 35276a8..392a9cd 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -190,7 +190,7 @@
         ['win', 'nvidia', 'opengl', 'passthrough'], bug=887578)
     self.Flaky('deqp/functional/gles3/transformfeedback/*',
         ['win', ('nvidia', 0x1cb3), 'opengl'], bug=822733)
-    self.Flaky('conformance2/textures/misc/' +
+    self.Fail('conformance2/textures/misc/' +
         'integer-cubemap-specification-order-bug.html',
         ['win', 'nvidia', 'opengl', 'passthrough'], bug=905003)
 
diff --git a/docs/security/mojo.md b/docs/security/mojo.md
index 8a373fc4..ead3ae9 100644
--- a/docs/security/mojo.md
+++ b/docs/security/mojo.md
@@ -5,7 +5,8 @@
 but can also add significant complexity. Below are some recommendation from
 Mojo and IPC reviewers for best practices.
 
-For questions, concerns, or suggestions, reach out to <mojo@chromium.org>.
+For questions, concerns, or suggestions, reach out to
+[chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo).
 
 > For legacy IPC, please see [security tips for IPC][security-tips-for-ipc].
 
diff --git a/gin/converter.cc b/gin/converter.cc
index ce40d59..bc95df4 100644
--- a/gin/converter.cc
+++ b/gin/converter.cc
@@ -151,6 +151,11 @@
   return true;
 }
 
+Local<Value> Converter<Local<Function>>::ToV8(Isolate* isolate,
+                                              Local<Function> val) {
+  return val.As<Value>();
+}
+
 bool Converter<Local<Function>>::FromV8(Isolate* isolate,
                                         Local<Value> val,
                                         Local<Function>* out) {
diff --git a/gin/converter.h b/gin/converter.h
index e4ef0a3..48be87c 100644
--- a/gin/converter.h
+++ b/gin/converter.h
@@ -121,6 +121,8 @@
 
 template<>
 struct GIN_EXPORT Converter<v8::Local<v8::Function> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                   v8::Local<v8::Function> val);
   static bool FromV8(v8::Isolate* isolate,
                      v8::Local<v8::Value> val,
                      v8::Local<v8::Function>* out);
diff --git a/google_apis/gaia/fake_oauth2_token_service_delegate.cc b/google_apis/gaia/fake_oauth2_token_service_delegate.cc
index 94c3ac7..58b8121 100644
--- a/google_apis/gaia/fake_oauth2_token_service_delegate.cc
+++ b/google_apis/gaia/fake_oauth2_token_service_delegate.cc
@@ -124,15 +124,15 @@
 void FakeOAuth2TokenServiceDelegate::UpdateAuthError(
     const std::string& account_id,
     const GoogleServiceAuthError& error) {
-  if (error.IsTransientError() || GetAuthError(account_id) == error)
-    return;
-
   // Drop transient errors to match OAuth2TokenService's stated contract for
   // GetAuthError() and to allow clients to test proper behavior in the case of
   // transient errors.
   if (error.IsTransientError())
     return;
 
+  if (GetAuthError(account_id) == error)
+    return;
+
   auto it = refresh_tokens_.find(account_id);
   DCHECK(it != refresh_tokens_.end());
   it->second->error = error;
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index c07584f..b984f6d 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -208,7 +208,14 @@
 HEADLESS_PROTOCOL_TEST(VirtualTimeBasics, "emulation/virtual-time-basics.js");
 HEADLESS_PROTOCOL_TEST(VirtualTimeInterrupt,
                        "emulation/virtual-time-interrupt.js");
-HEADLESS_PROTOCOL_TEST(VirtualTimeCrossProcessNavigation,
+#if defined(OS_LINUX)
+#define MAYBE_VirtualTimeCrossProcessNavigation \
+  DISABLED_VirtualTimeCrossProcessNavigation
+#else
+#define MAYBE_VirtualTimeCrossProcessNavigation \
+  VirtualTimeCrossProcessNavigation
+#endif
+HEADLESS_PROTOCOL_TEST(MAYBE_VirtualTimeCrossProcessNavigation,
                        "emulation/virtual-time-cross-process-navigation.js");
 HEADLESS_PROTOCOL_TEST(VirtualTimeDetachFrame,
                        "emulation/virtual-time-detach-frame.js");
diff --git a/ios/chrome/app/resources/omaha/omaha.html b/ios/chrome/app/resources/omaha/omaha.html
index 3f30fdf..0293d49a 100644
--- a/ios/chrome/app/resources/omaha/omaha.html
+++ b/ios/chrome/app/resources/omaha/omaha.html
@@ -1,10 +1,11 @@
 <!DOCTYPE HTML>
-<html i18n-values="dir:textdirection;">
+<html dir="$i18n{textdirection}">
 <head>
   <meta name="viewport"
     content="width=device-width, initial-scale=1, maximum-scale=1"/>
   <meta charset="utf-8"/>
   <title>Omaha</title>
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="omaha.css">
   <script src="chrome://resources/js/ios/web_ui.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
@@ -12,7 +13,7 @@
   <script src="chrome://omaha/omaha.js"></script>
   <script src="chrome://omaha/strings.js"></script>
 </head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+<body>
   <div id="outer">
     <table id="inner" cellpadding="0" cellspacing="0" border="0">
       <tr id="last_sent_time-tr">
@@ -53,6 +54,5 @@
       </tr>
     </table>
   </div>
-  <script src="chrome://resources/js/i18n_template.js"></script>
 </body>
 </html>
diff --git a/ios/chrome/browser/autofill/form_suggestion_label.mm b/ios/chrome/browser/autofill/form_suggestion_label.mm
index a4abaf4..a8f6cf9 100644
--- a/ios/chrome/browser/autofill/form_suggestion_label.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_label.mm
@@ -135,8 +135,8 @@
                                     base::SysNSStringToUTF16(suggestion.value),
                                     base::SysNSStringToUTF16(
                                         suggestion.displayDescription),
-                                    base::IntToString16(index + 1),
-                                    base::IntToString16(numSuggestions))];
+                                    base::NumberToString16(index + 1),
+                                    base::NumberToString16(numSuggestions))];
     [self
         setAccessibilityIdentifier:kFormSuggestionLabelAccessibilityIdentifier];
   }
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
index ab1d0aca5..b8d71347 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
@@ -321,10 +321,10 @@
 
     if (history_service) {
       base::RecordAction(base::UserMetricsAction("ClearBrowsingData_History"));
-      history_service->ExpireLocalAndRemoteHistoryBetween(
+      history_service->DeleteLocalAndRemoteHistoryBetween(
           ios::WebHistoryServiceFactory::GetForBrowserState(browser_state_),
-          std::set<GURL>(), delete_begin, delete_end, /*user_initiated*/ true,
-          CreatePendingTaskCompletionClosure(), &history_task_tracker_);
+          delete_begin, delete_end, CreatePendingTaskCompletionClosure(),
+          &history_task_tracker_);
     }
 
     // Need to clear the host cache and accumulated speculative data, as it also
diff --git a/ios/chrome/browser/notification_promo.cc b/ios/chrome/browser/notification_promo.cc
index 426b9e7..3917e0e 100644
--- a/ios/chrome/browser/notification_promo.cc
+++ b/ios/chrome/browser/notification_promo.cc
@@ -147,7 +147,7 @@
 
   base::DictionaryValue promo_dict;
   promo_dict.MergeDictionary(local_state_->GetDictionary(kPrefPromoObject));
-  promo_dict.Set(base::IntToString(promo_id), std::move(ntp_promo));
+  promo_dict.Set(base::NumberToString(promo_id), std::move(ntp_promo));
   local_state_->Set(kPrefPromoObject, promo_dict);
   DVLOG(1) << "WritePrefs " << promo_dict;
 }
@@ -163,7 +163,7 @@
     return;
 
   const base::DictionaryValue* ntp_promo = NULL;
-  promo_dict->GetDictionary(base::IntToString(promo_id_), &ntp_promo);
+  promo_dict->GetDictionary(base::NumberToString(promo_id_), &ntp_promo);
   if (!ntp_promo)
     return;
 
diff --git a/ios/chrome/browser/notification_promo_unittest.cc b/ios/chrome/browser/notification_promo_unittest.cc
index 59ca369c..4374924 100644
--- a/ios/chrome/browser/notification_promo_unittest.cc
+++ b/ios/chrome/browser/notification_promo_unittest.cc
@@ -95,9 +95,9 @@
     field_trial_params["start"] = start_param;
     field_trial_params["end"] = year_from_now_string;
     field_trial_params["promo_text"] = promo_text;
-    field_trial_params["max_views"] = base::IntToString(max_views);
-    field_trial_params["max_seconds"] = base::IntToString(max_seconds);
-    field_trial_params["promo_id"] = base::IntToString(promo_id);
+    field_trial_params["max_views"] = base::NumberToString(max_views);
+    field_trial_params["max_seconds"] = base::NumberToString(max_seconds);
+    field_trial_params["promo_id"] = base::NumberToString(promo_id);
     // Payload parameters.
     base::DictionaryValue* payload;
     test_json_->GetDictionary("payload", &payload);
diff --git a/ios/chrome/browser/signin/signin_browser_state_info_updater.h b/ios/chrome/browser/signin/signin_browser_state_info_updater.h
index af34bed..1dc1c1a 100644
--- a/ios/chrome/browser/signin/signin_browser_state_info_updater.h
+++ b/ios/chrome/browser/signin/signin_browser_state_info_updater.h
@@ -40,7 +40,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   identity::IdentityManager* identity_manager_ = nullptr;
   SigninErrorController* signin_error_controller_ = nullptr;
diff --git a/ios/chrome/browser/signin/signin_browser_state_info_updater.mm b/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
index 8149987c..9f9e1652 100644
--- a/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
+++ b/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
@@ -85,6 +85,6 @@
 }
 
 void SigninBrowserStateInfoUpdater::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   UpdateBrowserStateInfo();
 }
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
index 82c3390d..2421b22 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
@@ -18,7 +18,6 @@
 
 browser_sync::ProfileSyncService::InitParams
 CreateProfileSyncServiceParamsForTest(
-    std::unique_ptr<syncer::SyncClient> sync_client,
     ios::ChromeBrowserState* browser_state) {
   browser_sync::ProfileSyncService::InitParams init_params;
 
@@ -26,8 +25,7 @@
       IdentityManagerFactory::GetForBrowserState(browser_state);
   init_params.start_behavior = browser_sync::ProfileSyncService::MANUAL_START;
   init_params.sync_client =
-      sync_client ? std::move(sync_client)
-                  : std::make_unique<IOSChromeSyncClient>(browser_state);
+      std::make_unique<IOSChromeSyncClient>(browser_state);
   init_params.network_time_update_callback = base::DoNothing();
   init_params.url_loader_factory = browser_state->GetSharedURLLoaderFactory();
   init_params.debug_identifier = browser_state->GetDebugName();
@@ -39,5 +37,5 @@
     web::BrowserState* context) {
   return std::make_unique<browser_sync::ProfileSyncServiceMock>(
       CreateProfileSyncServiceParamsForTest(
-          nullptr, ios::ChromeBrowserState::FromBrowserState(context)));
+          ios::ChromeBrowserState::FromBrowserState(context)));
 }
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h
index 098ca117..c41e03a 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h
@@ -13,19 +13,13 @@
 class ChromeBrowserState;
 }
 
-namespace syncer {
-class SyncClient;
-}
-
 namespace web {
 class BrowserState;
 }
 
-// Helper method for constructing ProfileSyncService mocks. If |sync_client|
-// is null, a fresh one is created.
+// Helper method for constructing ProfileSyncService mocks.
 browser_sync::ProfileSyncService::InitParams
 CreateProfileSyncServiceParamsForTest(
-    std::unique_ptr<syncer::SyncClient> sync_client,
     ios::ChromeBrowserState* browser_state);
 
 // Helper routine to be used in conjunction with
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h
index b775aa24..9056c41 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
-#include "components/sync/driver/sync_client.h"
+#include "components/browser_sync/browser_sync_client.h"
 
 namespace autofill {
 class AutofillWebDataService;
@@ -25,16 +25,16 @@
 class PasswordStore;
 }
 
-namespace syncer {
-class SyncApiComponentFactory;
+namespace browser_sync {
+class ProfileSyncComponentsFactoryImpl;
 }
 
-class IOSChromeSyncClient : public syncer::SyncClient {
+class IOSChromeSyncClient : public browser_sync::BrowserSyncClient {
  public:
   explicit IOSChromeSyncClient(ios::ChromeBrowserState* browser_state);
   ~IOSChromeSyncClient() override;
 
-  // SyncClient implementation.
+  // BrowserSyncClient implementation.
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
   syncer::ModelTypeStoreService* GetModelTypeStoreService() override;
@@ -43,13 +43,12 @@
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
-  bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
   syncer::DataTypeController::TypeVector CreateDataTypeControllers(
       syncer::SyncService* sync_service) override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   invalidation::InvalidationService* GetInvalidationService() override;
-  BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
+  BookmarkUndoService* GetBookmarkUndoService() override;
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
@@ -59,14 +58,14 @@
       syncer::ModelSafeGroup group) override;
   syncer::SyncApiComponentFactory* GetSyncApiComponentFactory() override;
 
-  void SetSyncApiComponentFactoryForTesting(
-      std::unique_ptr<syncer::SyncApiComponentFactory> component_factory);
-
  private:
   ios::ChromeBrowserState* const browser_state_;
 
   // The sync api component factory in use by this client.
-  std::unique_ptr<syncer::SyncApiComponentFactory> component_factory_;
+  // TODO(crbug.com/915154): Revert to SyncApiComponentFactory once common
+  // controller creation is moved elsewhere.
+  std::unique_ptr<browser_sync::ProfileSyncComponentsFactoryImpl>
+      component_factory_;
 
   // Members that must be fetched on the UI thread but accessed on their
   // respective backend threads.
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index ff2a9e6..66d0efd 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -108,15 +108,12 @@
   password_store_ = IOSChromePasswordStoreFactory::GetForBrowserState(
       browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
 
-  // Component factory may already be set in tests.
-  if (!GetSyncApiComponentFactory()) {
-    component_factory_.reset(new browser_sync::ProfileSyncComponentsFactoryImpl(
-        this, ::GetChannel(), prefs::kSavingBrowserHistoryDisabled,
-        base::CreateSingleThreadTaskRunnerWithTraits({web::WebThread::UI}),
-        db_thread_, profile_web_data_service_, account_web_data_service_,
-        password_store_,
-        ios::BookmarkSyncServiceFactory::GetForBrowserState(browser_state_)));
-  }
+  component_factory_.reset(new browser_sync::ProfileSyncComponentsFactoryImpl(
+      this, ::GetChannel(), prefs::kSavingBrowserHistoryDisabled,
+      base::CreateSingleThreadTaskRunnerWithTraits({web::WebThread::UI}),
+      db_thread_, profile_web_data_service_, account_web_data_service_,
+      password_store_,
+      ios::BookmarkSyncServiceFactory::GetForBrowserState(browser_state_)));
 }
 
 IOSChromeSyncClient::~IOSChromeSyncClient() {}
@@ -163,11 +160,6 @@
   return SessionSyncServiceFactory::GetForBrowserState(browser_state_);
 }
 
-bool IOSChromeSyncClient::HasPasswordStore() {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  return password_store_ != nullptr;
-}
-
 autofill::PersonalDataManager* IOSChromeSyncClient::GetPersonalDataManager() {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
   return autofill::PersonalDataManagerFactory::GetForBrowserState(
@@ -188,9 +180,8 @@
       GetDisabledTypesFromCommandLine(), sync_service);
 }
 
-BookmarkUndoService* IOSChromeSyncClient::GetBookmarkUndoServiceIfExists() {
-  return ios::BookmarkUndoServiceFactory::GetForBrowserStateIfExists(
-      browser_state_);
+BookmarkUndoService* IOSChromeSyncClient::GetBookmarkUndoService() {
+  return ios::BookmarkUndoServiceFactory::GetForBrowserState(browser_state_);
 }
 
 invalidation::InvalidationService*
@@ -349,8 +340,3 @@
 IOSChromeSyncClient::GetSyncApiComponentFactory() {
   return component_factory_.get();
 }
-
-void IOSChromeSyncClient::SetSyncApiComponentFactoryForTesting(
-    std::unique_ptr<syncer::SyncApiComponentFactory> component_factory) {
-  component_factory_ = std::move(component_factory);
-}
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index cf3eb278..94771a4 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -43,7 +43,7 @@
  protected:
   // Returns the collection of default datatypes.
   std::vector<syncer::ModelType> DefaultDatatypes() {
-    static_assert(43 == syncer::MODEL_TYPE_COUNT,
+    static_assert(44 == syncer::MODEL_TYPE_COUNT,
                   "When adding a new type, you probably want to add it here as "
                   "well (assuming it is already enabled).");
 
@@ -63,6 +63,7 @@
     datatypes.push_back(syncer::PREFERENCES);
     datatypes.push_back(syncer::PRIORITY_PREFERENCES);
     datatypes.push_back(syncer::READING_LIST);
+    // TODO(crbug.com/919489) Add SECURITY_EVENTS data type once it is enabled.
     datatypes.push_back(syncer::SESSIONS);
     datatypes.push_back(syncer::PROXY_TABS);
     datatypes.push_back(syncer::TYPED_URLS);
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm
index 0873e3f..b873697 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm
@@ -108,7 +108,8 @@
 }
 
 // Called when the currently signed-in user for a user has been signed out.
-- (void)onPrimaryAccountCleared:(const AccountInfo&)previousPrimaryAccountInfo {
+- (void)onPrimaryAccountCleared:
+    (const CoreAccountInfo&)previousPrimaryAccountInfo {
   [self updateShouldShowSigninPromo];
 }
 
diff --git a/ios/chrome/browser/ui/find_bar/find_in_page_egtest.mm b/ios/chrome/browser/ui/find_bar/find_in_page_egtest.mm
index ce97c0f0..b504966 100644
--- a/ios/chrome/browser/ui/find_bar/find_in_page_egtest.mm
+++ b/ios/chrome/browser/ui/find_bar/find_in_page_egtest.mm
@@ -191,8 +191,8 @@
                         outOfTotal:(int)resultCount {
   // Returns "<current> of <total>" search results label (e.g "1 of 5").
   NSString* expectedResultsString = l10n_util::GetNSStringF(
-      IDS_FIND_IN_PAGE_COUNT, base::IntToString16(resultIndex),
-      base::IntToString16(resultCount));
+      IDS_FIND_IN_PAGE_COUNT, base::NumberToString16(resultIndex),
+      base::NumberToString16(resultCount));
 
   ConditionBlock condition = ^{
     NSError* error = nil;
diff --git a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h
index ffa00a47..56e96a1 100644
--- a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h
+++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h
@@ -38,7 +38,7 @@
   ~SyncedSessionsObserverBridge() override;
   // identity::IdentityManager::Observer implementation.
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
   // Returns true if user is signed in.
   bool IsSignedIn();
diff --git a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm
index 7fdc457f..04c3b04 100644
--- a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm
+++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm
@@ -42,7 +42,7 @@
 #pragma mark - identity::IdentityManager::Observer
 
 void SyncedSessionsObserverBridge::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   [owner_ reloadSessions];
 }
 
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
index 7649b6d..c9330fc 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
@@ -625,7 +625,8 @@
   [self updateIdentitySectionAndNotifyConsumer];
 }
 
-- (void)onPrimaryAccountCleared:(const AccountInfo&)previousPrimaryAccountInfo {
+- (void)onPrimaryAccountCleared:
+    (const CoreAccountInfo&)previousPrimaryAccountInfo {
   [self updateSyncSection:YES];
   [self updateIdentitySectionAndNotifyConsumer];
 }
diff --git a/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm b/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
index ef28860..d336f189 100644
--- a/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
+++ b/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
@@ -51,7 +51,7 @@
     web::BrowserState* context) {
   browser_sync::ProfileSyncService::InitParams init_params =
       CreateProfileSyncServiceParamsForTest(
-          nullptr, ios::ChromeBrowserState::FromBrowserState(context));
+          ios::ChromeBrowserState::FromBrowserState(context));
   return std::make_unique<NiceMock<browser_sync::ProfileSyncServiceMock>>(
       std::move(init_params));
 }
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index e97f9a24..08d7989 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -156,7 +156,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
 
  private:
   __weak SettingsTableViewController* owner_;
@@ -181,7 +181,7 @@
 }
 
 void IdentityObserverBridge::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   [owner_ onSignInStateChanged];
 }
 
diff --git a/ios/chrome/browser/ui/settings/sync/sync_encryption_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/sync/sync_encryption_table_view_controller_unittest.mm
index e8bcd9e..c3221e1 100644
--- a/ios/chrome/browser/ui/settings/sync/sync_encryption_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/sync/sync_encryption_table_view_controller_unittest.mm
@@ -35,7 +35,7 @@
     web::BrowserState* context) {
   browser_sync::ProfileSyncService::InitParams init_params =
       CreateProfileSyncServiceParamsForTest(
-          nullptr, ios::ChromeBrowserState::FromBrowserState(context));
+          ios::ChromeBrowserState::FromBrowserState(context));
   return std::make_unique<NiceMock<browser_sync::ProfileSyncServiceMock>>(
       std::move(init_params));
 }
diff --git a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
index 757615e..0bf49e8 100644
--- a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
@@ -124,7 +124,7 @@
       web::BrowserState* context) {
     browser_sync::ProfileSyncService::InitParams init_params =
         CreateProfileSyncServiceParamsForTest(
-            nullptr, ios::ChromeBrowserState::FromBrowserState(context));
+            ios::ChromeBrowserState::FromBrowserState(context));
     return std::make_unique<NiceMock<browser_sync::ProfileSyncServiceMock>>(
         std::move(init_params));
   }
diff --git a/ios/chrome/browser/ui/webui/about_ui.cc b/ios/chrome/browser/ui/webui/about_ui.cc
index ea4edf8..b070b3f 100644
--- a/ios/chrome/browser/ui/webui/about_ui.cc
+++ b/ios/chrome/browser/ui/webui/about_ui.cc
@@ -68,7 +68,7 @@
   output->append("<meta charset='utf-8'>\n");
   if (refresh > 0) {
     output->append("<meta http-equiv='refresh' content='");
-    output->append(base::IntToString(refresh));
+    output->append(base::NumberToString(refresh));
     output->append("'/>\n");
   }
 }
diff --git a/ios/chrome/browser/ui/webui/version_ui.mm b/ios/chrome/browser/ui/webui/version_ui.mm
index 695802f..4a6c4e6 100644
--- a/ios/chrome/browser/ui/webui/version_ui.mm
+++ b/ios/chrome/browser/ui/webui/version_ui.mm
@@ -55,7 +55,7 @@
   html_source->AddString(
       version_ui::kCopyright,
       l10n_util::GetStringFUTF16(IDS_IOS_ABOUT_VERSION_COPYRIGHT,
-                                 base::IntToString16(exploded_time.year)));
+                                 base::NumberToString16(exploded_time.year)));
   html_source->AddLocalizedString(version_ui::kRevision,
                                   IDS_VERSION_UI_REVISION);
   std::string last_change = version_info::GetLastChange();
diff --git a/ios/web/navigation/history_state_operations_inttest.mm b/ios/web/navigation/history_state_operations_inttest.mm
index 4766184..3aa0f331 100644
--- a/ios/web/navigation/history_state_operations_inttest.mm
+++ b/ios/web/navigation/history_state_operations_inttest.mm
@@ -219,7 +219,7 @@
   // occurred as the result of the pushState() call.
   std::string empty_state;
   std::string empty_title;
-  std::string new_port_string = base::IntToString(
+  std::string new_port_string = base::NumberToString(
       web::test::HttpServer::GetSharedInstance().GetPort() + 1);
   url::Replacements<char> port_replacement;
   port_replacement.SetPort(new_port_string.c_str(),
@@ -241,7 +241,7 @@
   // occurred as the result of the pushState() call.
   std::string empty_state;
   std::string empty_title;
-  std::string new_port_string = base::IntToString(
+  std::string new_port_string = base::NumberToString(
       web::test::HttpServer::GetSharedInstance().GetPort() + 1);
   url::Replacements<char> port_replacement;
   port_replacement.SetPort(new_port_string.c_str(),
diff --git a/ios/web/shell/test/page_state_egtest.mm b/ios/web/shell/test/page_state_egtest.mm
index 3ddeddb..362960c 100644
--- a/ios/web/shell/test/page_state_egtest.mm
+++ b/ios/web/shell/test/page_state_egtest.mm
@@ -122,7 +122,7 @@
         performAction:grey_scrollInDirection(kGREYDirectionDown, offset)];
     // Add a query parameter so the next load creates another NavigationItem.
     GURL::Replacements replacements;
-    replacements.SetQueryStr(base::IntToString(i));
+    replacements.SetQueryStr(base::NumberToString(i));
     [ShellEarlGrey loadURL:baseURL.ReplaceComponents(replacements)];
     // Wait for the content offset to be set to {0, 0}.
     WaitForOffset(0.0);
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm
index 772f210..8e2df8d 100644
--- a/ios/web/webui/mojo_facade.mm
+++ b/ios/web/webui/mojo_facade.mm
@@ -173,7 +173,7 @@
   std::vector<uint8_t> bytes(buffer->size());
   for (size_t i = 0; i < buffer->size(); i++) {
     int one_byte = 0;
-    buffer->GetInteger(base::IntToString(i), &one_byte);
+    buffer->GetInteger(base::NumberToString(i), &one_byte);
     bytes[i] = one_byte;
   }
 
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
index cd09325..b89cab3 100644
--- a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
+++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -12,8 +12,8 @@
 #include "base/files/file_path.h"
 #include "base/test/bind_test_util.h"
 #include "components/browser_sync/profile_sync_service_mock.h"
+#include "components/browser_sync/profile_sync_test_util.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/device_id_helper.h"
 #include "components/signin/core/browser/fake_account_fetcher_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
 #include "components/signin/core/browser/fake_signin_manager.h"
@@ -22,13 +22,7 @@
 #include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h"
 #include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
 #include "components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h"
-#include "components/sync/device_info/device_info_sync_service_impl.h"
-#include "components/sync/device_info/local_device_info_provider_impl.h"
-#include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/driver/sync_service_observer.h"
-#include "components/sync/model/test_model_type_store_service.h"
-#include "components/version_info/version_info.h"
-#include "components/version_info/version_string.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
@@ -55,31 +49,6 @@
 using testing::Invoke;
 using testing::Return;
 
-// TODO(crbug.com/922971): Hopefully this class is not needed when
-// ProfileSyncService doesn't have a direct dependency to DeviceInfoSyncService.
-class TestSyncClient : public syncer::FakeSyncClient {
- public:
-  TestSyncClient()
-      : device_info_sync_service_(
-            model_type_store_service_.GetStoreFactory(),
-            std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
-                version_info::Channel::UNKNOWN,
-                /*version=*/"",
-                /*is_tablet=*/false,
-                /*signin_scoped_device_id_callback=*/
-                base::BindLambdaForTesting([]() { return std::string(); }))) {}
-
-  ~TestSyncClient() override = default;
-
-  syncer::DeviceInfoSyncService* GetDeviceInfoSyncService() override {
-    return &device_info_sync_service_;
-  }
-
- private:
-  syncer::TestModelTypeStoreService model_type_store_service_;
-  syncer::DeviceInfoSyncServiceImpl device_info_sync_service_;
-};
-
 }  // namespace
 
 class CWVSyncControllerTest : public PlatformTest {
@@ -111,9 +80,11 @@
 
     browser_sync::ProfileSyncService::InitParams init_params;
     init_params.start_behavior = browser_sync::ProfileSyncService::MANUAL_START;
-    init_params.sync_client = std::make_unique<TestSyncClient>();
+    init_params.sync_client =
+        profile_sync_service_bundle_.CreateSyncClientMock();
     init_params.url_loader_factory = browser_state_.GetSharedURLLoaderFactory();
     init_params.network_time_update_callback = base::DoNothing();
+    init_params.identity_manager = identity_test_env_.identity_manager();
     profile_sync_service_ =
         std::make_unique<browser_sync::ProfileSyncServiceMock>(
             std::move(init_params));
@@ -154,7 +125,7 @@
   web::TestWebThreadBundle web_thread_bundle_;
   ios_web_view::WebViewBrowserState browser_state_;
   web::TestWebState web_state_;
-  std::unique_ptr<browser_sync::ProfileSyncServiceMock> profile_sync_service_;
+  browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_;
   AccountTrackerService account_tracker_service_;
   FakeAccountFetcherService account_fetcher_service_;
   TestSigninClient signin_client_;
@@ -168,6 +139,7 @@
   FakeSigninManager signin_manager_;
   identity::IdentityTestEnvironment identity_test_env_;
   SigninErrorController signin_error_controller_;
+  std::unique_ptr<browser_sync::ProfileSyncServiceMock> profile_sync_service_;
   CWVSyncController* sync_controller_;
   syncer::SyncServiceObserver* sync_service_observer_;
 };
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h
index fd60417..f106829 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.h
+++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -5,21 +5,26 @@
 #ifndef IOS_WEB_VIEW_INTERNAL_SYNC_WEB_VIEW_SYNC_CLIENT_H_
 #define IOS_WEB_VIEW_INTERNAL_SYNC_WEB_VIEW_SYNC_CLIENT_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
-#include "components/sync/driver/sync_client.h"
+#include "components/browser_sync/browser_sync_client.h"
 
 namespace autofill {
 class AutofillWebDataService;
 }  // namespace autofill
 
+namespace browser_sync {
+class ProfileSyncComponentsFactoryImpl;
+}  // namespace browser_sync
+
 namespace password_manager {
 class PasswordStore;
 }  // namespace password_manager
 
 namespace syncer {
-class SyncApiComponentFactory;
 class SyncService;
 }  // namespace syncer
 
@@ -27,12 +32,12 @@
 
 class WebViewBrowserState;
 
-class WebViewSyncClient : public syncer::SyncClient {
+class WebViewSyncClient : public browser_sync::BrowserSyncClient {
  public:
-  WebViewSyncClient(WebViewBrowserState* browser_state);
+  explicit WebViewSyncClient(WebViewBrowserState* browser_state);
   ~WebViewSyncClient() override;
 
-  // SyncClient implementation.
+  // BrowserSyncClient implementation.
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
   syncer::ModelTypeStoreService* GetModelTypeStoreService() override;
@@ -41,13 +46,12 @@
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
-  bool HasPasswordStore() override;
   base::RepeatingClosure GetPasswordStateChangedCallback() override;
   syncer::DataTypeController::TypeVector CreateDataTypeControllers(
       syncer::SyncService* sync_service) override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   invalidation::InvalidationService* GetInvalidationService() override;
-  BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
+  BookmarkUndoService* GetBookmarkUndoService() override;
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
@@ -63,7 +67,10 @@
   scoped_refptr<autofill::AutofillWebDataService> account_web_data_service_;
   scoped_refptr<password_manager::PasswordStore> password_store_;
 
-  std::unique_ptr<syncer::SyncApiComponentFactory> component_factory_;
+  // TODO(crbug.com/915154): Revert to SyncApiComponentFactory once common
+  // controller creation is moved elsewhere.
+  std::unique_ptr<browser_sync::ProfileSyncComponentsFactoryImpl>
+      component_factory_;
   scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewSyncClient);
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 01f58b5..35c88a3 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -126,10 +126,6 @@
   return nullptr;
 }
 
-bool WebViewSyncClient::HasPasswordStore() {
-  return true;
-}
-
 autofill::PersonalDataManager* WebViewSyncClient::GetPersonalDataManager() {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
   return WebViewPersonalDataManagerFactory::GetForBrowserState(browser_state_);
@@ -156,7 +152,7 @@
   return type_vector;
 }
 
-BookmarkUndoService* WebViewSyncClient::GetBookmarkUndoServiceIfExists() {
+BookmarkUndoService* WebViewSyncClient::GetBookmarkUndoService() {
   return nullptr;
 }
 
diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc
index a29616a2..35ba08bc 100644
--- a/media/base/audio_renderer_mixer_unittest.cc
+++ b/media/base/audio_renderer_mixer_unittest.cc
@@ -97,7 +97,7 @@
                                const OutputDeviceInfo& sink_info,
                                scoped_refptr<AudioRendererSink> sink) final {
     return mixer_.get();
-  };
+  }
 
   void ReturnMixer(AudioRendererMixer* mixer) override {
     EXPECT_EQ(mixer_.get(), mixer);
diff --git a/mojo/core/trap_unittest.cc b/mojo/core/trap_unittest.cc
index 555726f4..309e5476 100644
--- a/mojo/core/trap_unittest.cc
+++ b/mojo/core/trap_unittest.cc
@@ -511,7 +511,7 @@
   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-};
+}
 
 TEST_F(TrapTest, CloseWatchedDataPipeConsumerHandle) {
   constexpr size_t kTestPipeCapacity = 8;
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 9ef4825e..29ba2544 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -3202,6 +3202,7 @@
     "third_party/quic/core/quic_trace_visitor.h",
     "third_party/quic/platform/api/quic_expect_bug.h",
     "third_party/quic/platform/api/quic_mock_log.h",
+    "third_party/quic/platform/api/quic_port_utils.h",
     "third_party/quic/platform/api/quic_test.h",
     "third_party/quic/platform/api/quic_test_loopback.cc",
     "third_party/quic/platform/api/quic_test_loopback.h",
@@ -3209,6 +3210,8 @@
     "third_party/quic/platform/api/quic_test_output.h",
     "third_party/quic/platform/impl/quic_expect_bug_impl.h",
     "third_party/quic/platform/impl/quic_mock_log_impl.h",
+    "third_party/quic/platform/impl/quic_port_utils_impl.cc",
+    "third_party/quic/platform/impl/quic_port_utils_impl.h",
     "third_party/quic/platform/impl/quic_test_impl.cc",
     "third_party/quic/platform/impl/quic_test_impl.h",
     "third_party/quic/platform/impl/quic_test_loopback_impl.cc",
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 27c576e..ef5fe194 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -32,6 +32,7 @@
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "net/base/address_list.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_address.h"
@@ -1446,7 +1447,15 @@
   proc_->SignalMultiple(requests_.size());
 }
 
-TEST_F(HostResolverImplTest, DeleteWithinAbortedCallback_ResolveHost) {
+// Flaky on Fuchsia and Linux ASAN. crbug.com/930483
+#if defined(OS_FUCHSIA) || defined(OS_LINUX)
+#define MAYBE_DeleteWithinAbortedCallback_ResolveHost \
+  DISABLED_DeleteWithinAbortedCallback_ResolveHost
+#else
+#define MAYBE_DeleteWithinAbortedCallback_ResolveHost \
+  DeleteWithinAbortedCallback_ResolveHost
+#endif
+TEST_F(HostResolverImplTest, MAYBE_DeleteWithinAbortedCallback_ResolveHost) {
   std::vector<std::unique_ptr<ResolveHostResponseHelper>> responses;
   ResolveHostResponseHelper::Callback custom_callback =
       base::BindLambdaForTesting(
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index ad94984..216a2a2 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -656,7 +656,12 @@
                     base::Bind(&NetLogQuicStreamFrameCallback, frame));
 }
 
-void QuicConnectionLogger::OnAckFrame(const quic::QuicAckFrame& frame) {
+void QuicConnectionLogger::OnIncomingAck(
+    const quic::QuicAckFrame& frame,
+    quic::QuicTime ack_receive_time,
+    quic::QuicPacketNumber largest_observed,
+    bool rtt_updated,
+    quic::QuicPacketNumber least_unacked_sent_packet) {
   const size_t kApproximateLargestSoloAckBytes = 100;
   if (last_received_packet_number_ - first_received_packet_number_ <
           received_acks_.size() &&
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 085f4d91..4eada91 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -50,6 +50,11 @@
                     quic::QuicPacketNumber original_packet_number,
                     quic::TransmissionType transmission_type,
                     quic::QuicTime sent_time) override;
+  void OnIncomingAck(const quic::QuicAckFrame& frame,
+                     quic::QuicTime ack_receive_time,
+                     quic::QuicPacketNumber largest_observed,
+                     bool rtt_updated,
+                     quic::QuicPacketNumber least_unacked_sent_packet) override;
   void OnPacketLoss(quic::QuicPacketNumber lost_packet_number,
                     quic::TransmissionType transmission_type,
                     quic::QuicTime detection_time) override;
@@ -64,7 +69,6 @@
   void OnProtocolVersionMismatch(quic::ParsedQuicVersion version) override;
   void OnPacketHeader(const quic::QuicPacketHeader& header) override;
   void OnStreamFrame(const quic::QuicStreamFrame& frame) override;
-  void OnAckFrame(const quic::QuicAckFrame& frame) override;
   void OnStopWaitingFrame(const quic::QuicStopWaitingFrame& frame) override;
   void OnRstStreamFrame(const quic::QuicRstStreamFrame& frame) override;
   void OnConnectionCloseFrame(
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 427d199d..54346405 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -220,8 +220,8 @@
           FLAGS_quic_restart_flag_quic_no_server_conn_ver_negotiation2,
           false)
 
-// If true, enable QUIC version 46 which adds CRYPTO frames.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_46, false)
+// If true, enable QUIC version 46.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_46, true)
 
 // When true, cache that encryption has been established to save CPU.
 QUIC_FLAG(bool,
@@ -354,5 +354,5 @@
     FLAGS_quic_reloadable_flag_quic_clear_probing_mark_after_packet_processing,
     true)
 
-// If true, enable QUIC version 47.
+// If true, enable QUIC version 47 which adds CRYPTO frames.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_47, false)
diff --git a/net/third_party/quic/core/http/end_to_end_test.cc b/net/third_party/quic/core/http/end_to_end_test.cc
index 36a16948..8dcc7ef 100644
--- a/net/third_party/quic/core/http/end_to_end_test.cc
+++ b/net/third_party/quic/core/http/end_to_end_test.cc
@@ -24,6 +24,7 @@
 #include "net/third_party/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quic/platform/api/quic_flags.h"
 #include "net/third_party/quic/platform/api/quic_logging.h"
+#include "net/third_party/quic/platform/api/quic_port_utils.h"
 #include "net/third_party/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quic/platform/api/quic_sleep.h"
 #include "net/third_party/quic/platform/api/quic_socket_address.h"
@@ -271,7 +272,8 @@
   EndToEndTest()
       : initialized_(false),
         connect_to_server_on_initialize_(true),
-        server_address_(QuicSocketAddress(TestLoopback(), 0)),
+        server_address_(
+            QuicSocketAddress(TestLoopback(), QuicPickUnusedPortOrDie())),
         server_hostname_("test.example.com"),
         client_writer_(nullptr),
         server_writer_(nullptr),
@@ -311,10 +313,7 @@
     AddToCache("/bar", 200, kBarResponseBody);
   }
 
-  ~EndToEndTest() override {
-    // TODO(rtenneti): port RecycleUnusedPort if needed.
-    // RecycleUnusedPort(server_address_.port());
-  }
+  ~EndToEndTest() override { QuicRecyclePort(server_address_.port()); }
 
   virtual void CreateClientWithWriter() {
     client_.reset(CreateQuicClient(client_writer_));
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h
index 4244526..bf57bf0 100644
--- a/net/third_party/quic/core/quic_connection.h
+++ b/net/third_party/quic/core/quic_connection.h
@@ -231,9 +231,6 @@
   // Called when a StreamFrame has been parsed.
   virtual void OnStreamFrame(const QuicStreamFrame& frame) {}
 
-  // Called when a AckFrame has been parsed.
-  virtual void OnAckFrame(const QuicAckFrame& frame) {}
-
   // Called when a StopWaitingFrame has been parsed.
   virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {}
 
diff --git a/net/third_party/quic/platform/api/quic_port_utils.h b/net/third_party/quic/platform/api/quic_port_utils.h
new file mode 100644
index 0000000..b633e38
--- /dev/null
+++ b/net/third_party/quic/platform/api/quic_port_utils.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
+#define NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
+
+#include "net/third_party/quic/platform/impl/quic_port_utils_impl.h"
+
+namespace quic {
+
+// Returns a UDP port that is currently unused.  Check-fails if none are
+// available.
+inline int QuicPickUnusedPortOrDie() {
+  return QuicPickUnusedPortOrDieImpl();
+}
+
+// Indicates that a specified port previously returned by
+// QuicPickUnusedPortOrDie is no longer used.
+inline void QuicRecyclePort(int port) {
+  return QuicRecyclePortImpl(port);
+}
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
diff --git a/net/third_party/quic/platform/impl/quic_port_utils_impl.cc b/net/third_party/quic/platform/impl/quic_port_utils_impl.cc
new file mode 100644
index 0000000..416031a
--- /dev/null
+++ b/net/third_party/quic/platform/impl/quic_port_utils_impl.cc
@@ -0,0 +1,13 @@
+#include "net/third_party/quic/platform/impl/quic_port_utils_impl.h"
+
+#include "net/third_party/quic/core/crypto/quic_random.h"
+
+namespace quic {
+
+int QuicPickUnusedPortOrDieImpl() {
+  return 12345 + (QuicRandom::GetInstance()->RandUint64() % 20000);
+}
+
+void QuicRecyclePortImpl(int port) {}
+
+}  // namespace quic
diff --git a/net/third_party/quic/platform/impl/quic_port_utils_impl.h b/net/third_party/quic/platform/impl/quic_port_utils_impl.h
new file mode 100644
index 0000000..e19da4f
--- /dev/null
+++ b/net/third_party/quic/platform/impl/quic_port_utils_impl.h
@@ -0,0 +1,11 @@
+#ifndef NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_PORT_UTILS_IMPL_H_
+#define NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_PORT_UTILS_IMPL_H_
+
+namespace quic {
+
+int QuicPickUnusedPortOrDieImpl();
+void QuicRecyclePortImpl(int port);
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_PORT_UTILS_IMPL_H_
diff --git a/net/third_party/quic/test_tools/quic_test_utils.h b/net/third_party/quic/test_tools/quic_test_utils.h
index f48168c..aa92bfe48 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.h
+++ b/net/third_party/quic/test_tools/quic_test_utils.h
@@ -1008,8 +1008,6 @@
 
   MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&));
 
-  MOCK_METHOD1(OnAckFrame, void(const QuicAckFrame& frame));
-
   MOCK_METHOD1(OnStopWaitingFrame, void(const QuicStopWaitingFrame&));
 
   MOCK_METHOD1(OnRstStreamFrame, void(const QuicRstStreamFrame&));
diff --git a/net/third_party/quic/tools/quic_client_test.cc b/net/third_party/quic/tools/quic_client_test.cc
index b146ca4..600a6ad 100644
--- a/net/third_party/quic/tools/quic_client_test.cc
+++ b/net/third_party/quic/tools/quic_client_test.cc
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "net/third_party/quic/platform/api/quic_epoll.h"
+#include "net/third_party/quic/platform/api/quic_port_utils.h"
 #include "net/third_party/quic/platform/api/quic_string_piece.h"
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/platform/api/quic_test_loopback.h"
@@ -79,7 +80,7 @@
   const int kNumClients = 50;
   for (int i = 0; i < kNumClients; ++i) {
     std::unique_ptr<QuicClient> client(
-        CreateAndInitializeQuicClient(&eps, kTestPort + i));
+        CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()));
 
     // Initializing the client will create a new FD.
     EXPECT_LT(number_of_open_fds, NumOpenSocketFDs());
@@ -94,7 +95,7 @@
   size_t number_of_open_fds = NumOpenSocketFDs();
 
   std::unique_ptr<QuicClient> client(
-      CreateAndInitializeQuicClient(&eps, kTestPort));
+      CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()));
   EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
   // Create more UDP sockets.
   EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
diff --git a/net/third_party/quic/tools/quic_server_test.cc b/net/third_party/quic/tools/quic_server_test.cc
index 5d8908b..603248b 100644
--- a/net/third_party/quic/tools/quic_server_test.cc
+++ b/net/third_party/quic/tools/quic_server_test.cc
@@ -12,6 +12,7 @@
 #include "net/third_party/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quic/platform/api/quic_flags.h"
 #include "net/third_party/quic/platform/api/quic_logging.h"
+#include "net/third_party/quic/platform/api/quic_port_utils.h"
 #include "net/third_party/quic/platform/api/quic_socket_address.h"
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/platform/api/quic_test_loopback.h"
@@ -85,7 +86,8 @@
 class QuicServerEpollInTest : public QuicTest {
  public:
   QuicServerEpollInTest()
-      : port_(kTestPort), server_address_(QuicIpAddress::Loopback4(), port_) {}
+      : port_(QuicPickUnusedPortOrDie()),
+        server_address_(TestLoopback(), port_) {}
 
   void StartListening() {
     server_.CreateUDPSocketAndListen(server_address_);
diff --git a/pdf/pdfium/pdfium_print.cc b/pdf/pdfium/pdfium_print.cc
index c3961e3..93ed2c3 100644
--- a/pdf/pdfium/pdfium_print.cc
+++ b/pdf/pdfium/pdfium_print.cc
@@ -232,10 +232,10 @@
     if (!page_number_str.empty())
       page_number_str.push_back(',');
     const PP_PrintPageNumberRange_Dev& range = page_ranges[i];
-    page_number_str.append(base::UintToString(range.first_page_number + 1));
+    page_number_str.append(base::NumberToString(range.first_page_number + 1));
     if (range.first_page_number != range.last_page_number) {
       page_number_str.push_back('-');
-      page_number_str.append(base::UintToString(range.last_page_number + 1));
+      page_number_str.append(base::NumberToString(range.last_page_number + 1));
     }
   }
   return page_number_str;
diff --git a/remoting/base/buffered_socket_writer_unittest.cc b/remoting/base/buffered_socket_writer_unittest.cc
index f57188f..b252ea9 100644
--- a/remoting/base/buffered_socket_writer_unittest.cc
+++ b/remoting/base/buffered_socket_writer_unittest.cc
@@ -120,7 +120,7 @@
     writer_->Start(base::Bind(&WriteNetSocket, socket_.get()),
                    base::Bind(&BufferedSocketWriterTest::OnWriteFailed,
                               base::Unretained(this)));
-  };
+  }
 
   void OnWriteFailed(int error) {
     write_error_ = error;
diff --git a/remoting/base/chromoting_event_log_writer.h b/remoting/base/chromoting_event_log_writer.h
index edb2ee54..6fe0f89 100644
--- a/remoting/base/chromoting_event_log_writer.h
+++ b/remoting/base/chromoting_event_log_writer.h
@@ -11,7 +11,7 @@
 
 class ChromotingEventLogWriter {
  public:
-  virtual ~ChromotingEventLogWriter(){};
+  virtual ~ChromotingEventLogWriter() {}
 
   virtual void Log(const ChromotingEvent& entry) = 0;
 };
diff --git a/remoting/host/backoff_timer.cc b/remoting/host/backoff_timer.cc
index 4965d7d..a7dd3d3 100644
--- a/remoting/host/backoff_timer.cc
+++ b/remoting/host/backoff_timer.cc
@@ -32,7 +32,7 @@
   timer_->Stop();
   user_task_.Reset();
   backoff_entry_.reset();
-};
+}
 
 void BackoffTimer::SetTimerForTest(std::unique_ptr<base::OneShotTimer> timer) {
   timer_ = std::move(timer);
diff --git a/remoting/host/desktop_display_info.h b/remoting/host/desktop_display_info.h
index 8f00da5..d5cf5f9 100644
--- a/remoting/host/desktop_display_info.h
+++ b/remoting/host/desktop_display_info.h
@@ -46,7 +46,7 @@
   bool operator==(const DesktopDisplayInfo& other);
   bool operator!=(const DesktopDisplayInfo& other);
 
-  const std::vector<DisplayGeometry>& displays() const { return displays_; };
+  const std::vector<DisplayGeometry>& displays() const { return displays_; }
 
  private:
   std::vector<DisplayGeometry> displays_;
diff --git a/remoting/host/file_transfer/fake_file_operations.cc b/remoting/host/file_transfer/fake_file_operations.cc
index 26b442b2..58d688d 100644
--- a/remoting/host/file_transfer/fake_file_operations.cc
+++ b/remoting/host/file_transfer/fake_file_operations.cc
@@ -77,7 +77,7 @@
 
 FakeFileOperations::FakeFileWriter::~FakeFileWriter() {
   Cancel();
-};
+}
 
 void FakeFileOperations::FakeFileWriter::WriteChunk(std::string data,
                                                     Callback callback) {
diff --git a/remoting/host/host_status_monitor.h b/remoting/host/host_status_monitor.h
index a388ee6..f73a039b 100644
--- a/remoting/host/host_status_monitor.h
+++ b/remoting/host/host_status_monitor.h
@@ -23,7 +23,7 @@
 
   const base::ObserverList<HostStatusObserver>::Unchecked& observers() {
     return observers_;
-  };
+  }
 
  protected:
   friend class base::RefCountedThreadSafe<HostStatusMonitor>;
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 9fa650b..bc54071 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -345,7 +345,7 @@
 
   incoming_message_callback_.Run(iq);
   SendMessageToClient(std::move(response));
-};
+}
 
 void It2MeNativeMessagingHost::SendOutgoingIq(const std::string& iq) {
   std::unique_ptr<base::DictionaryValue> message(new base::DictionaryValue());
diff --git a/remoting/host/policy_watcher_unittest.cc b/remoting/host/policy_watcher_unittest.cc
index e4dd7a4..52a3135 100644
--- a/remoting/host/policy_watcher_unittest.cc
+++ b/remoting/host/policy_watcher_unittest.cc
@@ -46,7 +46,6 @@
 class MockPolicyCallback {
  public:
   MockPolicyCallback() = default;
-  ;
 
   // TODO(lukasza): gmock cannot mock a method taking std::unique_ptr<T>...
   MOCK_METHOD1(OnPolicyUpdatePtr, void(const base::DictionaryValue* policies));
diff --git a/remoting/host/server_log_entry_host.cc b/remoting/host/server_log_entry_host.cc
index 62d1e79..1cf10b7e 100644
--- a/remoting/host/server_log_entry_host.cc
+++ b/remoting/host/server_log_entry_host.cc
@@ -56,7 +56,7 @@
   entry->Set(kKeyOsVersion, GetHostOperatingSystemVersion());
   entry->Set(kKeyHostVersion, STRINGIZE(VERSION));
   entry->AddCpuField();
-};
+}
 
 void AddConnectionTypeToLogEntry(ServerLogEntry* entry,
     protocol::TransportRoute::RouteType type) {
diff --git a/remoting/protocol/fake_connection_to_client.cc b/remoting/protocol/fake_connection_to_client.cc
index 69edc4fd..8e4721a 100644
--- a/remoting/protocol/fake_connection_to_client.cc
+++ b/remoting/protocol/fake_connection_to_client.cc
@@ -32,7 +32,7 @@
   observer_ = observer;
 }
 
-void FakeVideoStream::SelectSource(int id) {};
+void FakeVideoStream::SelectSource(int id) {}
 
 base::WeakPtr<FakeVideoStream> FakeVideoStream::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
diff --git a/remoting/protocol/ice_transport_channel.h b/remoting/protocol/ice_transport_channel.h
index 8aeb9d3..ab6a4f1f 100644
--- a/remoting/protocol/ice_transport_channel.h
+++ b/remoting/protocol/ice_transport_channel.h
@@ -38,8 +38,8 @@
  public:
   class Delegate {
    public:
-    Delegate() {};
-    virtual ~Delegate() {};
+    Delegate() {}
+    virtual ~Delegate() {}
 
     // Called to pass ICE credentials to the session. Used only for STANDARD
     // version of ICE, see SetIceVersion().
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index 6e8c769..2928677d 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -168,7 +168,7 @@
                  << next_incoming_ << " current= " << current;
   }
   return result;
-};
+}
 
 void JingleSession::OrderedMessageQueue::SetInitialId(const std::string& id) {
   int current = GetSequentialId(id);
diff --git a/remoting/protocol/p2p_datagram_socket.h b/remoting/protocol/p2p_datagram_socket.h
index 1366223..606ccbb 100644
--- a/remoting/protocol/p2p_datagram_socket.h
+++ b/remoting/protocol/p2p_datagram_socket.h
@@ -17,7 +17,7 @@
 // Peer-to-peer socket with datagram semantics.
 class P2PDatagramSocket {
  public:
-  virtual ~P2PDatagramSocket() {};
+  virtual ~P2PDatagramSocket() {}
 
   // Receives a packet, up to |buf_len| bytes, from the socket. Size of the
   // incoming packet is returned in case of success. If the packet is larger
diff --git a/remoting/protocol/p2p_stream_socket.h b/remoting/protocol/p2p_stream_socket.h
index 805f6718..2f4bbc3 100644
--- a/remoting/protocol/p2p_stream_socket.h
+++ b/remoting/protocol/p2p_stream_socket.h
@@ -18,7 +18,7 @@
 // Peer-to-peer socket with stream semantics.
 class P2PStreamSocket {
  public:
-  virtual ~P2PStreamSocket() {};
+  virtual ~P2PStreamSocket() {}
 
   // Reads data, up to |buf_len| bytes, from the socket. The number of bytes
   // read is returned, or an error is returned upon failure. ERR_IO_PENDING
diff --git a/remoting/protocol/pseudotcp_adapter_unittest.cc b/remoting/protocol/pseudotcp_adapter_unittest.cc
index db96be54c..c60d1238 100644
--- a/remoting/protocol/pseudotcp_adapter_unittest.cc
+++ b/remoting/protocol/pseudotcp_adapter_unittest.cc
@@ -39,7 +39,7 @@
 class RateLimiter {
  public:
   virtual ~RateLimiter() = default;
-  ;
+
   // Returns true if the new packet needs to be dropped, false otherwise.
   virtual bool DropNextPacket() = 0;
 };
@@ -107,9 +107,9 @@
 
   void set_rate_limiter(RateLimiter* rate_limiter) {
     rate_limiter_ = rate_limiter;
-  };
+  }
 
-  void set_latency(int latency_ms) { latency_ms_ = latency_ms; };
+  void set_latency(int latency_ms) { latency_ms_ = latency_ms; }
 
   // P2PDatagramSocket interface.
   int Recv(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
diff --git a/remoting/protocol/rejecting_authenticator.cc b/remoting/protocol/rejecting_authenticator.cc
index 4f58f5b..05c3dc7 100644
--- a/remoting/protocol/rejecting_authenticator.cc
+++ b/remoting/protocol/rejecting_authenticator.cc
@@ -47,7 +47,7 @@
 const std::string& RejectingAuthenticator::GetAuthKey() const {
   NOTREACHED();
   return auth_key_;
-};
+}
 
 std::unique_ptr<ChannelAuthenticator>
 RejectingAuthenticator::CreateChannelAuthenticator() const {
diff --git a/remoting/protocol/webrtc_frame_scheduler_unittest.cc b/remoting/protocol/webrtc_frame_scheduler_unittest.cc
index b3912a6..3af2de2 100644
--- a/remoting/protocol/webrtc_frame_scheduler_unittest.cc
+++ b/remoting/protocol/webrtc_frame_scheduler_unittest.cc
@@ -101,7 +101,7 @@
 
   // Should not be sent, because of throttling of empty frames.
   EXPECT_FALSE(result);
-};
+}
 
 TEST_F(WebrtcFrameSchedulerTest, EmptyFrameUpdate_ShouldBeSentAfter2000ms) {
   // Identical to the previous test, except it waits a short amount of time
@@ -123,7 +123,7 @@
 
   // Empty frames should be sent at the throttled rate.
   EXPECT_TRUE(result);
-};
+}
 
 TEST_F(WebrtcFrameSchedulerTest, Capturer_RunsAt30Fps) {
   simulate_capture_ = true;
diff --git a/remoting/signaling/xmpp_login_handler.cc b/remoting/signaling/xmpp_login_handler.cc
index 51bf49d..f331f27 100644
--- a/remoting/signaling/xmpp_login_handler.cc
+++ b/remoting/signaling/xmpp_login_handler.cc
@@ -215,7 +215,7 @@
              "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">" +
         cookie +
       "</auth>");
-};
+}
 
 void XmppLoginHandler::OnParserError() {
   OnError(SignalStrategy::PROTOCOL_ERROR);
diff --git a/remoting/signaling/xmpp_stream_parser_unittest.cc b/remoting/signaling/xmpp_stream_parser_unittest.cc
index 64b18bf..bce9fc59 100644
--- a/remoting/signaling/xmpp_stream_parser_unittest.cc
+++ b/remoting/signaling/xmpp_stream_parser_unittest.cc
@@ -51,18 +51,18 @@
 TEST_F(XmppStreamParserTest, ParseXmppStream) {
   parser_->AppendData("<stream><iq>text</iq>");
   EXPECT_EQ(received_stanzas_[0]->Str(), "<iq>text</iq>");
-};
+}
 
 TEST_F(XmppStreamParserTest, HandleMultipleIncomingStanzas) {
   parser_->AppendData("<stream><iq>text</iq><iq>more text</iq>");
   EXPECT_EQ(received_stanzas_[0]->Str(), "<iq>text</iq>");
   EXPECT_EQ(received_stanzas_[1]->Str(), "<iq>more text</iq>");
-};
+}
 
 TEST_F(XmppStreamParserTest, IgnoreWhitespaceBetweenStanzas) {
   parser_->AppendData("<stream> <iq>text</iq>");
   EXPECT_EQ(received_stanzas_[0]->Str(), "<iq>text</iq>");
-};
+}
 
 TEST_F(XmppStreamParserTest, AssembleMessagesFromChunks) {
   parser_->AppendData("<stream><i");
@@ -76,22 +76,22 @@
   parser_->AppendData("</iq>");
 
   EXPECT_EQ(received_stanzas_[0]->Str(), "<iq>😃</iq>");
-};
+}
 
 TEST_F(XmppStreamParserTest, StopParsingOnErrors) {
   parser_->AppendData("<stream><invalidtag p!='a'></invalidtag><iq>text</iq>");
   EXPECT_TRUE(error_);
   EXPECT_TRUE(received_stanzas_.empty());
-};
+}
 
 TEST_F(XmppStreamParserTest, FailOnInvalidStreamHeader) {
   parser_->AppendData("<stream p!='a'>");
   EXPECT_TRUE(error_);
-};
+}
 
 TEST_F(XmppStreamParserTest, FailOnLooseText) {
   parser_->AppendData("stream<");
   EXPECT_TRUE(error_);
-};
+}
 
 }  // namespace remoting
diff --git a/remoting/test/access_token_fetcher.h b/remoting/test/access_token_fetcher.h
index da0c9e7..62f18d2 100644
--- a/remoting/test/access_token_fetcher.h
+++ b/remoting/test/access_token_fetcher.h
@@ -16,7 +16,7 @@
 namespace network {
 class SharedURLLoaderFactory;
 class TransitionalURLLoaderFactoryOwner;
-};  // namespace network
+}  // namespace network
 
 namespace remoting {
 namespace test {
diff --git a/remoting/test/fake_connection_event_logger.cc b/remoting/test/fake_connection_event_logger.cc
index 7ee1b37..a88dbf9f 100644
--- a/remoting/test/fake_connection_event_logger.cc
+++ b/remoting/test/fake_connection_event_logger.cc
@@ -230,7 +230,7 @@
       const protocol::PairingRequest& pairing_request) override {}
   void SetCapabilities(const protocol::Capabilities& capabilities) override {}
   void SelectDesktopDisplay(
-      const protocol::SelectDesktopDisplayRequest& select_display) override{};
+      const protocol::SelectDesktopDisplayRequest& select_display) override {}
 };
 
 FakeConnectionEventLogger::CounterHostStub::CounterHostStub()
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 93de3ef..e086c2e 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -281,6 +281,12 @@
   return account_tracker_service_->SeedAccountInfo(info);
 }
 
+#if defined(OS_IOS)
+void IdentityManager::ForceTriggerOnCookieChange() {
+  gaia_cookie_manager_service_->ForceOnCookieChangeProcessing();
+}
+#endif
+
 void IdentityManager::AddObserver(Observer* observer) {
   observer_list_.AddObserver(observer);
 }
@@ -414,7 +420,7 @@
 void IdentityManager::OnAuthErrorChanged(
     const std::string& account_id,
     const GoogleServiceAuthError& auth_error) {
-  AccountInfo account_info =
+  CoreAccountInfo account_info =
       GetAccountInfoForAccountWithRefreshToken(account_id);
 
   for (auto& observer : observer_list_)
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index a5095bcf..6b7867ff 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/observer_list.h"
+#include "build/build_config.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
@@ -76,7 +77,7 @@
     // Called when when the user moves from having a primary account to no
     // longer having a primary account.
     virtual void OnPrimaryAccountCleared(
-        const AccountInfo& previous_primary_account_info) {}
+        const CoreAccountInfo& previous_primary_account_info) {}
 
     // Called when the user attempts but fails to set their primary
     // account. |error| gives the reason for the failure.
@@ -111,7 +112,7 @@
     // |OnRefreshTokenUpdatedForAccount| when the refresh token is updated. It
     // is not called when the refresh token is removed.
     virtual void OnErrorStateOfRefreshTokenUpdatedForAccount(
-        const AccountInfo& account_info,
+        const CoreAccountInfo& account_info,
         const GoogleServiceAuthError& error) {}
 
     // Called after refresh tokens are loaded.
@@ -385,6 +386,16 @@
   // account id. It's only for replacement of production code.
   std::string LegacySeedAccountInfo(const AccountInfo& info);
 
+#if defined(OS_IOS)
+  // Forces the processing of GaiaCookieManagerService::OnCookieChange. On
+  // iOS, it's necessary to force-trigger the processing of cookie changes
+  // from the client as the normal mechanism for internally observing them
+  // is not wired up.
+  // TODO(https://crbug.com/930582) : Remove the need to expose this method
+  // or move it to the network::CookieManager.
+  void ForceTriggerOnCookieChange();
+#endif
+
   // Methods to register or remove observers.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index 290eda77..ef10f1e 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -233,7 +233,7 @@
   const CoreAccountInfo& primary_account_from_set_callback() {
     return primary_account_from_set_callback_;
   }
-  const AccountInfo& primary_account_from_cleared_callback() {
+  const CoreAccountInfo& primary_account_from_cleared_callback() {
     return primary_account_from_cleared_callback_;
   }
 
@@ -261,7 +261,7 @@
   const std::string& account_from_refresh_token_removed_callback() {
     return account_from_refresh_token_removed_callback_;
   }
-  const AccountInfo&
+  const CoreAccountInfo&
   account_from_error_state_of_refresh_token_updated_callback() {
     return account_from_error_state_of_refresh_token_updated_callback_;
   }
@@ -324,7 +324,7 @@
       std::move(on_primary_account_set_callback_).Run();
   }
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override {
+      const CoreAccountInfo& previous_primary_account_info) override {
     primary_account_from_cleared_callback_ = previous_primary_account_info;
     if (on_primary_account_cleared_callback_)
       std::move(on_primary_account_cleared_callback_).Run();
@@ -355,7 +355,7 @@
       on_refresh_token_removed_callback_.Run(account_id);
   }
   void OnErrorStateOfRefreshTokenUpdatedForAccount(
-      const AccountInfo& account_info,
+      const CoreAccountInfo& account_info,
       const GoogleServiceAuthError& error) override {
     account_from_error_state_of_refresh_token_updated_callback_ = account_info;
     error_from_error_state_of_refresh_token_updated_callback_ = error;
@@ -420,10 +420,10 @@
   base::OnceClosure on_refresh_tokens_loaded_callback_;
   base::OnceClosure on_accounts_in_cookie_updated_callback_;
   CoreAccountInfo primary_account_from_set_callback_;
-  AccountInfo primary_account_from_cleared_callback_;
+  CoreAccountInfo primary_account_from_cleared_callback_;
   AccountInfo account_from_refresh_token_updated_callback_;
   std::string account_from_refresh_token_removed_callback_;
-  AccountInfo account_from_error_state_of_refresh_token_updated_callback_;
+  CoreAccountInfo account_from_error_state_of_refresh_token_updated_callback_;
   AccountInfo account_from_account_updated_callback_;
   AccountInfo account_from_account_removed_with_info_callback_;
   GoogleServiceAuthError
@@ -720,7 +720,7 @@
   signin_manager()->ForceSignOut();
   run_loop2.Run();
 
-  AccountInfo primary_account_from_cleared_callback =
+  CoreAccountInfo primary_account_from_cleared_callback =
       identity_manager_observer()->primary_account_from_cleared_callback();
   EXPECT_EQ(kTestGaiaId, primary_account_from_cleared_callback.gaia);
   EXPECT_EQ(kTestEmail, primary_account_from_cleared_callback.email);
@@ -1528,6 +1528,20 @@
   EXPECT_EQ(account_info.gaia, kTestGaiaId2);
 }
 
+#if defined(OS_IOS)
+TEST_F(IdentityManagerTest, ForceTriggerOnCookieChange) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  signin::SetListAccountsResponseNoAccounts(test_url_loader_factory());
+  // Forces the processing of OnCookieChange and it calls
+  // OnGaiaAccountsInCookieUpdated.
+  identity_manager()->ForceTriggerOnCookieChange();
+  run_loop.Run();
+}
+#endif
+
 #if !defined(OS_CHROMEOS)
 TEST_F(
     IdentityManagerTest,
diff --git a/services/identity/public/cpp/identity_test_utils.cc b/services/identity/public/cpp/identity_test_utils.cc
index c07b158..1f1f96e 100644
--- a/services/identity/public/cpp/identity_test_utils.cc
+++ b/services/identity/public/cpp/identity_test_utils.cc
@@ -40,7 +40,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
   void OnRefreshTokensLoaded() override;
   void OnRefreshTokenUpdatedForAccount(
       const AccountInfo& account_info) override;
@@ -80,7 +80,7 @@
 }
 
 void OneShotIdentityManagerObserver::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   if (event_to_wait_on_ != IdentityManagerEvent::PRIMARY_ACCOUNT_CLEARED)
     return;
 
diff --git a/services/identity/public/cpp/primary_account_mutator_unittest.cc b/services/identity/public/cpp/primary_account_mutator_unittest.cc
index 9ca642e..81ed22f 100644
--- a/services/identity/public/cpp/primary_account_mutator_unittest.cc
+++ b/services/identity/public/cpp/primary_account_mutator_unittest.cc
@@ -39,7 +39,7 @@
 // method OnPrimaryAccountCleared is invoked. The parameter will be a
 // reference to the still valid primary account that was cleared.
 using PrimaryAccountClearedCallback =
-    base::RepeatingCallback<void(const AccountInfo&)>;
+    base::RepeatingCallback<void(const CoreAccountInfo&)>;
 
 // This callback will be invoked every time the IdentityManager::Observer
 // method OnPrimaryAccountSigninFailed is invoked. The parameter will be
@@ -75,7 +75,7 @@
   }
 
   // identity::IdentityManager::Observer implementation.
-  void OnPrimaryAccountCleared(const AccountInfo& account_info) override {
+  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override {
     on_primary_account_cleared_.Run(account_info);
   }
 
@@ -163,7 +163,7 @@
   base::RunLoop run_loop;
   PrimaryAccountClearedCallback primary_account_cleared_callback =
       base::BindRepeating([](base::RepeatingClosure quit_closure,
-                             const AccountInfo&) { quit_closure.Run(); },
+                             const CoreAccountInfo&) { quit_closure.Run(); },
                           run_loop.QuitClosure());
 
   // Authentication error should not occur.
@@ -572,7 +572,7 @@
 
   // No primary account to "clear", so no callback.
   PrimaryAccountClearedCallback primary_account_cleared_callback =
-      base::BindRepeating([](const AccountInfo&) {
+      base::BindRepeating([](const CoreAccountInfo&) {
         FAIL() << "no primary account is set, so nothing should be cleared";
       });
 
diff --git a/services/identity/public/objc/identity_manager_observer_bridge.h b/services/identity/public/objc/identity_manager_observer_bridge.h
index 12f54b9..a1d0751 100644
--- a/services/identity/public/objc/identity_manager_observer_bridge.h
+++ b/services/identity/public/objc/identity_manager_observer_bridge.h
@@ -23,7 +23,8 @@
 // these semantics.
 
 - (void)onPrimaryAccountSet:(const CoreAccountInfo&)primaryAccountInfo;
-- (void)onPrimaryAccountCleared:(const AccountInfo&)previousPrimaryAccountInfo;
+- (void)onPrimaryAccountCleared:
+    (const CoreAccountInfo&)previousPrimaryAccountInfo;
 - (void)onPrimaryAccountSigninFailed:(const GoogleServiceAuthError&)error;
 - (void)onRefreshTokenUpdatedForAccount:(const AccountInfo&)accountInfo;
 - (void)onRefreshTokenRemovedForAccount:(const std::string&)accountId;
@@ -50,7 +51,7 @@
   void OnPrimaryAccountSet(
       const CoreAccountInfo& primary_account_info) override;
   void OnPrimaryAccountCleared(
-      const AccountInfo& previous_primary_account_info) override;
+      const CoreAccountInfo& previous_primary_account_info) override;
   void OnPrimaryAccountSigninFailed(
       const GoogleServiceAuthError& error) override;
   void OnRefreshTokenUpdatedForAccount(
diff --git a/services/identity/public/objc/identity_manager_observer_bridge.mm b/services/identity/public/objc/identity_manager_observer_bridge.mm
index d26af7b9..3438d3e5 100644
--- a/services/identity/public/objc/identity_manager_observer_bridge.mm
+++ b/services/identity/public/objc/identity_manager_observer_bridge.mm
@@ -29,7 +29,7 @@
 }
 
 void IdentityManagerObserverBridge::OnPrimaryAccountCleared(
-    const AccountInfo& previous_primary_account_info) {
+    const CoreAccountInfo& previous_primary_account_info) {
   if ([delegate_ respondsToSelector:@selector(onPrimaryAccountCleared:)]) {
     [delegate_ onPrimaryAccountCleared:previous_primary_account_info];
   }
diff --git a/services/metrics/ukm_api.md b/services/metrics/ukm_api.md
index 8a4a8394..61f058d 100644
--- a/services/metrics/ukm_api.md
+++ b/services/metrics/ukm_api.md
@@ -34,6 +34,55 @@
 </event>
 ```
 
+### Controlling the Aggregation of Metrics
+
+Control of which metrics are included in the History table is done via the same
+[`tools/metrics/ukm/ukm.xml`](https://cs.chromium.org/chromium/src/tools/metrics/ukm/ukm.xml)
+file in the Chromium codebase. To have a metric aggregated, `<aggregation>` and
+`<history>` tags need to be added.
+
+```
+<event name="Goat.Teleported">
+  <metric name="Duration">
+    ...
+    <aggregation>
+      <history>
+        <index fields="profile.country"/>
+        <statistics>
+          <quantiles type="std-percentiles"/>
+        </statistics>
+      </history>
+    </aggregation>
+    ...
+  </metric>
+</event>
+```
+
+Supported statistic types are:
+
+*   `<quantiles type="std-percentiles"/>`: Calculates the "standard percentiles"
+    for the values which are 1, 5, 10, 25, 50, 75, 90, 95, and 99%ile.
+*   `<enumeration/>`: Calculates the proportions of all values individually. The
+    proportions indicate the relative frequency of each bucket and are
+    calculated independently for each metric over each aggregation. The
+    proportions will sum to 1.0 for an enumeration that emits only one result
+    per page-load if it emits anything at all. An enumeration emitted more than
+    once on a page will result in proportions that total greater than 1.0.
+
+There can also be one or more `index` tags which define additional aggregation
+keys. These are a comma-separated list of keys that is appended to the standard
+set. These additional keys are optional but, if present, are always present
+together. In other words, "fields=profile.county,profile.form_factory" will
+cause all the standard aggregations plus each with *both* country *and*
+form_factor but **not** with all the standard aggregations (see above) plus only
+one of them. If individual and combined versions are desired, use multiple index
+tags.
+
+Currently supported additional index fields are:
+
+*   `profile.country`
+*   `profile.form_factor`
+
 ## Get UkmRecorder instance
 
 In order to record UKM events, your code needs a UkmRecorder object, defined by [//services/metrics/public/cpp/ukm_recorder.h](https://cs.chromium.org/chromium/src/services/metrics/public/cpp/ukm_recorder.h)
diff --git a/testing/libfuzzer/fuzzers/libsrtp_fuzzer.cc b/testing/libfuzzer/fuzzers/libsrtp_fuzzer.cc
index 7170b25..e265386 100644
--- a/testing/libfuzzer/fuzzers/libsrtp_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/libsrtp_fuzzer.cc
@@ -85,7 +85,7 @@
     assert(static_cast<size_t>(policy.rtcp.cipher_key_len) == key_length);
     memcpy(key, replacement_key, key_length);
     return policy;
-  };
+  }
 
   Environment() {
     srtp_init();
@@ -112,7 +112,7 @@
     p->auth_key_len = 0;
     p->auth_tag_len = 0;
     p->sec_serv = sec_serv_none;
-  };
+  }
 };
 
 size_t ReadLength(const uint8_t* data, size_t size) {
diff --git a/testing/libfuzzer/fuzzers/usrsctp_fuzzer.cc b/testing/libfuzzer/fuzzers/usrsctp_fuzzer.cc
index 3724270..a6a8f4f 100644
--- a/testing/libfuzzer/fuzzers/usrsctp_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/usrsctp_fuzzer.cc
@@ -13,9 +13,9 @@
                    uint8_t tos,
                    uint8_t set_df) {
   return 0;
-};
+}
 
-static void ignore2(const char* format, ...) {};
+static void ignore2(const char* format, ...) {}
 
 struct Environment {
   Environment() {
diff --git a/testing/libfuzzer/proto/skia_image_filter_proto_converter.cc b/testing/libfuzzer/proto/skia_image_filter_proto_converter.cc
index 6cb9c61..c0aefeab 100644
--- a/testing/libfuzzer/proto/skia_image_filter_proto_converter.cc
+++ b/testing/libfuzzer/proto/skia_image_filter_proto_converter.cc
@@ -2340,4 +2340,4 @@
          kMisbehavedFlattenableBlacklist.end();
 #endif  // AVOID_MISBEHAVIOR
 }
-};  // namespace skia_image_filter_proto_converter
+}  // namespace skia_image_filter_proto_converter
diff --git a/testing/libfuzzer/proto/skia_image_filter_proto_converter.h b/testing/libfuzzer/proto/skia_image_filter_proto_converter.h
index e6c17199..d4cf6db 100644
--- a/testing/libfuzzer/proto/skia_image_filter_proto_converter.h
+++ b/testing/libfuzzer/proto/skia_image_filter_proto_converter.h
@@ -444,5 +444,5 @@
                             ImageInfo::AlphaType alpha_type) const;
 #endif  // DEVELOPMENT
 };
-};      // namespace skia_image_filter_proto_converter
+}  // namespace skia_image_filter_proto_converter
 #endif  // TESTING_LIBFUZZER_PROTO_SKIA_IMAGE_FILTER_PROTO_CONVERTER_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 106efc62..6cac9d0 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -138,6 +138,24 @@
             ]
         }
     ],
+    "AndroidGooglePasswordManager": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "min-google-play-services-version": "14700000"
+                    },
+                    "enable_features": [
+                        "google-password-manager"
+                    ]
+                }
+            ]
+        }
+    ],
     "AndroidInProductHelpContextualSearchPromotePanelOpen": [
         {
             "platforms": [
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index 29e8f84..14007b6 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 0b1e6d417b414aad9282e32e8c49c719edeb63c1
+Revision: 2901ec32a919311384d6ad4194e2d927c06831f7
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/absl/base/attributes.h b/third_party/abseil-cpp/absl/base/attributes.h
index 291ad89..fa44012e 100644
--- a/third_party/abseil-cpp/absl/base/attributes.h
+++ b/third_party/abseil-cpp/absl/base/attributes.h
@@ -287,6 +287,17 @@
 #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
 #endif
 
+// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+//
+// Tells the SafeStack to not instrument a given function.
+// See https://clang.llvm.org/docs/SafeStack.html for details.
+#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
+  __attribute__((no_sanitize("safe-stack")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+#endif
+
 // ABSL_ATTRIBUTE_RETURNS_NONNULL
 //
 // Tells the compiler that a particular function never returns a null pointer.
diff --git a/third_party/abseil-cpp/absl/base/internal/endian.h b/third_party/abseil-cpp/absl/base/internal/endian.h
index d5dc51a..3f59184 100644
--- a/third_party/abseil-cpp/absl/base/internal/endian.h
+++ b/third_party/abseil-cpp/absl/base/internal/endian.h
@@ -75,7 +75,7 @@
   if (__builtin_constant_p(host_int)) {
     return __bswap_constant_64(host_int);
   } else {
-    register uint64_t result;
+    uint64_t result;
     __asm__("bswap %0" : "=r"(result) : "0"(host_int));
     return result;
   }
diff --git a/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc b/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc
index 94c861d..3bbd4954 100644
--- a/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc
+++ b/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc
@@ -51,17 +51,12 @@
 ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode) {
-  if (loop != 0) {
-    int save_errno = errno;
-    struct timespec tm;
-    tm.tv_sec = 0;
-    // Increase the delay; we expect (but do not rely on) explicit wakeups.
-    // We don't rely on explicit wakeups because we intentionally allow for
-    // a race on the kSpinLockSleeper bit.
-    tm.tv_nsec = 16 * absl::base_internal::SpinLockSuggestedDelayNS(loop);
-    syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
-    errno = save_errno;
-  }
+  int save_errno = errno;
+  struct timespec tm;
+  tm.tv_sec = 0;
+  tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
+  syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
+  errno = save_errno;
 }
 
 ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
diff --git a/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc b/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc
index 365a7939..7e4f4352 100644
--- a/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc
+++ b/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc
@@ -65,17 +65,14 @@
   r = 0x5deece66dLL * r + 0xb;   // numbers from nrand48()
   delay_rand.store(r, std::memory_order_relaxed);
 
-  r <<= 16;   // 48-bit random number now in top 48-bits.
   if (loop < 0 || loop > 32) {   // limit loop to 0..32
     loop = 32;
   }
-  // loop>>3 cannot exceed 4 because loop cannot exceed 32.
-  // Select top 20..24 bits of lower 48 bits,
-  // giving approximately 0ms to 16ms.
-  // Mean is exponential in loop for first 32 iterations, then 8ms.
-  // The futex path multiplies this by 16, since we expect explicit wakeups
-  // almost always on that path.
-  return static_cast<int>(r >> (44 - (loop >> 3)));
+  const int kMinDelay = 128 << 10;  // 128us
+  // Double delay every 8 iterations, up to 16x (2ms).
+  int delay = kMinDelay << (loop / 8);
+  // Randomize in delay..2*delay range, for resulting 128us..4ms range.
+  return delay | ((delay - 1) & static_cast<int>(r));
 }
 
 }  // namespace base_internal
diff --git a/third_party/abseil-cpp/absl/base/macros.h b/third_party/abseil-cpp/absl/base/macros.h
index 9e7ab37..5ed12cb0 100644
--- a/third_party/abseil-cpp/absl/base/macros.h
+++ b/third_party/abseil-cpp/absl/base/macros.h
@@ -24,7 +24,6 @@
 // This code is compiled directly on many platforms, including client
 // platforms like Windows, Mac, and embedded systems.  Before making
 // any changes here, make sure that you're not breaking any platforms.
-//
 
 #ifndef ABSL_BASE_MACROS_H_
 #define ABSL_BASE_MACROS_H_
diff --git a/third_party/abseil-cpp/absl/container/BUILD.bazel b/third_party/abseil-cpp/absl/container/BUILD.bazel
index 87fc734..f3b3a2c0 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/container/BUILD.bazel
@@ -447,8 +447,20 @@
 )
 
 cc_library(
+    name = "hashtablez_force_sampling",
+    srcs = ["internal/hashtablez_force_sampling.cc"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":hashtablez_sampler",
+    ],
+)
+
+cc_library(
     name = "hashtablez_sampler",
-    srcs = ["internal/hashtablez_sampler.cc"],
+    srcs = [
+        "internal/hashtablez_sampler.cc",
+        "internal/hashtablez_sampler_force_weak_definition.cc",
+    ],
     hdrs = ["internal/hashtablez_sampler.h"],
     copts = ABSL_DEFAULT_COPTS,
     deps = [
@@ -476,6 +488,20 @@
     ],
 )
 
+cc_test(
+    name = "hashtablez_force_sampling_test",
+    srcs = ["internal/hashtablez_force_sampling_test.cc"],
+    tags = [
+        "no_test_darwin_x86_64",
+        "no_test_msvc_x64",
+    ],
+    deps = [
+        ":hashtablez_force_sampling",
+        ":hashtablez_sampler",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "node_hash_policy",
     hdrs = ["internal/node_hash_policy.h"],
@@ -516,6 +542,7 @@
     copts = ABSL_DEFAULT_COPTS,
     deps = [
         "//absl/meta:type_traits",
+        "//absl/types:optional",
     ],
 )
 
@@ -539,7 +566,6 @@
         "//absl/base:endian",
         "//absl/memory",
         "//absl/meta:type_traits",
-        "//absl/types:optional",
         "//absl/utility",
     ],
 )
diff --git a/third_party/abseil-cpp/absl/container/BUILD.gn b/third_party/abseil-cpp/absl/container/BUILD.gn
index 209c5ec7..98635d5 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.gn
+++ b/third_party/abseil-cpp/absl/container/BUILD.gn
@@ -292,6 +292,21 @@
   ]
 }
 
+source_set("hashtablez_force_sampling") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/hashtablez_force_sampling.cc",
+  ]
+  deps = [
+    ":hashtablez_sampler",
+  ]
+}
+
 source_set("hashtablez_sampler") {
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [
@@ -304,6 +319,7 @@
   ]
   sources = [
     "internal/hashtablez_sampler.cc",
+    "internal/hashtablez_sampler_force_weak_definition.cc",
   ]
   deps = [
     ":have_sse",
@@ -370,6 +386,7 @@
   ]
   deps = [
     "../meta:type_traits",
+    "../types:optional",
   ]
 }
 
@@ -401,7 +418,6 @@
     "../base:endian",
     "../memory",
     "../meta:type_traits",
-    "../types:optional",
     "../utility",
   ]
 }
diff --git a/third_party/abseil-cpp/absl/container/CMakeLists.txt b/third_party/abseil-cpp/absl/container/CMakeLists.txt
index 21c9cb9..822388bd 100644
--- a/third_party/abseil-cpp/absl/container/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/container/CMakeLists.txt
@@ -444,6 +444,7 @@
     "internal/hashtablez_sampler.h"
   SRCS
     "internal/hashtablez_sampler.cc"
+    "internal/hashtablez_sampler_force_weak_definition.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
@@ -465,6 +466,30 @@
 
 absl_cc_library(
   NAME
+    hashtablez_force_sampling
+  SRCS
+    "internal/hashtablez_force_sampling.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::base
+    absl::have_sse
+    absl::synchronization
+)
+
+absl_cc_test(
+  NAME
+    hashtablez_force_sampling_test
+  SRCS
+    "internal/hashtablez_force_sampling_test.cc"
+  DEPS
+    absl::hashtablez_force_sampling
+    absl::hashtablez_sampler
+    gmock_main
+)
+
+absl_cc_library(
+  NAME
     hashtable_debug
   HDRS
     "internal/hashtable_debug.h"
diff --git a/third_party/abseil-cpp/absl/container/fixed_array_test.cc b/third_party/abseil-cpp/absl/container/fixed_array_test.cc
index 205ff41..1679ba4 100644
--- a/third_party/abseil-cpp/absl/container/fixed_array_test.cc
+++ b/third_party/abseil-cpp/absl/container/fixed_array_test.cc
@@ -869,4 +869,21 @@
 }
 #endif  // ADDRESS_SANITIZER
 
+TEST(FixedArrayTest, AbslHashValueWorks) {
+  using V = absl::FixedArray<int>;
+  std::vector<V> cases;
+
+  // Generate a variety of vectors some of these are small enough for the inline
+  // space but are stored out of line.
+  for (int i = 0; i < 10; ++i) {
+    V v(i);
+    for (int j = 0; j < i; ++j) {
+      v[j] = j;
+    }
+    cases.push_back(v);
+  }
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
+}
+
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector.h b/third_party/abseil-cpp/absl/container/inlined_vector.h
index 649e904..5c9e6d9 100644
--- a/third_party/abseil-cpp/absl/container/inlined_vector.h
+++ b/third_party/abseil-cpp/absl/container/inlined_vector.h
@@ -53,7 +53,6 @@
 #include "absl/memory/memory.h"
 
 namespace absl {
-
 // -----------------------------------------------------------------------------
 // InlinedVector
 // -----------------------------------------------------------------------------
@@ -67,29 +66,16 @@
 template <typename T, size_t N, typename A = std::allocator<T>>
 class InlinedVector {
   static_assert(N > 0, "InlinedVector requires inline capacity greater than 0");
-  constexpr static typename A::size_type inlined_capacity() {
+  constexpr static typename A::size_type GetInlinedCapacity() {
     return static_cast<typename A::size_type>(N);
   }
 
   template <typename Iterator>
-  using IsAtLeastInputIterator = std::is_convertible<
-      typename std::iterator_traits<Iterator>::iterator_category,
-      std::input_iterator_tag>;
-
-  template <typename Iterator>
   using IsAtLeastForwardIterator = std::is_convertible<
       typename std::iterator_traits<Iterator>::iterator_category,
       std::forward_iterator_tag>;
 
   template <typename Iterator>
-  using DisableIfIntegral =
-      absl::enable_if_t<!std::is_integral<Iterator>::value>;
-
-  template <typename Iterator>
-  using EnableIfAtLeastInputIterator =
-      absl::enable_if_t<IsAtLeastInputIterator<Iterator>::value>;
-
-  template <typename Iterator>
   using EnableIfAtLeastForwardIterator =
       absl::enable_if_t<IsAtLeastForwardIterator<Iterator>::value>;
 
@@ -139,29 +125,40 @@
     InitAssign(n, v);
   }
 
-  // Creates an inlined vector of copies of the values in `init_list`.
-  InlinedVector(std::initializer_list<value_type> init_list,
+  // Creates an inlined vector of copies of the values in `list`.
+  InlinedVector(std::initializer_list<value_type> list,
                 const allocator_type& alloc = allocator_type())
       : allocator_and_tag_(alloc) {
-    AppendRange(init_list.begin(), init_list.end());
+    AppendForwardRange(list.begin(), list.end());
   }
 
   // Creates an inlined vector with elements constructed from the provided
-  // Iterator range [`first`, `last`).
+  // forward iterator range [`first`, `last`).
   //
   // NOTE: The `enable_if` prevents ambiguous interpretation between a call to
   // this constructor with two integral arguments and a call to the above
   // `InlinedVector(size_type, const_reference)` constructor.
-  template <typename InputIterator, DisableIfIntegral<InputIterator>* = nullptr>
+  template <typename ForwardIterator,
+            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+  InlinedVector(ForwardIterator first, ForwardIterator last,
+                const allocator_type& alloc = allocator_type())
+      : allocator_and_tag_(alloc) {
+    AppendForwardRange(first, last);
+  }
+
+  // Creates an inlined vector with elements constructed from the provided input
+  // iterator range [`first`, `last`).
+  template <typename InputIterator,
+            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
   InlinedVector(InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type())
       : allocator_and_tag_(alloc) {
-    AppendRange(first, last);
+    std::copy(first, last, std::back_inserter(*this));
   }
 
   // Creates a copy of `other` using `other`'s allocator.
   InlinedVector(const InlinedVector& other)
-      : InlinedVector(other, other.get_allocator()) {}
+      : InlinedVector(other, other.allocator()) {}
 
   // Creates a copy of `other` but with a specified allocator.
   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
@@ -189,17 +186,19 @@
   InlinedVector(InlinedVector&& other) noexcept(
       absl::allocator_is_nothrow<allocator_type>::value ||
       std::is_nothrow_move_constructible<value_type>::value)
-      : allocator_and_tag_(other.allocator_and_tag_) {
+      : allocator_and_tag_(other.allocator()) {
     if (other.allocated()) {
       // We can just steal the underlying buffer from the source.
       // That leaves the source empty, so we clear its size.
       init_allocation(other.allocation());
+      tag().set_allocated_size(other.size());
       other.tag() = Tag();
     } else {
       UninitializedCopy(
           std::make_move_iterator(other.inlined_space()),
           std::make_move_iterator(other.inlined_space() + other.size()),
           inlined_space());
+      tag().set_inline_size(other.size());
     }
   }
 
@@ -268,12 +267,12 @@
   // Returns the number of elements that can be stored in the inlined vector
   // without requiring a reallocation of underlying memory.
   //
-  // NOTE: For most inlined vectors, `capacity()` should equal
-  // `inlined_capacity()`. For inlined vectors which exceed this capacity, they
+  // NOTE: For most inlined vectors, `capacity()` should equal the template
+  // parameter `N`. For inlined vectors which exceed this capacity, they
   // will no longer be inlined and `capacity()` will equal its capacity on the
   // allocated heap.
   size_type capacity() const noexcept {
-    return allocated() ? allocation().capacity() : inlined_capacity();
+    return allocated() ? allocation().capacity() : GetInlinedCapacity();
   }
 
   // `InlinedVector::data()`
@@ -433,8 +432,8 @@
   //
   // Replaces the contents of the inlined vector with copies of the elements in
   // the provided `std::initializer_list`.
-  InlinedVector& operator=(std::initializer_list<value_type> init_list) {
-    AssignRange(init_list.begin(), init_list.end());
+  InlinedVector& operator=(std::initializer_list<value_type> list) {
+    AssignForwardRange(list.begin(), list.end());
     return *this;
   }
 
@@ -510,15 +509,30 @@
   // Overload of `InlinedVector::assign()` to replace the contents of the
   // inlined vector with copies of the values in the provided
   // `std::initializer_list`.
-  void assign(std::initializer_list<value_type> init_list) {
-    AssignRange(init_list.begin(), init_list.end());
+  void assign(std::initializer_list<value_type> list) {
+    AssignForwardRange(list.begin(), list.end());
   }
 
   // Overload of `InlinedVector::assign()` to replace the contents of the
-  // inlined vector with values constructed from the range [`first`, `last`).
-  template <typename InputIterator, DisableIfIntegral<InputIterator>* = nullptr>
+  // inlined vector with the forward iterator range [`first`, `last`).
+  template <typename ForwardIterator,
+            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+  void assign(ForwardIterator first, ForwardIterator last) {
+    AssignForwardRange(first, last);
+  }
+
+  // Overload of `InlinedVector::assign()` to replace the contents of the
+  // inlined vector with the input iterator range [`first`, `last`).
+  template <typename InputIterator,
+            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
   void assign(InputIterator first, InputIterator last) {
-    AssignRange(first, last);
+    size_type assign_index = 0;
+    for (; (assign_index < size()) && (first != last);
+         static_cast<void>(++assign_index), static_cast<void>(++first)) {
+      *(data() + assign_index) = *first;
+    }
+    erase(data() + assign_index, data() + size());
+    std::copy(first, last, std::back_inserter(*this));
   }
 
   // `InlinedVector::resize()`
@@ -569,62 +583,75 @@
 
   // `InlinedVector::insert()`
   //
-  // Copies `v` into `position`, returning an `iterator` pointing to the newly
+  // Copies `v` into `pos`, returning an `iterator` pointing to the newly
   // inserted element.
-  iterator insert(const_iterator position, const_reference v) {
-    return emplace(position, v);
+  iterator insert(const_iterator pos, const_reference v) {
+    return emplace(pos, v);
   }
 
-  // Overload of `InlinedVector::insert()` for moving `v` into `position`,
-  // returning an iterator pointing to the newly inserted element.
-  iterator insert(const_iterator position, rvalue_reference v) {
-    return emplace(position, std::move(v));
+  // Overload of `InlinedVector::insert()` for moving `v` into `pos`, returning
+  // an iterator pointing to the newly inserted element.
+  iterator insert(const_iterator pos, rvalue_reference v) {
+    return emplace(pos, std::move(v));
   }
 
   // Overload of `InlinedVector::insert()` for inserting `n` contiguous copies
-  // of `v` starting at `position`. Returns an `iterator` pointing to the first
-  // of the newly inserted elements.
-  iterator insert(const_iterator position, size_type n, const_reference v) {
-    return InsertWithCount(position, n, v);
+  // of `v` starting at `pos`. Returns an `iterator` pointing to the first of
+  // the newly inserted elements.
+  iterator insert(const_iterator pos, size_type n, const_reference v) {
+    return InsertWithCount(pos, n, v);
   }
 
   // Overload of `InlinedVector::insert()` for copying the contents of the
-  // `std::initializer_list` into the vector starting at `position`. Returns an
+  // `std::initializer_list` into the vector starting at `pos`. Returns an
   // `iterator` pointing to the first of the newly inserted elements.
-  iterator insert(const_iterator position,
-                  std::initializer_list<value_type> init_list) {
-    return insert(position, init_list.begin(), init_list.end());
+  iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
+    return insert(pos, list.begin(), list.end());
   }
 
   // Overload of `InlinedVector::insert()` for inserting elements constructed
-  // from the range [`first`, `last`). Returns an `iterator` pointing to the
-  // first of the newly inserted elements.
+  // from the forward iterator range [`first`, `last`). Returns an `iterator`
+  // pointing to the first of the newly inserted elements.
   //
   // NOTE: The `enable_if` is intended to disambiguate the two three-argument
   // overloads of `insert()`.
+  template <typename ForwardIterator,
+            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+  iterator insert(const_iterator pos, ForwardIterator first,
+                  ForwardIterator last) {
+    return InsertWithForwardRange(pos, first, last);
+  }
+
+  // Overload of `InlinedVector::insert()` for inserting elements constructed
+  // from the input iterator range [`first`, `last`). Returns an `iterator`
+  // pointing to the first of the newly inserted elements.
   template <typename InputIterator,
-            EnableIfAtLeastInputIterator<InputIterator>* = nullptr>
-  iterator insert(const_iterator position, InputIterator first,
-                  InputIterator last) {
-    return InsertWithRange(position, first, last);
+            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+  iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
+    size_type initial_insert_index = std::distance(cbegin(), pos);
+    for (size_type insert_index = initial_insert_index; first != last;
+         static_cast<void>(++insert_index), static_cast<void>(++first)) {
+      insert(data() + insert_index, *first);
+    }
+    return iterator(data() + initial_insert_index);
   }
 
   // `InlinedVector::emplace()`
   //
-  // Constructs and inserts an object in the inlined vector at the given
-  // `position`, returning an `iterator` pointing to the newly emplaced element.
+  // Constructs and inserts an object in the inlined vector at the given `pos`,
+  // returning an `iterator` pointing to the newly emplaced element.
   template <typename... Args>
-  iterator emplace(const_iterator position, Args&&... args) {
-    assert(position >= begin());
-    assert(position <= end());
-    if (ABSL_PREDICT_FALSE(position == end())) {
+  iterator emplace(const_iterator pos, Args&&... args) {
+    assert(pos >= begin());
+    assert(pos <= end());
+    if (ABSL_PREDICT_FALSE(pos == end())) {
       emplace_back(std::forward<Args>(args)...);
       return end() - 1;
     }
 
     T new_t = T(std::forward<Args>(args)...);
 
-    auto range = ShiftRight(position, 1);
+    auto range = ShiftRight(pos, 1);
     if (range.first == range.second) {
       // constructing into uninitialized memory
       Construct(range.first, std::move(new_t));
@@ -643,12 +670,9 @@
   template <typename... Args>
   reference emplace_back(Args&&... args) {
     size_type s = size();
-    assert(s <= capacity());
     if (ABSL_PREDICT_FALSE(s == capacity())) {
       return GrowAndEmplaceBack(std::forward<Args>(args)...);
     }
-    assert(s < capacity());
-
     pointer space;
     if (allocated()) {
       tag().set_allocated_size(s + 1);
@@ -689,18 +713,18 @@
 
   // `InlinedVector::erase()`
   //
-  // Erases the element at `position` of the inlined vector, returning an
-  // `iterator` pointing to the first element following the erased element.
+  // Erases the element at `pos` of the inlined vector, returning an `iterator`
+  // pointing to the first element following the erased element.
   //
   // NOTE: May return the end iterator, which is not dereferencable.
-  iterator erase(const_iterator position) {
-    assert(position >= begin());
-    assert(position < end());
+  iterator erase(const_iterator pos) {
+    assert(pos >= begin());
+    assert(pos < end());
 
-    iterator pos = const_cast<iterator>(position);
-    std::move(pos + 1, end(), pos);
+    iterator position = const_cast<iterator>(pos);
+    std::move(position + 1, end(), position);
     pop_back();
-    return pos;
+    return position;
   }
 
   // Overload of `InlinedVector::erase()` for erasing all elements in the
@@ -766,19 +790,19 @@
   // `InlinedVector::shrink_to_fit()`
   //
   // Reduces memory usage by freeing unused memory. After this call, calls to
-  // `capacity()` will be equal to `(std::max)(inlined_capacity(), size())`.
+  // `capacity()` will be equal to `(std::max)(GetInlinedCapacity(), size())`.
   //
-  // If `size() <= inlined_capacity()` and the elements are currently stored on
-  // the heap, they will be moved to the inlined storage and the heap memory
+  // If `size() <= GetInlinedCapacity()` and the elements are currently stored
+  // on the heap, they will be moved to the inlined storage and the heap memory
   // will be deallocated.
   //
-  // If `size() > inlined_capacity()` and `size() < capacity()` the elements
+  // If `size() > GetInlinedCapacity()` and `size() < capacity()` the elements
   // will be moved to a smaller heap allocation.
   void shrink_to_fit() {
     const auto s = size();
     if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return;
 
-    if (s <= inlined_capacity()) {
+    if (s <= GetInlinedCapacity()) {
       // Move the elements to the inlined storage.
       // We have to do this using a temporary, because `inlined_storage` and
       // `allocation_storage` are in a union field.
@@ -809,7 +833,7 @@
 
  private:
   template <typename H, typename TheT, size_t TheN, typename TheA>
-  friend H AbslHashValue(H, const InlinedVector<TheT, TheN, TheA>& vector);
+  friend auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H;
 
   // Holds whether the vector is allocated or not in the lowest bit and the size
   // in the high bits:
@@ -960,7 +984,7 @@
     const size_type s = size();
     assert(s <= capacity());
 
-    size_type target = (std::max)(inlined_capacity(), s + delta);
+    size_type target = (std::max)(GetInlinedCapacity(), s + delta);
 
     // Compute new capacity by repeatedly doubling current capacity
     // TODO(psrc): Check and avoid overflow?
@@ -1063,7 +1087,7 @@
   }
 
   void InitAssign(size_type n) {
-    if (n > inlined_capacity()) {
+    if (n > GetInlinedCapacity()) {
       Allocation new_allocation(allocator(), n);
       init_allocation(new_allocation);
       UninitializedFill(allocated_space(), allocated_space() + n);
@@ -1075,7 +1099,7 @@
   }
 
   void InitAssign(size_type n, const_reference v) {
-    if (n > inlined_capacity()) {
+    if (n > GetInlinedCapacity()) {
       Allocation new_allocation(allocator(), n);
       init_allocation(new_allocation);
       UninitializedFill(allocated_space(), allocated_space() + n, v);
@@ -1086,15 +1110,18 @@
     }
   }
 
-  template <typename ForwardIterator,
-            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
-  void AssignRange(ForwardIterator first, ForwardIterator last) {
+  template <typename ForwardIterator>
+  void AssignForwardRange(ForwardIterator first, ForwardIterator last) {
+    static_assert(IsAtLeastForwardIterator<ForwardIterator>::value, "");
+
     auto length = std::distance(first, last);
+
     // Prefer reassignment to copy construction for elements.
     if (static_cast<size_type>(length) <= size()) {
       erase(std::copy(first, last, begin()), end());
       return;
     }
+
     reserve(length);
     iterator out = begin();
     for (; out != end(); ++first, ++out) *out = *first;
@@ -1107,22 +1134,10 @@
     }
   }
 
-  template <typename InputIterator,
-            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
-  void AssignRange(InputIterator first, InputIterator last) {
-    // Optimized to avoid reallocation.
-    // Prefer reassignment to copy construction for elements.
-    iterator out = begin();
-    for (; first != last && out != end(); ++first, ++out) {
-      *out = *first;
-    }
-    erase(out, end());
-    std::copy(first, last, std::back_inserter(*this));
-  }
+  template <typename ForwardIterator>
+  void AppendForwardRange(ForwardIterator first, ForwardIterator last) {
+    static_assert(IsAtLeastForwardIterator<ForwardIterator>::value, "");
 
-  template <typename ForwardIterator,
-            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
-  void AppendRange(ForwardIterator first, ForwardIterator last) {
     auto length = std::distance(first, last);
     reserve(size() + length);
     if (allocated()) {
@@ -1134,12 +1149,6 @@
     }
   }
 
-  template <typename InputIterator,
-            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
-  void AppendRange(InputIterator first, InputIterator last) {
-    std::copy(first, last, std::back_inserter(*this));
-  }
-
   iterator InsertWithCount(const_iterator position, size_type n,
                            const_reference v) {
     assert(position >= begin() && position <= end());
@@ -1153,11 +1162,12 @@
     return it_pair.first;
   }
 
-  template <typename ForwardIterator,
-            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
-  iterator InsertWithRange(const_iterator position, ForwardIterator first,
-                           ForwardIterator last) {
+  template <typename ForwardIterator>
+  iterator InsertWithForwardRange(const_iterator position,
+                                  ForwardIterator first, ForwardIterator last) {
+    static_assert(IsAtLeastForwardIterator<ForwardIterator>::value, "");
     assert(position >= begin() && position <= end());
+
     if (ABSL_PREDICT_FALSE(first == last))
       return const_cast<iterator>(position);
 
@@ -1170,17 +1180,6 @@
     return it_pair.first;
   }
 
-  template <typename InputIterator,
-            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
-  iterator InsertWithRange(const_iterator position, InputIterator first,
-                           InputIterator last) {
-    assert(position >= begin() && position <= end());
-    size_type index = position - cbegin();
-    size_type i = index;
-    while (first != last) insert(begin() + i++, *first++);
-    return begin() + index;
-  }
-
   void SwapImpl(InlinedVector& other) {
     using std::swap;  // Augment ADL with `std::swap`.
 
@@ -1291,8 +1290,8 @@
 // Swaps the contents of two inlined vectors. This convenience function
 // simply calls `InlinedVector::swap()`.
 template <typename T, size_t N, typename A>
-void swap(InlinedVector<T, N, A>& a,
-          InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
+auto swap(InlinedVector<T, N, A>& a,
+          InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) -> void {
   a.swap(b);
 }
 
@@ -1300,8 +1299,8 @@
 //
 // Tests the equivalency of the contents of two inlined vectors.
 template <typename T, size_t N, typename A>
-bool operator==(const InlinedVector<T, N, A>& a,
-                const InlinedVector<T, N, A>& b) {
+auto operator==(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) -> bool {
   return absl::equal(a.begin(), a.end(), b.begin(), b.end());
 }
 
@@ -1309,8 +1308,8 @@
 //
 // Tests the inequality of the contents of two inlined vectors.
 template <typename T, size_t N, typename A>
-bool operator!=(const InlinedVector<T, N, A>& a,
-                const InlinedVector<T, N, A>& b) {
+auto operator!=(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) -> bool {
   return !(a == b);
 }
 
@@ -1319,8 +1318,8 @@
 // Tests whether the contents of one inlined vector are less than the contents
 // of another through a lexicographical comparison operation.
 template <typename T, size_t N, typename A>
-bool operator<(const InlinedVector<T, N, A>& a,
-               const InlinedVector<T, N, A>& b) {
+auto operator<(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b)
+    -> bool {
   return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
 }
 
@@ -1329,8 +1328,8 @@
 // Tests whether the contents of one inlined vector are greater than the
 // contents of another through a lexicographical comparison operation.
 template <typename T, size_t N, typename A>
-bool operator>(const InlinedVector<T, N, A>& a,
-               const InlinedVector<T, N, A>& b) {
+auto operator>(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b)
+    -> bool {
   return b < a;
 }
 
@@ -1339,8 +1338,8 @@
 // Tests whether the contents of one inlined vector are less than or equal to
 // the contents of another through a lexicographical comparison operation.
 template <typename T, size_t N, typename A>
-bool operator<=(const InlinedVector<T, N, A>& a,
-                const InlinedVector<T, N, A>& b) {
+auto operator<=(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) -> bool {
   return !(b < a);
 }
 
@@ -1349,8 +1348,8 @@
 // Tests whether the contents of one inlined vector are greater than or equal to
 // the contents of another through a lexicographical comparison operation.
 template <typename T, size_t N, typename A>
-bool operator>=(const InlinedVector<T, N, A>& a,
-                const InlinedVector<T, N, A>& b) {
+auto operator>=(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) -> bool {
   return !(a < b);
 }
 
@@ -1359,11 +1358,12 @@
 // Provides `absl::Hash` support for inlined vectors. You do not normally call
 // this function directly.
 template <typename H, typename TheT, size_t TheN, typename TheA>
-H AbslHashValue(H hash, const InlinedVector<TheT, TheN, TheA>& vector) {
-  auto p = vector.data();
-  auto n = vector.size();
-  return H::combine(H::combine_contiguous(std::move(hash), p, n), n);
+auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H {
+  auto p = v.data();
+  auto n = v.size();
+  return H::combine(H::combine_contiguous(std::move(h), p, n), n);
 }
+}  // namespace absl
 
 // -----------------------------------------------------------------------------
 // Implementation of InlinedVector
@@ -1371,6 +1371,4 @@
 // Do not depend on any below implementation details!
 // -----------------------------------------------------------------------------
 
-}  // namespace absl
-
 #endif  // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
index a3ad0f8..9ca93b27 100644
--- a/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
+++ b/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
@@ -159,15 +159,14 @@
 
 struct LargeCopyableSwappable {
   LargeCopyableSwappable() : d(1024, 17) {}
+
   LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
-  LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
 
   LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
     using std::swap;
     swap(*this, o);
     return *this;
   }
-  LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
 
   friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
     using std::swap;
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
index 9408ee9..5b1527e 100644
--- a/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
+++ b/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
@@ -1762,4 +1762,23 @@
   }
 }
 
+TEST(InlinedVectorTest, AbslHashValueWorks) {
+  using V = absl::InlinedVector<int, 4>;
+  std::vector<V> cases;
+
+  // Generate a variety of vectors some of these are small enough for the inline
+  // space but are stored out of line.
+  for (int i = 0; i < 10; ++i) {
+    V v;
+    for (int j = 0; j < i; ++j) {
+      v.push_back(j);
+    }
+    cases.push_back(v);
+    v.resize(i % 4);
+    cases.push_back(v);
+  }
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
+}
+
 }  // anonymous namespace
diff --git a/third_party/abseil-cpp/absl/container/internal/common.h b/third_party/abseil-cpp/absl/container/internal/common.h
index a6dc9103..c781656 100644
--- a/third_party/abseil-cpp/absl/container/internal/common.h
+++ b/third_party/abseil-cpp/absl/container/internal/common.h
@@ -18,6 +18,7 @@
 #include <type_traits>
 
 #include "absl/meta/type_traits.h"
+#include "absl/types/optional.h"
 
 namespace absl {
 namespace container_internal {
@@ -42,7 +43,140 @@
   using type = key_type;
 };
 
+// The node_handle concept from C++17.
+// We specialize node_handle for sets and maps. node_handle_base holds the
+// common API of both.
+template <typename PolicyTraits, typename Alloc>
+class node_handle_base {
+ protected:
+  using slot_type = typename PolicyTraits::slot_type;
+
+ public:
+  using allocator_type = Alloc;
+
+  constexpr node_handle_base() {}
+  node_handle_base(node_handle_base&& other) noexcept {
+    *this = std::move(other);
+  }
+  ~node_handle_base() { destroy(); }
+  node_handle_base& operator=(node_handle_base&& other) noexcept {
+    destroy();
+    if (!other.empty()) {
+      alloc_ = other.alloc_;
+      PolicyTraits::transfer(alloc(), slot(), other.slot());
+      other.reset();
+    }
+    return *this;
+  }
+
+  bool empty() const noexcept { return !alloc_; }
+  explicit operator bool() const noexcept { return !empty(); }
+  allocator_type get_allocator() const { return *alloc_; }
+
+ protected:
+  friend struct CommonAccess;
+
+  node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
+    PolicyTraits::transfer(alloc(), slot(), s);
+  }
+
+  void destroy() {
+    if (!empty()) {
+      PolicyTraits::destroy(alloc(), slot());
+      reset();
+    }
+  }
+
+  void reset() {
+    assert(alloc_.has_value());
+    alloc_ = absl::nullopt;
+  }
+
+  slot_type* slot() const {
+    assert(!empty());
+    return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
+  }
+  allocator_type* alloc() { return std::addressof(*alloc_); }
+
+ private:
+  absl::optional<allocator_type> alloc_;
+  mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
+      slot_space_;
+};
+
+// For sets.
+template <typename Policy, typename PolicyTraits, typename Alloc,
+          typename = void>
+class node_handle : public node_handle_base<PolicyTraits, Alloc> {
+  using Base = typename node_handle::node_handle_base;
+
+ public:
+  using value_type = typename PolicyTraits::value_type;
+
+  constexpr node_handle() {}
+
+  value_type& value() const { return PolicyTraits::element(this->slot()); }
+
+ private:
+  friend struct CommonAccess;
+
+  node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
+};
+
+// For maps.
+template <typename Policy, typename PolicyTraits, typename Alloc>
+class node_handle<Policy, PolicyTraits, Alloc,
+                  absl::void_t<typename Policy::mapped_type>>
+    : public node_handle_base<PolicyTraits, Alloc> {
+  using Base = typename node_handle::node_handle_base;
+
+ public:
+  using key_type = typename Policy::key_type;
+  using mapped_type = typename Policy::mapped_type;
+
+  constexpr node_handle() {}
+
+  auto key() const -> decltype(PolicyTraits::key(this->slot())) {
+    return PolicyTraits::key(this->slot());
+  }
+
+  mapped_type& mapped() const {
+    return PolicyTraits::value(&PolicyTraits::element(this->slot()));
+  }
+
+ private:
+  friend struct CommonAccess;
+
+  node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
+};
+
+// Provide access to non-public node-handle functions.
+struct CommonAccess {
+  template <typename Node>
+  static auto GetSlot(const Node& node) -> decltype(node.slot()) {
+    return node.slot();
+  }
+
+  template <typename Node>
+  static void Reset(Node* node) {
+    node->reset();
+  }
+
+  template <typename T, typename... Args>
+  static T Make(Args&&... args) {
+    return T(std::forward<Args>(args)...);
+  }
+};
+
+// Implement the insert_return_type<> concept of C++17.
+template <class Iterator, class NodeType>
+struct InsertReturnType {
+  Iterator position;
+  bool inserted;
+  NodeType node;
+};
+
 }  // namespace container_internal
-}   // namespace absl
+}  // namespace absl
 
 #endif  // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_force_sampling.cc b/third_party/abseil-cpp/absl/container/internal/hashtablez_force_sampling.cc
new file mode 100644
index 0000000..868976e
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_force_sampling.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+namespace absl {
+namespace container_internal {
+
+// See hashtablez_sampler.h for details.
+extern "C" const bool kAbslContainerInternalSampleEverything = true;
+
+}  // namespace container_internal
+}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_force_sampling_test.cc b/third_party/abseil-cpp/absl/container/internal/hashtablez_force_sampling_test.cc
new file mode 100644
index 0000000..9ff1046
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_force_sampling_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstddef>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/container/internal/hashtablez_sampler.h"
+
+namespace absl {
+namespace container_internal {
+
+class HashtablezInfoHandlePeer {
+ public:
+  static bool IsSampled(const HashtablezInfoHandle& h) {
+    return h.info_ != nullptr;
+  }
+};
+
+namespace {
+
+bool samples[3]{true, true, true};
+
+// We do this test in a global object to test that this works even before main.
+struct Global {
+  Global() {
+    // By default it is sampled.
+    samples[0] = HashtablezInfoHandlePeer::IsSampled(Sample());
+
+    // Even with a large parameter, it is sampled.
+    SetHashtablezSampleParameter(100);
+    samples[1] = HashtablezInfoHandlePeer::IsSampled(Sample());
+
+    // Even if we turn it off, it is still sampled.
+    SetHashtablezEnabled(false);
+    samples[2] = HashtablezInfoHandlePeer::IsSampled(Sample());
+  }
+} global;
+
+TEST(kAbslContainerInternalSampleEverything, Works) {
+  EXPECT_THAT(samples, testing::Each(true));
+  EXPECT_TRUE(kAbslContainerInternalSampleEverything);
+  // One more after main()
+  EXPECT_TRUE(HashtablezInfoHandlePeer::IsSampled(Sample()));
+}
+
+}  // namespace
+}  // namespace container_internal
+}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc
index 1ba95645..dc66924 100644
--- a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc
@@ -93,7 +93,7 @@
   // under piii debug for some binaries.
   double q = static_cast<uint32_t>(rng >> (prng_mod_power - 26)) + 1.0;
   // Put the computed p-value through the CDF of a geometric.
-  double interval = (std::log2(q) - 26) * (-std::log(2.0) * mean);
+  double interval = (log2(q) - 26) * (-std::log(2.0) * mean);
 
   // Very large values of interval overflow int64_t. If we happen to
   // hit such improbable condition, we simply cheat and clamp interval
@@ -116,6 +116,11 @@
   return *sampler;
 }
 
+HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback(
+    DisposeCallback f) {
+  return dispose_.exchange(f, std::memory_order_relaxed);
+}
+
 HashtablezInfo::HashtablezInfo() { PrepareForSampling(); }
 HashtablezInfo::~HashtablezInfo() = default;
 
@@ -138,7 +143,7 @@
 }
 
 HashtablezSampler::HashtablezSampler()
-    : dropped_samples_(0), size_estimate_(0), all_(nullptr) {
+    : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) {
   absl::MutexLock l(&graveyard_.init_mu);
   graveyard_.dead = &graveyard_;
 }
@@ -161,6 +166,10 @@
 }
 
 void HashtablezSampler::PushDead(HashtablezInfo* sample) {
+  if (auto* dispose = dispose_.load(std::memory_order_relaxed)) {
+    dispose(*sample);
+  }
+
   absl::MutexLock graveyard_lock(&graveyard_.init_mu);
   absl::MutexLock sample_lock(&sample->init_mu);
   sample->dead = graveyard_.dead;
@@ -220,6 +229,11 @@
 }
 
 HashtablezInfo* SampleSlow(int64_t* next_sample) {
+  if (kAbslContainerInternalSampleEverything) {
+    *next_sample = 1;
+    return HashtablezSampler::Global().Register();
+  }
+
   bool first = *next_sample < 0;
   *next_sample = GetGeometricVariable(
       g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
@@ -240,7 +254,7 @@
 }
 
 #if ABSL_PER_THREAD_TLS == 1
-ABSL_PER_THREAD_TLS_KEYWORD int64_t next_sample = 0;
+ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
 #endif  // ABSL_PER_THREAD_TLS == 1
 
 void UnsampleSlow(HashtablezInfo* info) {
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
index c42f184..8b81653a5 100644
--- a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
@@ -146,23 +146,23 @@
   HashtablezInfo* info_;
 };
 
-// Returns an RAII sampling handle that manages registration and unregistation
-// with the global sampler.
 #if ABSL_PER_THREAD_TLS == 1
-extern ABSL_PER_THREAD_TLS_KEYWORD int64_t next_sample;
+extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
 #endif  // ABSL_PER_THREAD_TLS
 
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
 inline HashtablezInfoHandle Sample() {
 #if ABSL_PER_THREAD_TLS == 0
   static auto* mu = new absl::Mutex;
-  static int64_t next_sample = 0;
+  static int64_t global_next_sample = 0;
   absl::MutexLock l(mu);
 #endif  // !ABSL_HAVE_THREAD_LOCAL
 
-  if (ABSL_PREDICT_TRUE(--next_sample > 0)) {
+  if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
     return HashtablezInfoHandle(nullptr);
   }
-  return HashtablezInfoHandle(SampleSlow(&next_sample));
+  return HashtablezInfoHandle(SampleSlow(&global_next_sample));
 }
 
 // Holds samples and their associated stack traces with a soft limit of
@@ -183,6 +183,13 @@
   // Unregisters the sample.
   void Unregister(HashtablezInfo* sample);
 
+  // The dispose callback will be called on all samples the moment they are
+  // being unregistered. Only affects samples that are unregistered after the
+  // callback has been set.
+  // Returns the previous callback.
+  using DisposeCallback = void (*)(const HashtablezInfo&);
+  DisposeCallback SetDisposeCallback(DisposeCallback f);
+
   // Iterates over all the registered `StackInfo`s.  Returning the number of
   // samples that have been dropped.
   int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& f);
@@ -222,6 +229,8 @@
   //
   std::atomic<HashtablezInfo*> all_;
   HashtablezInfo graveyard_;
+
+  std::atomic<DisposeCallback> dispose_;
 };
 
 // Enables or disables sampling for Swiss tables.
@@ -233,6 +242,13 @@
 // Sets a soft max for the number of samples that will be kept.
 void SetHashtablezMaxSamples(int32_t max);
 
+// Configuration override.
+// This allows process-wide sampling without depending on order of
+// initialization of static storage duration objects.
+// The definition of this constant is weak, which allows us to inject a
+// different value for it at link time.
+extern "C" const bool kAbslContainerInternalSampleEverything;
+
 }  // namespace container_internal
 }  // namespace absl
 
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
new file mode 100644
index 0000000..38a3f26
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include "absl/base/attributes.h"
+
+namespace absl {
+namespace container_internal {
+
+// See hashtablez_sampler.h for details.
+extern "C" ABSL_ATTRIBUTE_WEAK const bool
+    kAbslContainerInternalSampleEverything = false;
+
+}  // namespace container_internal
+}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc
index 31e7641..f9ee941a 100644
--- a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc
@@ -302,6 +302,31 @@
   stop.Notify();
 }
 
+TEST(HashtablezSamplerTest, Callback) {
+  HashtablezSampler sampler;
+
+  auto* info1 = Register(&sampler, 1);
+  auto* info2 = Register(&sampler, 2);
+
+  static const HashtablezInfo* expected;
+
+  auto callback = [](const HashtablezInfo& info) {
+    // We can't use `info` outside of this callback because the object will be
+    // disposed as soon as we return from here.
+    EXPECT_EQ(&info, expected);
+  };
+
+  // Set the callback.
+  EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
+  expected = info1;
+  sampler.Unregister(info1);
+
+  // Unset the callback.
+  EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
+  expected = nullptr;  // no more calls.
+  sampler.Unregister(info2);
+}
+
 }  // namespace
 }  // namespace container_internal
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
index 8f6469f..a5d0cae 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
@@ -115,7 +115,6 @@
 #include "absl/container/internal/layout.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
-#include "absl/types/optional.h"
 #include "absl/utility/utility.h"
 
 namespace absl {
@@ -502,126 +501,6 @@
   return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
 }
 
-// The node_handle concept from C++17.
-// We specialize node_handle for sets and maps. node_handle_base holds the
-// common API of both.
-template <typename Policy, typename Alloc>
-class node_handle_base {
- protected:
-  using PolicyTraits = hash_policy_traits<Policy>;
-  using slot_type = typename PolicyTraits::slot_type;
-
- public:
-  using allocator_type = Alloc;
-
-  constexpr node_handle_base() {}
-  node_handle_base(node_handle_base&& other) noexcept {
-    *this = std::move(other);
-  }
-  ~node_handle_base() { destroy(); }
-  node_handle_base& operator=(node_handle_base&& other) {
-    destroy();
-    if (!other.empty()) {
-      alloc_ = other.alloc_;
-      PolicyTraits::transfer(alloc(), slot(), other.slot());
-      other.reset();
-    }
-    return *this;
-  }
-
-  bool empty() const noexcept { return !alloc_; }
-  explicit operator bool() const noexcept { return !empty(); }
-  allocator_type get_allocator() const { return *alloc_; }
-
- protected:
-  template <typename, typename, typename, typename>
-  friend class raw_hash_set;
-
-  node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
-    PolicyTraits::transfer(alloc(), slot(), s);
-  }
-
-  void destroy() {
-    if (!empty()) {
-      PolicyTraits::destroy(alloc(), slot());
-      reset();
-    }
-  }
-
-  void reset() {
-    assert(alloc_.has_value());
-    alloc_ = absl::nullopt;
-  }
-
-  slot_type* slot() const {
-    assert(!empty());
-    return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
-  }
-  allocator_type* alloc() { return std::addressof(*alloc_); }
-
- private:
-  absl::optional<allocator_type> alloc_;
-  mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
-      slot_space_;
-};
-
-// For sets.
-template <typename Policy, typename Alloc, typename = void>
-class node_handle : public node_handle_base<Policy, Alloc> {
-  using Base = typename node_handle::node_handle_base;
-
- public:
-  using value_type = typename Base::PolicyTraits::value_type;
-
-  constexpr node_handle() {}
-
-  value_type& value() const {
-    return Base::PolicyTraits::element(this->slot());
-  }
-
- private:
-  template <typename, typename, typename, typename>
-  friend class raw_hash_set;
-
-  node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
-};
-
-// For maps.
-template <typename Policy, typename Alloc>
-class node_handle<Policy, Alloc, absl::void_t<typename Policy::mapped_type>>
-    : public node_handle_base<Policy, Alloc> {
-  using Base = typename node_handle::node_handle_base;
-
- public:
-  using key_type = typename Policy::key_type;
-  using mapped_type = typename Policy::mapped_type;
-
-  constexpr node_handle() {}
-
-  auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) {
-    return Base::PolicyTraits::key(this->slot());
-  }
-
-  mapped_type& mapped() const {
-    return Base::PolicyTraits::value(
-        &Base::PolicyTraits::element(this->slot()));
-  }
-
- private:
-  template <typename, typename, typename, typename>
-  friend class raw_hash_set;
-
-  node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
-};
-
-// Implement the insert_return_type<> concept of C++17.
-template <class Iterator, class NodeType>
-struct insert_return_type {
-  Iterator position;
-  bool inserted;
-  NodeType node;
-};
-
 // Policy: a policy defines how to perform different operations on
 // the slots of the hashtable (see hash_policy_traits.h for the full interface
 // of policy).
@@ -828,7 +707,8 @@
     iterator inner_;
   };
 
-  using node_type = container_internal::node_handle<Policy, Alloc>;
+  using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
+  using insert_return_type = InsertReturnType<iterator, node_type>;
 
   raw_hash_set() noexcept(
       std::is_nothrow_default_constructible<hasher>::value&&
@@ -1035,7 +915,7 @@
   size_t capacity() const { return capacity_; }
   size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
 
-  void clear() {
+  ABSL_ATTRIBUTE_REINITIALIZES void clear() {
     // Iterating over this container is O(bucket_count()). When bucket_count()
     // is much greater than size(), iteration becomes prohibitively expensive.
     // For clear() it is more important to reuse the allocated array when the
@@ -1136,13 +1016,14 @@
     insert(ilist.begin(), ilist.end());
   }
 
-  insert_return_type<iterator, node_type> insert(node_type&& node) {
+  insert_return_type insert(node_type&& node) {
     if (!node) return {end(), false, node_type()};
-    const auto& elem = PolicyTraits::element(node.slot());
+    const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
     auto res = PolicyTraits::apply(
-        InsertSlot<false>{*this, std::move(*node.slot())}, elem);
+        InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
+        elem);
     if (res.second) {
-      node.reset();
+      CommonAccess::Reset(&node);
       return {res.first, true, node_type()};
     } else {
       return {res.first, false, std::move(node)};
@@ -1306,7 +1187,8 @@
   }
 
   node_type extract(const_iterator position) {
-    node_type node(alloc_ref(), position.inner_.slot_);
+    auto node =
+        CommonAccess::Make<node_type>(alloc_ref(), position.inner_.slot_);
     erase_meta_only(position);
     return node;
   }
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
index d9f1826..7adcc96 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
@@ -1706,7 +1706,7 @@
   EXPECT_FALSE(node.empty());
 
   StringTable t2;
-  auto res = t2.insert(std::move(node));
+  StringTable::insert_return_type res = t2.insert(std::move(node));
   EXPECT_TRUE(res.inserted);
   EXPECT_THAT(*res.position, Pair(k0, ""));
   EXPECT_FALSE(res.node);
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
index 8029fbe..dcb5269 100644
--- a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
+++ b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
@@ -392,16 +392,20 @@
 extern "C" {
 inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
   void *pc = nullptr;
-#if defined(__i386__) || defined(__x86_64__)
-  __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#if defined(__i386__)
+  __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
+#elif defined(__x86_64__)
+  __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
 #endif
   return pc;
 }
 
 void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
   void *pc = nullptr;
-#if defined(__i386__) || defined(__x86_64__)
-  __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#if defined(__i386__)
+  __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
+#elif defined(__x86_64__)
+  __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
 #endif
   return pc;
 }
diff --git a/third_party/abseil-cpp/absl/hash/hash_test.cc b/third_party/abseil-cpp/absl/hash/hash_test.cc
index 224832b..a5af93a 100644
--- a/third_party/abseil-cpp/absl/hash/hash_test.cc
+++ b/third_party/abseil-cpp/absl/hash/hash_test.cc
@@ -15,6 +15,7 @@
 #include "absl/hash/hash.h"
 
 #include <array>
+#include <bitset>
 #include <cstring>
 #include <deque>
 #include <forward_list>
@@ -84,6 +85,327 @@
                                 uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
 
+enum LegacyEnum { kValue1, kValue2, kValue3 };
+
+enum class EnumClass { kValue4, kValue5, kValue6 };
+
+TEST(HashValueTest, EnumAndBool) {
+  EXPECT_TRUE((is_hashable<LegacyEnum>::value));
+  EXPECT_TRUE((is_hashable<EnumClass>::value));
+  EXPECT_TRUE((is_hashable<bool>::value));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3)));
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6)));
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(true, false)));
+}
+
+TEST(HashValueTest, FloatingPoint) {
+  EXPECT_TRUE((is_hashable<float>::value));
+  EXPECT_TRUE((is_hashable<double>::value));
+  EXPECT_TRUE((is_hashable<long double>::value));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(),
+                      -std::numeric_limits<float>::infinity())));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(),
+                      -std::numeric_limits<double>::infinity())));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      // Add some values with small exponent to test that NORMAL values also
+      // append their category.
+      .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L,
+      17 * static_cast<long double>(std::numeric_limits<double>::max()),
+      std::numeric_limits<long double>::infinity(),
+      -std::numeric_limits<long double>::infinity())));
+}
+
+TEST(HashValueTest, Pointer) {
+  EXPECT_TRUE((is_hashable<int*>::value));
+
+  int i;
+  int* ptr = &i;
+  int* n = nullptr;
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(&i, ptr, nullptr, ptr + 1, n)));
+}
+
+// TODO(EricWF): MSVC 15 has a bug that causes it to incorrectly evaluate the
+// SFINAE in internal/hash.h, causing this test to fail.
+#if !defined(_MSC_VER)
+TEST(HashValueTest, PairAndTuple) {
+  EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
+  EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
+  EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value));
+  EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0),
+      std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42))));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42),
+                      std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0),
+                      std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9),
+                      std::make_tuple(0, 0, -42))));
+
+  // Test that tuples of lvalue references work (so we need a few lvalues):
+  int a = 0, b = 1, c = 17, d = 23;
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      std::tie(a, a), std::tie(a, b), std::tie(b, c), std::tie(c, d))));
+
+  // Test that tuples of rvalue references work:
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42),
+      std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0),
+      std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
+      std::forward_as_tuple(0, 0, -42))));
+}
+#endif  // !defined(_MSC_VER)
+
+TEST(HashValueTest, CombineContiguousWorks) {
+  std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)};
+  std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)};
+
+  auto vh1 = SpyHash(v1);
+  auto vh2 = SpyHash(v2);
+  EXPECT_NE(vh1, vh2);
+}
+
+struct DummyDeleter {
+  template <typename T>
+  void operator() (T* ptr) {}
+};
+
+struct SmartPointerEq {
+  template <typename T, typename U>
+  bool operator()(const T& t, const U& u) const {
+    return GetPtr(t) == GetPtr(u);
+  }
+
+  template <typename T>
+  static auto GetPtr(const T& t) -> decltype(&*t) {
+    return t ? &*t : nullptr;
+  }
+
+  static std::nullptr_t GetPtr(std::nullptr_t) { return nullptr; }
+};
+
+TEST(HashValueTest, SmartPointers) {
+  EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value));
+  EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value));
+  EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value));
+
+  int i, j;
+  std::unique_ptr<int, DummyDeleter> unique1(&i);
+  std::unique_ptr<int, DummyDeleter> unique2(&i);
+  std::unique_ptr<int, DummyDeleter> unique_other(&j);
+  std::unique_ptr<int, DummyDeleter> unique_null;
+
+  std::shared_ptr<int> shared1(&i, DummyDeleter());
+  std::shared_ptr<int> shared2(&i, DummyDeleter());
+  std::shared_ptr<int> shared_other(&j, DummyDeleter());
+  std::shared_ptr<int> shared_null;
+
+  // Sanity check of the Eq function.
+  ASSERT_TRUE(SmartPointerEq{}(unique1, shared1));
+  ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other));
+  ASSERT_TRUE(SmartPointerEq{}(unique_null, nullptr));
+  ASSERT_FALSE(SmartPointerEq{}(shared2, nullptr));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::forward_as_tuple(&i, nullptr,                    //
+                            unique1, unique2, unique_null,  //
+                            absl::make_unique<int>(),       //
+                            shared1, shared2, shared_null,  //
+                            std::make_shared<int>()),
+      SmartPointerEq{}));
+}
+
+TEST(HashValueTest, FunctionPointer) {
+  using Func = int (*)();
+  EXPECT_TRUE(is_hashable<Func>::value);
+
+  Func p1 = [] { return 2; }, p2 = [] { return 1; };
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(p1, p2, nullptr)));
+}
+
+struct WrapInTuple {
+  template <typename T>
+  std::tuple<int, T, size_t> operator()(const T& t) const {
+    return std::make_tuple(7, t, 0xdeadbeef);
+  }
+};
+
+TEST(HashValueTest, Strings) {
+  EXPECT_TRUE((is_hashable<std::string>::value));
+  EXPECT_TRUE((is_hashable<std::string>::value));
+
+  const std::string small = "foo";
+  const std::string dup = "foofoo";
+  const std::string large = "large";
+  const std::string huge = std::string(5000, 'a');
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      std::string(), absl::string_view(),
+      std::string(""), absl::string_view(""),
+      std::string(small), absl::string_view(small),
+      std::string(dup), absl::string_view(dup),
+      std::string(large), absl::string_view(large),
+      std::string(huge), absl::string_view(huge))));
+
+  // Also check that nested types maintain the same hash.
+  const WrapInTuple t{};
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      //
+      t(std::string()), t(absl::string_view()),
+      t(std::string("")), t(absl::string_view("")),
+      t(std::string(small)), t(absl::string_view(small)),
+      t(std::string(dup)), t(absl::string_view(dup)),
+      t(std::string(large)), t(absl::string_view(large)),
+      t(std::string(huge)), t(absl::string_view(huge)))));
+
+  // Make sure that hashing a `const char*` does not use its std::string-value.
+  EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
+            SpyHash(absl::string_view("ABC")));
+}
+
+// TODO(EricWF): MSVC 15 has a bug that causes it to incorrectly evaluate the
+// SFINAE in internal/hash.h, causing this test to fail.
+#if !defined(_MSC_VER)
+TEST(HashValueTest, StdArray) {
+  EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
+}
+#endif  // !defined(_MSC_VER)
+
+TEST(HashValueTest, StdBitset) {
+  EXPECT_TRUE((is_hashable<std::bitset<257>>::value));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      {std::bitset<2>("00"), std::bitset<2>("01"), std::bitset<2>("10"),
+       std::bitset<2>("11")}));
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      {std::bitset<5>("10101"), std::bitset<5>("10001"), std::bitset<5>()}));
+
+  constexpr int kNumBits = 256;
+  std::array<std::string, 6> bit_strings;
+  bit_strings.fill(std::string(kNumBits, '1'));
+  bit_strings[1][0] = '0';
+  bit_strings[2][1] = '0';
+  bit_strings[3][kNumBits / 3] = '0';
+  bit_strings[4][kNumBits - 2] = '0';
+  bit_strings[5][kNumBits - 1] = '0';
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      {std::bitset<kNumBits>(bit_strings[0].c_str()),
+       std::bitset<kNumBits>(bit_strings[1].c_str()),
+       std::bitset<kNumBits>(bit_strings[2].c_str()),
+       std::bitset<kNumBits>(bit_strings[3].c_str()),
+       std::bitset<kNumBits>(bit_strings[4].c_str()),
+       std::bitset<kNumBits>(bit_strings[5].c_str())}));
+}  // namespace
+
+template <typename T>
+class HashValueSequenceTest : public testing::Test {
+};
+TYPED_TEST_SUITE_P(HashValueSequenceTest);
+
+TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
+  EXPECT_TRUE((is_hashable<TypeParam>::value));
+
+  using ValueType = typename TypeParam::value_type;
+  auto a = static_cast<ValueType>(0);
+  auto b = static_cast<ValueType>(23);
+  auto c = static_cast<ValueType>(42);
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(TypeParam(), TypeParam{}, TypeParam{a, b, c},
+                      TypeParam{a, b}, TypeParam{b, c})));
+}
+
+REGISTER_TYPED_TEST_CASE_P(HashValueSequenceTest, BasicUsage);
+using IntSequenceTypes =
+    testing::Types<std::deque<int>, std::forward_list<int>, std::list<int>,
+                   std::vector<int>, std::vector<bool>, std::set<int>,
+                   std::multiset<int>>;
+INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
+
+// Private type that only supports AbslHashValue to make sure our chosen hash
+// implentation is recursive within absl::Hash.
+// It uses std::abs() on the value to provide different bitwise representations
+// of the same logical value.
+struct Private {
+  int i;
+  template <typename H>
+  friend H AbslHashValue(H h, Private p) {
+    return H::combine(std::move(h), std::abs(p.i));
+  }
+
+  friend bool operator==(Private a, Private b) {
+    return std::abs(a.i) == std::abs(b.i);
+  }
+
+  friend std::ostream& operator<<(std::ostream& o, Private p) {
+    return o << p.i;
+  }
+};
+
+TEST(HashValueTest, PrivateSanity) {
+  // Sanity check that Private is working as the tests below expect it to work.
+  EXPECT_TRUE(is_hashable<Private>::value);
+  EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1}));
+  EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1}));
+}
+
+TEST(HashValueTest, Optional) {
+  EXPECT_TRUE(is_hashable<absl::optional<Private>>::value);
+
+  using O = absl::optional<Private>;
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}})));
+}
+
+TEST(HashValueTest, Variant) {
+  using V = absl::variant<Private, std::string>;
+  EXPECT_TRUE(is_hashable<V>::value);
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD"))));
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+  struct S {};
+  EXPECT_FALSE(is_hashable<absl::variant<S>>::value);
+#endif
+}
+
+// TODO(EricWF): MSVC 15 has a bug that causes it to incorrectly evaluate the
+// SFINAE in internal/hash.h, causing this test to fail.
+#if !defined(_MSC_VER)
+TEST(HashValueTest, Maps) {
+  EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value));
+
+  using M = std::map<int, std::string>;
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      M{}, M{{0, "foo"}}, M{{1, "foo"}}, M{{0, "bar"}}, M{{1, "bar"}},
+      M{{0, "foo"}, {42, "bar"}}, M{{1, "foo"}, {42, "bar"}},
+      M{{1, "foo"}, {43, "bar"}}, M{{1, "foo"}, {43, "baz"}})));
+
+  using MM = std::multimap<int, std::string>;
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      MM{}, MM{{0, "foo"}}, MM{{1, "foo"}}, MM{{0, "bar"}}, MM{{1, "bar"}},
+      MM{{0, "foo"}, {0, "bar"}}, MM{{0, "bar"}, {0, "foo"}},
+      MM{{0, "foo"}, {42, "bar"}}, MM{{1, "foo"}, {42, "bar"}},
+      MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
+}
+#endif  // !defined(_MSC_VER)
+
 template <typename T, typename = void>
 struct IsHashCallble : std::false_type {};
 
@@ -108,7 +430,8 @@
   EXPECT_TRUE(IsHashCallble<int>::value);
   EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value);
 }
-#if ABSL_HASH_INTERNAL_CAN_POISON_ && !defined(__APPLE__)
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 TEST(IsHashableTest, PoisonHash) {
   struct X {};
   EXPECT_FALSE((is_hashable<X>::value));
@@ -120,7 +443,7 @@
   EXPECT_FALSE(IsHashCallble<X>::value);
   EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value);
 }
-#endif  // ABSL_HASH_INTERNAL_CAN_POISON_
+#endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 
 // Hashable types
 //
@@ -245,13 +568,13 @@
 }
 
 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
-#if ABSL_HASH_INTERNAL_CAN_POISON_
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
   // is_hashable is false if we don't support any of the hooks.
   using type = CustomHashType<>;
   EXPECT_FALSE(is_hashable<type>());
   EXPECT_FALSE(is_hashable<const type>());
   EXPECT_FALSE(is_hashable<const type&>());
-#endif  // ABSL_HASH_INTERNAL_CAN_POISON_
+#endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 }
 
 template <InvokeTag Tag, typename... T>
diff --git a/third_party/abseil-cpp/absl/hash/internal/hash.h b/third_party/abseil-cpp/absl/hash/internal/hash.h
index 6c00f35..ba6d746 100644
--- a/third_party/abseil-cpp/absl/hash/internal/hash.h
+++ b/third_party/abseil-cpp/absl/hash/internal/hash.h
@@ -541,17 +541,8 @@
 //   * If is_uniquely_represented, hash bytes directly.
 //   * ADL AbslHashValue(H, const T&) call.
 //   * std::hash<T>
-
-// In MSVC we can't probe std::hash or stdext::hash because it triggers a
-// static_assert instead of failing substitution.
-#if defined(_MSC_VER)
-#define ABSL_HASH_INTERNAL_CAN_POISON_ 0
-#else   // _MSC_VER
-#define ABSL_HASH_INTERNAL_CAN_POISON_ 1
-#endif  // _MSC_VER
-
 #if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \
-    ABSL_HASH_INTERNAL_CAN_POISON_
+    ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1
 #else
 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0
@@ -616,13 +607,7 @@
 #endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
 
   template <typename U>
-  using ProbeStdHash =
-#if ABSL_HASH_INTERNAL_CAN_POISON_
-      std::is_convertible<decltype(std::hash<U>()(std::declval<const U&>())),
-                          size_t>;
-#else   // ABSL_HASH_INTERNAL_CAN_POISON_
-      std::true_type;
-#endif  // ABSL_HASH_INTERNAL_CAN_POISON_
+  using ProbeStdHash = absl::type_traits_internal::IsHashable<U>;
 
   template <typename U>
   using ProbeNone = std::true_type;
diff --git a/third_party/abseil-cpp/absl/hash/internal/spy_hash_state.h b/third_party/abseil-cpp/absl/hash/internal/spy_hash_state.h
index 03d795b..e7d1dfe 100644
--- a/third_party/abseil-cpp/absl/hash/internal/spy_hash_state.h
+++ b/third_party/abseil-cpp/absl/hash/internal/spy_hash_state.h
@@ -200,7 +200,7 @@
 template <
     typename T, typename U,
     // Only trigger for when (T != U),
-    absl::enable_if_t<!std::is_same<T, U>::value, int> = 0,
+    typename = absl::enable_if_t<!std::is_same<T, U>::value>,
     // This statement works in two ways:
     //  - First, it instantiates RunOnStartup and forces the initialization of
     //    `run`, which set the global variable.
diff --git a/third_party/abseil-cpp/absl/meta/type_traits.h b/third_party/abseil-cpp/absl/meta/type_traits.h
index 23ebd6ed..8885397 100644
--- a/third_party/abseil-cpp/absl/meta/type_traits.h
+++ b/third_party/abseil-cpp/absl/meta/type_traits.h
@@ -413,21 +413,73 @@
 using result_of_t = typename std::result_of<T>::type;
 
 namespace type_traits_internal {
+// In MSVC we can't probe std::hash or stdext::hash because it triggers a
+// static_assert instead of failing substitution. Libc++ prior to 4.0
+// also used a static_assert.
+//
+#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
+                          _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
+#else
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
+#endif
+
+#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 template <typename Key, typename = size_t>
+struct IsHashable : std::true_type {};
+#else   // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+template <typename Key, typename = void>
 struct IsHashable : std::false_type {};
 
 template <typename Key>
-struct IsHashable<Key,
-                  decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))>
-    : std::true_type {};
+struct IsHashable<
+    Key,
+    absl::enable_if_t<std::is_convertible<
+        decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
+        std::size_t>::value>> : std::true_type {};
+#endif  // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 
-template <typename Key>
-struct IsHashEnabled
-    : absl::conjunction<std::is_default_constructible<std::hash<Key>>,
-                        std::is_copy_constructible<std::hash<Key>>,
-                        std::is_destructible<std::hash<Key>>,
-                        absl::is_copy_assignable<std::hash<Key>>,
-                        IsHashable<Key>> {};
+struct AssertHashEnabledHelper {
+ private:
+  static void Sink(...) {}
+  struct NAT {};
+
+  template <class Key>
+  static auto GetReturnType(int)
+      -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
+  template <class Key>
+  static NAT GetReturnType(...);
+
+  template <class Key>
+  static std::nullptr_t DoIt() {
+    static_assert(IsHashable<Key>::value,
+                  "std::hash<Key> does not provide a call operator");
+    static_assert(
+        std::is_default_constructible<std::hash<Key>>::value,
+        "std::hash<Key> must be default constructible when it is enabled");
+    static_assert(
+        std::is_copy_constructible<std::hash<Key>>::value,
+        "std::hash<Key> must be copy constructible when it is enabled");
+    static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
+                  "std::hash<Key> must be copy assignable when it is enabled");
+    // is_destructible is unchecked as it's implied by each of the
+    // is_constructible checks.
+    using ReturnType = decltype(GetReturnType<Key>(0));
+    static_assert(std::is_same<ReturnType, NAT>::value ||
+                      std::is_same<ReturnType, size_t>::value,
+                  "std::hash<Key> must return size_t");
+    return nullptr;
+  }
+
+  template <class... Ts>
+  friend void AssertHashEnabled();
+};
+
+template <class... Ts>
+inline void AssertHashEnabled() {
+  using Helper = AssertHashEnabledHelper;
+  Helper::Sink(Helper::DoIt<Ts>()...);
+}
 
 }  // namespace type_traits_internal
 
diff --git a/third_party/abseil-cpp/absl/numeric/int128_test.cc b/third_party/abseil-cpp/absl/numeric/int128_test.cc
index 81c868d..4a6eb455 100644
--- a/third_party/abseil-cpp/absl/numeric/int128_test.cc
+++ b/third_party/abseil-cpp/absl/numeric/int128_test.cc
@@ -440,4 +440,29 @@
   EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max());
 }
 
+TEST(Uint128, Hash) {
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+      // Some simple values
+      absl::uint128{0},
+      absl::uint128{1},
+      ~absl::uint128{},
+      // 64 bit limits
+      absl::uint128{std::numeric_limits<int64_t>::max()},
+      absl::uint128{std::numeric_limits<uint64_t>::max()} + 0,
+      absl::uint128{std::numeric_limits<uint64_t>::max()} + 1,
+      absl::uint128{std::numeric_limits<uint64_t>::max()} + 2,
+      // Keeping high same
+      absl::uint128{1} << 62,
+      absl::uint128{1} << 63,
+      // Keeping low same
+      absl::uint128{1} << 64,
+      absl::uint128{1} << 65,
+      // 128 bit limits
+      std::numeric_limits<absl::uint128>::max(),
+      std::numeric_limits<absl::uint128>::max() - 1,
+      std::numeric_limits<absl::uint128>::min() + 1,
+      std::numeric_limits<absl::uint128>::min(),
+  }));
+}
+
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
index 758adb7a..a89295d 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
@@ -53,7 +53,8 @@
         // "A negative field width is taken as a '-' flag followed by a
         // positive field width."
         force_left = true;
-        width = -width;
+        // Make sure we don't overflow the width when negating it.
+        width = -std::max(width, -std::numeric_limits<int>::max());
       }
     }
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
index 4757573..ba6470e 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
@@ -1,6 +1,7 @@
 #include "absl/strings/internal/str_format/bind.h"
 
 #include <string.h>
+#include <limits>
 
 #include "gtest/gtest.h"
 
@@ -91,6 +92,20 @@
   }
 }
 
+TEST_F(FormatBindTest, WidthUnderflowRegression) {
+  UnboundConversion props;
+  BoundConversion bound;
+  int next = 0;
+  const int args_i[] = {std::numeric_limits<int>::min(), 17};
+  const FormatArgImpl args[] = {FormatArgImpl(args_i[0]),
+                                FormatArgImpl(args_i[1])};
+  ASSERT_TRUE(Extract("*d", &props, &next));
+  ASSERT_TRUE(BindWithPack(&props, args, &bound));
+
+  EXPECT_EQ(bound.width(), std::numeric_limits<int>::max());
+  EXPECT_EQ(bound.arg(), args + 1);
+}
+
 TEST_F(FormatBindTest, FormatPack) {
   struct Expectation {
     int line;
diff --git a/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc b/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc
index 64cec70..07a000c 100644
--- a/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc
@@ -22,6 +22,11 @@
 
 namespace {
 
+#if !defined(__cpp_char8_t)
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++2a-compat"
+#endif
 TEST(EncodeUTF8Char, BasicFunction) {
   std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"},
                                          {0x00A3, u8"\u00A3"},
@@ -53,5 +58,9 @@
   EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1),
             absl::strings_internal::kMaxEncodedUTF8Size);
 }
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif  // !defined(__cpp_char8_t)
 
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/strings/str_format.h b/third_party/abseil-cpp/absl/strings/str_format.h
index 2d07725..060909a 100644
--- a/third_party/abseil-cpp/absl/strings/str_format.h
+++ b/third_party/abseil-cpp/absl/strings/str_format.h
@@ -186,7 +186,7 @@
 // A format string generally follows the POSIX syntax as used within the POSIX
 // `printf` specification.
 //
-// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.)
+// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.)
 //
 // In specific, the `FormatSpec` supports the following type specifiers:
 //   * `c` for characters
diff --git a/third_party/abseil-cpp/absl/strings/str_split_test.cc b/third_party/abseil-cpp/absl/strings/str_split_test.cc
index 413ad31..1ea7cad 100644
--- a/third_party/abseil-cpp/absl/strings/str_split_test.cc
+++ b/third_party/abseil-cpp/absl/strings/str_split_test.cc
@@ -647,6 +647,11 @@
   }
 }
 
+#if !defined(__cpp_char8_t)
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++2a-compat"
+#endif
 TEST(Split, UTF8) {
   // Tests splitting utf8 strings and utf8 delimiters.
   std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
@@ -673,6 +678,10 @@
     EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
   }
 }
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif  // !defined(__cpp_char8_t)
 
 TEST(Split, EmptyStringDelimiter) {
   {
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc b/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc
index e7a65cd8..60be25c 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc
+++ b/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc
@@ -67,6 +67,30 @@
   return (addr + align - 1) & ~(align - 1);
 }
 
+static void ResetThreadIdentity(base_internal::ThreadIdentity* identity) {
+  base_internal::PerThreadSynch* pts = &identity->per_thread_synch;
+  pts->next = nullptr;
+  pts->skip = nullptr;
+  pts->may_skip = false;
+  pts->waitp = nullptr;
+  pts->suppress_fatal_errors = false;
+  pts->readers = 0;
+  pts->priority = 0;
+  pts->next_priority_read_cycles = 0;
+  pts->state.store(base_internal::PerThreadSynch::State::kAvailable,
+                   std::memory_order_relaxed);
+  pts->maybe_unlocking = false;
+  pts->wake = false;
+  pts->cond_waiter = false;
+  pts->all_locks = nullptr;
+  identity->waiter_state = {};
+  identity->blocked_count_ptr = nullptr;
+  identity->ticker.store(0, std::memory_order_relaxed);
+  identity->wait_start.store(0, std::memory_order_relaxed);
+  identity->is_idle.store(false, std::memory_order_relaxed);
+  identity->next = nullptr;
+}
+
 static base_internal::ThreadIdentity* NewThreadIdentity() {
   base_internal::ThreadIdentity* identity = nullptr;
 
@@ -90,7 +114,7 @@
         RoundUp(reinterpret_cast<intptr_t>(allocation),
                 base_internal::PerThreadSynch::kAlignment));
   }
-  memset(identity, 0, sizeof(*identity));
+  ResetThreadIdentity(identity);
 
   return identity;
 }
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc b/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc
index c29d840..81cbe95 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc
+++ b/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc
@@ -152,12 +152,16 @@
 }
 
 TEST_F(PerThreadSemTest, Timeouts) {
-  absl::Time timeout = absl::Now() + absl::Milliseconds(50);
+  const absl::Duration delay = absl::Milliseconds(50);
+  const absl::Time start = absl::Now();
+  EXPECT_FALSE(Wait(start + delay));
+  const absl::Duration elapsed = absl::Now() - start;
   // Allow for a slight early return, to account for quality of implementation
   // issues on various platforms.
   const absl::Duration slop = absl::Microseconds(200);
-  EXPECT_FALSE(Wait(timeout));
-  EXPECT_LE(timeout, absl::Now() + slop);
+  EXPECT_LE(delay - slop, elapsed)
+      << "Wait returned " << delay - elapsed
+      << " early (with " << slop << " slop), start time was " << start;
 
   absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100);
   EXPECT_FALSE(Wait(negative_timeout));
diff --git a/third_party/abseil-cpp/absl/synchronization/notification_test.cc b/third_party/abseil-cpp/absl/synchronization/notification_test.cc
index d8708d55..95bde0bd 100644
--- a/third_party/abseil-cpp/absl/synchronization/notification_test.cc
+++ b/third_party/abseil-cpp/absl/synchronization/notification_test.cc
@@ -72,12 +72,16 @@
   EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
 
   const absl::Duration delay = absl::Milliseconds(50);
+  const absl::Time start = absl::Now();
+  EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
+  const absl::Duration elapsed = absl::Now() - start;
+
   // Allow for a slight early return, to account for quality of implementation
   // issues on various platforms.
   const absl::Duration slop = absl::Microseconds(200);
-  absl::Time start = absl::Now();
-  EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
-  EXPECT_LE(start + delay, absl::Now() + slop);
+  EXPECT_LE(delay - slop, elapsed)
+      << "WaitForNotificationWithTimeout returned " << delay - elapsed
+      << " early (with " << slop << " slop), start time was " << start;
 
   ThreadSafeCounter ready_counter;
   ThreadSafeCounter done_counter;
diff --git a/third_party/abseil-cpp/absl/time/clock.cc b/third_party/abseil-cpp/absl/time/clock.cc
index 74ee140..4863f64 100644
--- a/third_party/abseil-cpp/absl/time/clock.cc
+++ b/third_party/abseil-cpp/absl/time/clock.cc
@@ -379,7 +379,7 @@
 //
 // Manually mark this 'noinline' to minimize stack frame size of the fast
 // path.  Without this, sometimes a compiler may inline this big block of code
-// into the fast past.  That causes lots of register spills and reloads that
+// into the fast path.  That causes lots of register spills and reloads that
 // are unnecessary unless the slow path is taken.
 //
 // TODO(absl-team): Remove this attribute when our compiler is smart enough
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc
index aad52c2..a5c72df8 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc
@@ -13,7 +13,7 @@
 //   limitations under the License.
 
 #if !defined(HAS_STRPTIME)
-# if !defined(_MSC_VER)
+# if !defined(_MSC_VER) && !defined(__MINGW32__)
 #  define HAS_STRPTIME 1  // assume everyone has strptime() except windows
 # endif
 #endif
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc
index 2cb358d..6aa80ff 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc
@@ -921,7 +921,7 @@
     ++begin;
   }
   std::int_fast64_t unix_time = ToUnixSeconds(tp);
-  const Transition target = { unix_time };
+  const Transition target = {unix_time, 0, civil_second(), civil_second()};
   const Transition* tr = std::upper_bound(begin, end, target,
                                           Transition::ByUnixTime());
   for (; tr != end; ++tr) {  // skip no-op transitions
@@ -956,7 +956,7 @@
     }
     unix_time += 1;  // ceils
   }
-  const Transition target = { unix_time };
+  const Transition target = {unix_time, 0, civil_second(), civil_second()};
   const Transition* tr = std::lower_bound(begin, end, target,
                                           Transition::ByUnixTime());
   for (; tr != begin; --tr) {  // skip no-op transitions
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
index 6db519e..2829170 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -267,13 +267,13 @@
   return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
 }
 
-bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp,
-                                  time_zone::civil_transition* trans) const {
+bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
+                                  time_zone::civil_transition*) const {
   return false;
 }
 
-bool TimeZoneLibC::PrevTransition(const time_point<seconds>& tp,
-                                  time_zone::civil_transition* trans) const {
+bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
+                                  time_zone::civil_transition*) const {
   return false;
 }
 
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 3dca822c..2e49e48c 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -1021,7 +1021,7 @@
   //  1) we know how to change the time zone used by localtime()/mktime(),
   //  2) cctz and localtime()/mktime() will use similar-enough tzdata, and
   //  3) we have some idea about how mktime() behaves during transitions.
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__ANDROID__)
   const char* const ep = getenv("TZ");
   std::string tz_name = (ep != nullptr) ? ep : "";
   for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc
index bf2d2d2..1bc16ae 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc
@@ -54,7 +54,7 @@
 #pragma comment( \
     linker,      \
     "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64)
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
 #pragma comment( \
     linker,      \
     "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
diff --git a/third_party/abseil-cpp/absl/types/internal/variant.h b/third_party/abseil-cpp/absl/types/internal/variant.h
index 477e589..a0ab1e8 100644
--- a/third_party/abseil-cpp/absl/types/internal/variant.h
+++ b/third_party/abseil-cpp/absl/types/internal/variant.h
@@ -1605,11 +1605,12 @@
 template <typename Variant, typename... Ts>
 struct VariantHashBase<Variant,
                        absl::enable_if_t<absl::conjunction<
-                           type_traits_internal::IsHashEnabled<Ts>...>::value>,
+                           type_traits_internal::IsHashable<Ts>...>::value>,
                        Ts...> {
   using argument_type = Variant;
   using result_type = size_t;
   size_t operator()(const Variant& var) const {
+    type_traits_internal::AssertHashEnabled<Ts...>();
     if (var.valueless_by_exception()) {
       return 239799884;
     }
diff --git a/third_party/abseil-cpp/absl/types/optional.h b/third_party/abseil-cpp/absl/types/optional.h
index 7677fe5..d800ca68 100644
--- a/third_party/abseil-cpp/absl/types/optional.h
+++ b/third_party/abseil-cpp/absl/types/optional.h
@@ -295,7 +295,7 @@
 
   optional_data() = default;
 
-  optional_data(const optional_data& rhs) {
+  optional_data(const optional_data& rhs) : optional_data_base<T>() {
     if (rhs.engaged_) {
       this->construct(rhs.data_);
     }
@@ -303,7 +303,8 @@
 
   optional_data(optional_data&& rhs) noexcept(
       absl::default_allocator_is_nothrow::value ||
-      std::is_nothrow_move_constructible<T>::value) {
+      std::is_nothrow_move_constructible<T>::value)
+      : optional_data_base<T>() {
     if (rhs.engaged_) {
       this->construct(std::move(rhs.data_));
     }
@@ -467,6 +468,7 @@
   using argument_type = absl::optional<T>;
   using result_type = size_t;
   size_t operator()(const absl::optional<T>& opt) const {
+    absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
     if (opt) {
       return std::hash<absl::remove_const_t<T> >()(*opt);
     } else {
diff --git a/third_party/abseil-cpp/absl/types/optional_test.cc b/third_party/abseil-cpp/absl/types/optional_test.cc
index fc4f00a4..bedf5b0 100644
--- a/third_party/abseil-cpp/absl/types/optional_test.cc
+++ b/third_party/abseil-cpp/absl/types/optional_test.cc
@@ -1504,18 +1504,19 @@
 
   static_assert(is_hash_enabled_for<absl::optional<int>>::value, "");
   static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, "");
+  static_assert(
+      absl::type_traits_internal::IsHashable<absl::optional<int>>::value, "");
+  static_assert(
+      absl::type_traits_internal::IsHashable<absl::optional<Hashable>>::value,
+      "");
+  absl::type_traits_internal::AssertHashEnabled<absl::optional<int>>();
+  absl::type_traits_internal::AssertHashEnabled<absl::optional<Hashable>>();
 
-#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
-                          _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
-  // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
-  // static_assert to catch any user-defined type that doesn't provide a hash
-  // specialization. So instantiating std::hash<absl::optional<T>> will result
-  // in a hard error which is not SFINAE friendly.
-#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
-#endif
-
-#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
   static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, "");
+  static_assert(!absl::type_traits_internal::IsHashable<
+                    absl::optional<NonHashable>>::value,
+                "");
 #endif
 
   // libstdc++ std::optional is missing remove_const_t, i.e. it's using
diff --git a/third_party/abseil-cpp/absl/types/span_test.cc b/third_party/abseil-cpp/absl/types/span_test.cc
index bd739ff..f4203b5 100644
--- a/third_party/abseil-cpp/absl/types/span_test.cc
+++ b/third_party/abseil-cpp/absl/types/span_test.cc
@@ -779,4 +779,19 @@
   EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
 }
 
+TEST(Span, Hash) {
+  int array[] = {1, 2, 3, 4};
+  int array2[] = {1, 2, 3};
+  using T = absl::Span<const int>;
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      {// Empties
+       T(), T(nullptr, 0), T(array, 0), T(array2, 0),
+       // Different array with same value
+       T(array, 3), T(array2), T({1, 2, 3}),
+       // Same array, but different length
+       T(array, 1), T(array, 2),
+       // Same length, but different array
+       T(array + 1, 2), T(array + 2, 2)}));
+}
+
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/types/variant_test.cc b/third_party/abseil-cpp/absl/types/variant_test.cc
index 80e8467..463d775 100644
--- a/third_party/abseil-cpp/absl/types/variant_test.cc
+++ b/third_party/abseil-cpp/absl/types/variant_test.cc
@@ -1977,29 +1977,17 @@
 }
 
 TEST(VariantTest, Hash) {
-  static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, "");
-  static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value,
+  static_assert(type_traits_internal::IsHashable<variant<int>>::value, "");
+  static_assert(type_traits_internal::IsHashable<variant<Hashable>>::value, "");
+  static_assert(type_traits_internal::IsHashable<variant<int, Hashable>>::value,
+                "");
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+  static_assert(!type_traits_internal::IsHashable<variant<NonHashable>>::value,
                 "");
   static_assert(
-      type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, "");
-
-#if defined(_MSC_VER) ||                                   \
-    (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \
-     _LIBCPP_STD_VER > 11) ||                              \
-    defined(__APPLE__)
-  // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
-  // static_assert to catch any user-defined type T that doesn't provide a hash
-  // specialization. So instantiating std::hash<variant<T>> will result
-  // in a hard error which is not SFINAE friendly.
-#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
-#endif
-
-#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
-  static_assert(
-      !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, "");
-  static_assert(!type_traits_internal::IsHashEnabled<
-                    variant<Hashable, NonHashable>>::value,
-                "");
+      !type_traits_internal::IsHashable<variant<Hashable, NonHashable>>::value,
+      "");
 #endif
 
 // MSVC std::hash<std::variant> does not use the index, thus produce the same
@@ -2023,11 +2011,10 @@
     EXPECT_GT(hashcodes.size(), 90);
 
     // test const-qualified
+    static_assert(type_traits_internal::IsHashable<variant<const int>>::value,
+                  "");
     static_assert(
-        type_traits_internal::IsHashEnabled<variant<const int>>::value, "");
-    static_assert(
-        type_traits_internal::IsHashEnabled<variant<const Hashable>>::value,
-        "");
+        type_traits_internal::IsHashable<variant<const Hashable>>::value, "");
     std::hash<absl::variant<const int>> c_hash;
     for (int i = 0; i < 100; ++i) {
       EXPECT_EQ(hash(i), c_hash(i));
diff --git a/third_party/blink/public/web/web_text_check_client.h b/third_party/blink/public/web/web_text_check_client.h
index d4a7371..cb8c59f 100644
--- a/third_party/blink/public/web/web_text_check_client.h
+++ b/third_party/blink/public/web/web_text_check_client.h
@@ -24,8 +24,8 @@
   // error, then upon return misspelledLength is 0. If optional_suggestions
   // is given, then it will be filled with suggested words (not a cheap step).
   virtual void CheckSpelling(const WebString& text,
-                             int& misspelled_offset,
-                             int& misspelled_length,
+                             size_t& misspelled_offset,
+                             size_t& misspelled_length,
                              WebVector<WebString>* optional_suggestions) {}
 
   // Requests asynchronous spelling and grammar checking, whose result should be
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
index 78a579ae..14df764 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
@@ -300,7 +300,7 @@
 }
 
 String SerializedScriptValue::ToWireString() const {
-  // Add the padding '\0', but don't put it in |m_dataBuffer|.
+  // Add the padding '\0', but don't put it in |data_buffer_|.
   // This requires direct use of uninitialized strings, though.
   UChar* destination;
   wtf_size_t string_size_bytes =
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index e352fa3e..dbf6ee9 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -81,12 +81,12 @@
   // WorkerOrWorkletScriptController::evaluate(), with the contoller using it
   // during script evaluation. To handle nested evaluate() uses,
   // ExecutionStates are chained together;
-  // |m_outerState| keeps a pointer to the context object one level out
+  // |outer_state_| keeps a pointer to the context object one level out
   // (or 0, if outermost.) Upon return from evaluate(), the
   // WorkerOrWorkletScriptController's ExecutionState is popped and the
   // previous one restored (see above dtor.)
   //
-  // With Oilpan, |m_outerState| isn't traced. It'll be "up the stack"
+  // With Oilpan, |outer_state_| isn't traced. It'll be "up the stack"
   // and its fields will be traced when scanning the stack.
   Member<WorkerOrWorkletScriptController> controller_;
   ExecutionState* outer_state_;
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
index 54f8fab..a263cd3 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
@@ -127,7 +127,7 @@
 
   scoped_refptr<RejectedPromises> rejected_promises_;
 
-  // |m_executionState| refers to a stack object that evaluate() allocates;
+  // |execution_state_| refers to a stack object that evaluate() allocates;
   // evaluate() ensuring that the pointer reference to it is removed upon
   // returning. Hence kept as a bare pointer here, and not a Persistent with
   // Oilpan enabled; stack scanning will visit the object and
diff --git a/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.h.tmpl b/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.h.tmpl
index 49cc3b8..245cab6 100644
--- a/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.h.tmpl
@@ -35,25 +35,25 @@
     USING_FAST_MALLOC(StylePropertyShorthand);
  public:
   constexpr StylePropertyShorthand()
-      : m_properties(0),
-        m_length(0),
-        m_shorthandID(CSSPropertyInvalid) {}
+      : properties_(0),
+        length_(0),
+        shorthand_id_(CSSPropertyInvalid) {}
 
   constexpr StylePropertyShorthand(CSSPropertyID id,
                                    const CSSProperty** properties,
                                    unsigned numProperties)
-      : m_properties(properties),
-        m_length(numProperties),
-        m_shorthandID(id) {}
+      : properties_(properties),
+        length_(numProperties),
+        shorthand_id_(id) {}
 
-  const CSSProperty** properties() const { return m_properties; }
-  unsigned length() const { return m_length; }
-  CSSPropertyID id() const { return m_shorthandID; }
+  const CSSProperty** properties() const { return properties_; }
+  unsigned length() const { return length_; }
+  CSSPropertyID id() const { return shorthand_id_; }
 
  private:
-  const CSSProperty** m_properties;
-  unsigned m_length;
-  CSSPropertyID m_shorthandID;
+  const CSSProperty** properties_;
+  unsigned length_;
+  CSSPropertyID shorthand_id_;
 };
 
 {% for property in properties %}
diff --git a/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl
index 69733345a..7a8fef6 100644
--- a/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl
@@ -49,7 +49,7 @@
 
 void {{sink_class}}::add{{agent}}({{class_name}}* agent) {
   bool already_had_agent = has{{agent}}s();
-  m_{{getter_name}}s.insert(agent);
+  {{getter_name}}s_.insert(agent);
 
   if (!already_had_agent) {
     MutexLocker lock(AgentCountMutex());
@@ -64,7 +64,7 @@
   if (!has{{agent}}s())
     return;
 
-  m_{{getter_name}}s.erase(agent);
+  {{getter_name}}s_.erase(agent);
 
   if (!has{{agent}}s()) {
     MutexLocker lock(AgentCountMutex());
@@ -82,7 +82,7 @@
 {
 {% for agent in agents %}
 {% set getter_name = agent | to_lower_case %}
-  visitor->Trace(m_{{getter_name}}s);
+  visitor->Trace({{getter_name}}s_);
 {% endfor %}
 }
 
diff --git a/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.cc.tmpl
index b54ce95..eca77c48 100644
--- a/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.cc.tmpl
@@ -11,9 +11,9 @@
 namespace blink {
 
 InternalSettingsGenerated::InternalSettingsGenerated(Page* page)
-    : m_page(page)
+    : page_(page)
     {% for setting in settings if setting.type|to_idl_type %}
-    , m_{{setting.name}}(page->GetSettings().Get{{setting.name.to_upper_camel_case()}}())
+    , {{setting.name}}_(page->GetSettings().Get{{setting.name.to_upper_camel_case()}}())
     {% endfor %}
 {
 }
@@ -22,18 +22,18 @@
 
 void InternalSettingsGenerated::resetToConsistentState() {
   {% for setting in settings if setting.type|to_idl_type %}
-  m_page->GetSettings().Set{{setting.name.to_upper_camel_case()}}(m_{{setting.name}});
+  page_->GetSettings().Set{{setting.name.to_upper_camel_case()}}({{setting.name}}_);
   {% endfor %}
 }
 {% for setting in settings if setting.type|to_idl_type %}
 
 void InternalSettingsGenerated::set{{setting.name.to_upper_camel_case()}}({{setting.type|to_passing_type}} {{setting.name}}) {
-  m_page->GetSettings().Set{{setting.name.to_upper_camel_case()}}({{setting.name}});
+  page_->GetSettings().Set{{setting.name.to_upper_camel_case()}}({{setting.name}});
 }
 {% endfor %}
 
 void InternalSettingsGenerated::Trace(Visitor* visitor) {
-  visitor->Trace(m_page);
+  visitor->Trace(page_);
   ScriptWrappable::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.h.tmpl b/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.h.tmpl
index 7933bd18..eb7b9f28 100644
--- a/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/internal_settings_generated.h.tmpl
@@ -30,10 +30,10 @@
   void Trace(Visitor*) override;
 
  private:
-  Member<Page> m_page;
+  Member<Page> page_;
 
   {% for setting in settings if setting.type|to_idl_type %}
-  {{setting.type}} m_{{setting.name}};
+  {{setting.type}} {{setting.name}}_;
   {% endfor %}
 };
 
diff --git a/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl b/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl
index e3cff07..facc4929 100644
--- a/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl
@@ -42,8 +42,8 @@
 {% for agent in agents %}
 {% set class_name = agent | agent_name_to_class %}
 {% set getter_name = agent | to_lower_case %}
-  bool has{{agent}}s() const { return !m_{{getter_name}}s.IsEmpty(); }
-  const HeapListHashSet<Member<{{class_name}}>>& {{getter_name}}s() const { return m_{{getter_name}}s; }
+  bool has{{agent}}s() const { return !{{getter_name}}s_.IsEmpty(); }
+  const HeapListHashSet<Member<{{class_name}}>>& {{getter_name}}s() const { return {{getter_name}}s_; }
   void add{{agent}}({{class_name}}* agent);
   void remove{{agent}}({{class_name}}* agent);
 
@@ -57,7 +57,7 @@
 {% for agent in agents %}
 {% set class_name = agent | agent_name_to_class %}
 {% set getter_name = agent | to_lower_case %}
-  HeapListHashSet<Member<{{class_name}}>> m_{{getter_name}}s;
+  HeapListHashSet<Member<{{class_name}}>> {{getter_name}}s_;
 {% endfor %}
 
   // Number of sinks with an enabled agent of each type, used to keep
diff --git a/third_party/blink/renderer/core/animation/document_timeline.cc b/third_party/blink/renderer/core/animation/document_timeline.cc
index f83a0fe..a7e2ab0 100644
--- a/third_party/blink/renderer/core/animation/document_timeline.cc
+++ b/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -268,7 +268,7 @@
       std::isnan(last_current_time_internal_))
     return false;
 
-  // We allow m_lastCurrentTimeInternal to advance here when there
+  // We allow |last_current_time_internal_| to advance here when there
   // are no animations to allow animations spawned during style
   // recalc to not invalidate this flag.
   if (animations_needing_update_.IsEmpty())
diff --git a/third_party/blink/renderer/core/animation/invalidatable_interpolation.cc b/third_party/blink/renderer/core/animation/invalidatable_interpolation.cc
index 8d7bac4..1f765f2 100644
--- a/third_party/blink/renderer/core/animation/invalidatable_interpolation.cc
+++ b/third_party/blink/renderer/core/animation/invalidatable_interpolation.cc
@@ -25,7 +25,7 @@
   if (is_conversion_cached_ && cached_pair_conversion_)
     cached_pair_conversion_->InterpolateValue(fraction, cached_value_);
   // We defer the interpolation to ensureValidConversion() if
-  // m_cachedPairConversion is null.
+  // |cached_pair_conversion_| is null.
 }
 
 std::unique_ptr<PairwisePrimitiveInterpolation>
diff --git a/third_party/blink/renderer/core/animation/underlying_value_owner.cc b/third_party/blink/renderer/core/animation/underlying_value_owner.cc
index 9e3b744..ccbca95a 100644
--- a/third_party/blink/renderer/core/animation/underlying_value_owner.cc
+++ b/third_party/blink/renderer/core/animation/underlying_value_owner.cc
@@ -28,8 +28,8 @@
                                const InterpolationValue& value) {
   DCHECK(value);
   type_ = &type;
-  // By clearing m_valueOwner we will perform a copy before attempting to mutate
-  // m_value, thus upholding the const contract for this instance of
+  // By clearing |value_owner_| we will perform a copy before attempting to
+  // mutate |value_|, thus upholding the const contract for this instance of
   // interpolationValue.
   value_owner_.Clear();
   value_ = &value;
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.cc b/third_party/blink/renderer/core/clipboard/data_object_item.cc
index 9f1bfed..64f74d6 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_item.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object_item.cc
@@ -128,7 +128,7 @@
       return file_.Get();
     DCHECK(shared_buffer_);
     // FIXME: This code is currently impossible--we never populate
-    // m_sharedBuffer when dragging in. At some point though, we may need to
+    // |shared_buffer_| when dragging in. At some point though, we may need to
     // support correctly converting a shared buffer into a file.
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.h b/third_party/blink/renderer/core/clipboard/data_object_item.h
index fa2cd04..5b051db 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_item.h
+++ b/third_party/blink/renderer/core/clipboard/data_object_item.h
@@ -103,8 +103,8 @@
   String title_;
   KURL base_url_;
 
-  uint64_t sequence_number_;  // Only valid when m_source == PasteboardSource
-  String file_system_id_;     // Only valid when m_file is backed by FileEntry.
+  uint64_t sequence_number_;  // Only valid when |source_| == PasteboardSource.
+  String file_system_id_;     // Only valid when |file_| is backed by FileEntry.
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/clipboard/data_transfer.cc b/third_party/blink/renderer/core/clipboard/data_transfer.cc
index 9f2e9745..a772f4c 100644
--- a/third_party/blink/renderer/core/clipboard/data_transfer.cc
+++ b/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -91,7 +91,7 @@
 #if DCHECK_IS_ON()
     DCHECK_EQ(dom_tree_version_, node_->GetDocument().DomTreeVersion());
 #endif
-    // Construct layout object for |m_node| with pseudo class "-webkit-drag"
+    // Construct layout object for |node_| with pseudo class "-webkit-drag"
     local_frame_->View()->UpdateAllLifecyclePhasesExceptPaint();
     LayoutObject* const dragged_layout_object = node_->GetLayoutObject();
     if (!dragged_layout_object)
@@ -263,7 +263,7 @@
   if (ConvertEffectAllowedToDragOperation(effect) == kDragOperationPrivate) {
     // This means that there was no conversion, and the effectAllowed that
     // we are passed isn't a valid effectAllowed, so we should ignore it,
-    // and not set m_effectAllowed.
+    // and not set |effect_allowed_|.
 
     // The attribute must ignore any attempts to set it to a value other than
     // none, copy, copyLink, copyMove, link, linkMove, move, all, and
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index b08c16e..66c3d19 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -17,6 +17,8 @@
     "binary_data_font_face_source.h",
     "computed_style_css_value_mapping.cc",
     "computed_style_css_value_mapping.h",
+    "css_axis_value.cc",
+    "css_axis_value.h",
     "css_basic_shape_values.cc",
     "css_basic_shape_values.h",
     "css_border_image.cc",
diff --git a/third_party/blink/renderer/core/css/css_axis_value.cc b/third_party/blink/renderer/core/css/css_axis_value.cc
new file mode 100644
index 0000000..9b3020a
--- /dev/null
+++ b/third_party/blink/renderer/core/css/css_axis_value.cc
@@ -0,0 +1,79 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/css_axis_value.h"
+
+#include "third_party/blink/renderer/core/css/css_identifier_value.h"
+#include "third_party/blink/renderer/core/css/css_primitive_value.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+CSSAxisValue::CSSAxisValue(CSSValueID axis_name)
+    : CSSValueList(kAxisClass, kSpaceSeparator), axis_name_(axis_name) {
+  double x = 0;
+  double y = 0;
+  double z = 0;
+  switch (axis_name) {
+    case CSSValueX:
+      x = 1;
+      break;
+
+    case CSSValueY:
+      y = 1;
+      break;
+
+    case CSSValueZ:
+      z = 1;
+      break;
+
+    default:
+      NOTREACHED();
+  }
+  Append(*CSSPrimitiveValue::Create(x, CSSPrimitiveValue::UnitType::kNumber));
+  Append(*CSSPrimitiveValue::Create(y, CSSPrimitiveValue::UnitType::kNumber));
+  Append(*CSSPrimitiveValue::Create(z, CSSPrimitiveValue::UnitType::kNumber));
+}
+
+CSSAxisValue::CSSAxisValue(double x, double y, double z)
+    : CSSValueList(kAxisClass, kSpaceSeparator), axis_name_(CSSValueInvalid) {
+  // Normalize axis that are parallel to x, y or z axis.
+  if (x > 0 && y == 0 && z == 0) {
+    x = 1;
+    axis_name_ = CSSValueX;
+  } else if (x == 0 && y > 0 && z == 0) {
+    y = 1;
+    axis_name_ = CSSValueY;
+  } else if (x == 0 && y == 0 && z > 0) {
+    z = 1;
+    axis_name_ = CSSValueZ;
+  }
+  Append(*CSSPrimitiveValue::Create(x, CSSPrimitiveValue::UnitType::kNumber));
+  Append(*CSSPrimitiveValue::Create(y, CSSPrimitiveValue::UnitType::kNumber));
+  Append(*CSSPrimitiveValue::Create(z, CSSPrimitiveValue::UnitType::kNumber));
+}
+
+String CSSAxisValue::CustomCSSText() const {
+  StringBuilder result;
+  if (axis_name_ != CSSValueInvalid) {
+    result.Append(AtomicString(getValueName(axis_name_)));
+  } else {
+    result.Append(CSSValueList::CustomCSSText());
+  }
+  return result.ToString();
+}
+
+double CSSAxisValue::X() const {
+  return ToCSSPrimitiveValue(Item(0)).GetDoubleValue();
+}
+
+double CSSAxisValue::Y() const {
+  return ToCSSPrimitiveValue(Item(1)).GetDoubleValue();
+}
+
+double CSSAxisValue::Z() const {
+  return ToCSSPrimitiveValue(Item(2)).GetDoubleValue();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_axis_value.h b/third_party/blink/renderer/core/css/css_axis_value.h
new file mode 100644
index 0000000..c0d7aee2
--- /dev/null
+++ b/third_party/blink/renderer/core/css/css_axis_value.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_AXIS_VALUE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_AXIS_VALUE_H_
+
+#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/core/css_value_keywords.h"
+
+namespace blink {
+
+class CSSAxisValue : public CSSValueList {
+ public:
+  static CSSAxisValue* Create(CSSValueID axis_name) {
+    return MakeGarbageCollected<CSSAxisValue>(axis_name);
+  }
+  static CSSAxisValue* Create(double x, double y, double z) {
+    return MakeGarbageCollected<CSSAxisValue>(x, y, z);
+  }
+
+  explicit CSSAxisValue(CSSValueID axis_name);
+  CSSAxisValue(double x, double y, double z);
+
+  String CustomCSSText() const;
+
+  double X() const;
+
+  double Y() const;
+
+  double Z() const;
+
+  void TraceAfterDispatch(blink::Visitor* visitor) {
+    CSSValueList::TraceAfterDispatch(visitor);
+  }
+
+ private:
+  CSSValueID axis_name_;
+};
+
+DEFINE_CSS_VALUE_TYPE_CASTS(CSSAxisValue, IsAxisValue());
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_AXIS_VALUE_H_
diff --git a/third_party/blink/renderer/core/css/css_gradient_value.cc b/third_party/blink/renderer/core/css/css_gradient_value.cc
index e210029..3da9265 100644
--- a/third_party/blink/renderer/core/css/css_gradient_value.cc
+++ b/third_party/blink/renderer/core/css/css_gradient_value.cc
@@ -290,7 +290,8 @@
                               const Document& document,
                               const ComputedStyle& style) {
   return document.GetTextLinkColors().ColorFromCSSValue(
-      stop_color, style.VisitedDependentColor(GetCSSPropertyColor()));
+      stop_color, style.VisitedDependentColor(GetCSSPropertyColor()),
+      document.GetColorScheme());
 }
 
 void CSSGradientValue::AddDeprecatedStops(GradientDesc& desc,
diff --git a/third_party/blink/renderer/core/css/css_selector_watch.h b/third_party/blink/renderer/core/css/css_selector_watch.h
index 1f8f1677..7791ba78f 100644
--- a/third_party/blink/renderer/core/css/css_selector_watch.h
+++ b/third_party/blink/renderer/core/css/css_selector_watch.h
@@ -74,7 +74,7 @@
   // Maps a CSS selector string with a -webkit-callback property to the number
   // of matching ComputedStyle objects in this document.
   HashCountedSet<String> matching_callback_selectors_;
-  // Selectors are relative to m_matchingCallbackSelectors's contents at
+  // Selectors are relative to |matching_callback_selectors_|'s contents at
   // the previous call to selectorMatchChanged.
   HashSet<String> added_selectors_;
   HashSet<String> removed_selectors_;
diff --git a/third_party/blink/renderer/core/css/css_value.cc b/third_party/blink/renderer/core/css/css_value.cc
index e00e74e..5f0fb56 100644
--- a/third_party/blink/renderer/core/css/css_value.cc
+++ b/third_party/blink/renderer/core/css/css_value.cc
@@ -26,6 +26,7 @@
 
 #include "third_party/blink/renderer/core/css/css_value.h"
 
+#include "third_party/blink/renderer/core/css/css_axis_value.h"
 #include "third_party/blink/renderer/core/css/css_basic_shape_values.h"
 #include "third_party/blink/renderer/core/css/css_border_image_slice_value.h"
 #include "third_party/blink/renderer/core/css/css_color_value.h"
@@ -150,6 +151,8 @@
 bool CSSValue::operator==(const CSSValue& other) const {
   if (class_type_ == other.class_type_) {
     switch (GetClassType()) {
+      case kAxisClass:
+        return CompareCSSValues<CSSAxisValue>(*this, other);
       case kBasicShapeCircleClass:
         return CompareCSSValues<CSSBasicShapeCircleValue>(*this, other);
       case kBasicShapeEllipseClass:
@@ -258,6 +261,8 @@
 
 String CSSValue::CssText() const {
   switch (GetClassType()) {
+    case kAxisClass:
+      return ToCSSAxisValue(this)->CustomCSSText();
     case kBasicShapeCircleClass:
       return ToCSSBasicShapeCircleValue(this)->CustomCSSText();
     case kBasicShapeEllipseClass:
@@ -363,6 +368,9 @@
 
 void CSSValue::FinalizeGarbageCollectedObject() {
   switch (GetClassType()) {
+    case kAxisClass:
+      ToCSSAxisValue(this)->~CSSAxisValue();
+      return;
     case kBasicShapeCircleClass:
       ToCSSBasicShapeCircleValue(this)->~CSSBasicShapeCircleValue();
       return;
@@ -517,6 +525,9 @@
 
 void CSSValue::Trace(blink::Visitor* visitor) {
   switch (GetClassType()) {
+    case kAxisClass:
+      ToCSSAxisValue(this)->TraceAfterDispatch(visitor);
+      return;
     case kBasicShapeCircleClass:
       ToCSSBasicShapeCircleValue(this)->TraceAfterDispatch(visitor);
       return;
diff --git a/third_party/blink/renderer/core/css/css_value.h b/third_party/blink/renderer/core/css/css_value.h
index e1bd0489..22407d8 100644
--- a/third_party/blink/renderer/core/css/css_value.h
+++ b/third_party/blink/renderer/core/css/css_value.h
@@ -164,6 +164,7 @@
   bool IsInvalidVariableValue() const {
     return class_type_ == kInvalidVariableValueClass;
   }
+  bool IsAxisValue() const { return class_type_ == kAxisClass; }
 
   bool HasFailedOrCanceledSubresources() const;
   bool MayContainUrl() const;
@@ -249,6 +250,7 @@
     kImageSetClass,
     kGridLineNamesClass,
     kGridAutoRepeatClass,
+    kAxisClass,
     // Do not append non-list class types here.
   };
 
diff --git a/third_party/blink/renderer/core/css/css_value_keywords.json5 b/third_party/blink/renderer/core/css/css_value_keywords.json5
index bfa19f63..22a4eb6 100644
--- a/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -220,6 +220,9 @@
     // Value used to implement the behavior in:
     // https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk
     "-internal-quirk-inherit",
+    // The default color value for the root element. Using a keyword to account
+    // for different values for different color schemes like dark mode.
+    "-internal-root-color",
     //
     // background-repeat
     //
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
index 1bc35b3..0a9cfd3 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 
+#include "third_party/blink/renderer/core/css/css_axis_value.h"
 #include "third_party/blink/renderer/core/css/css_calculation_value.h"
 #include "third_party/blink/renderer/core/css/css_color_value.h"
 #include "third_party/blink/renderer/core/css/css_crossfade_value.h"
@@ -1477,6 +1478,27 @@
   return ConsumeImage(range, context);
 }
 
+CSSValue* ConsumeAxis(CSSParserTokenRange& range) {
+  CSSValueID axis_id = range.Peek().Id();
+  if (axis_id == CSSValueX || axis_id == CSSValueY || axis_id == CSSValueZ) {
+    ConsumeIdent(range);
+    return CSSAxisValue::Create(axis_id);
+  }
+
+  CSSValue* x_dimension =
+      css_property_parser_helpers::ConsumeNumber(range, kValueRangeAll);
+  CSSValue* y_dimension =
+      css_property_parser_helpers::ConsumeNumber(range, kValueRangeAll);
+  CSSValue* z_dimension =
+      css_property_parser_helpers::ConsumeNumber(range, kValueRangeAll);
+  if (!x_dimension || !y_dimension || !z_dimension)
+    return nullptr;
+  double x = ToCSSPrimitiveValue(x_dimension)->GetDoubleValue();
+  double y = ToCSSPrimitiveValue(y_dimension)->GetDoubleValue();
+  double z = ToCSSPrimitiveValue(z_dimension)->GetDoubleValue();
+  return CSSAxisValue::Create(x, y, z);
+}
+
 static CSSValue* ConsumeCrossFade(CSSParserTokenRange& args,
                                   const CSSParserContext* context) {
   CSSValue* from_image_value = ConsumeImageOrNone(args, context);
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
index 9dbf89c..ce5211a 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
@@ -126,6 +126,8 @@
     ConsumeGeneratedImagePolicy = ConsumeGeneratedImagePolicy::kAllow);
 CSSValue* ConsumeImageOrNone(CSSParserTokenRange&, const CSSParserContext*);
 
+CSSValue* ConsumeAxis(CSSParserTokenRange&);
+
 bool IsCSSWideKeyword(StringView);
 
 CSSIdentifierValue* ConsumeShapeBox(CSSParserTokenRange&);
diff --git a/third_party/blink/renderer/core/css/properties/longhands/rotate_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/rotate_custom.cc
index 69367f2..9e46283b 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/rotate_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/rotate_custom.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/css/properties/longhands/rotate.h"
 
+#include "third_party/blink/renderer/core/css/css_axis_value.h"
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
@@ -27,43 +28,11 @@
   CSSValue* rotation = css_property_parser_helpers::ConsumeAngle(
       range, &context, base::Optional<WebFeature>());
 
-  CSSValueID axis_id = range.Peek().Id();
-  if (axis_id == CSSValueX) {
-    css_property_parser_helpers::ConsumeIdent(range);
-    list->Append(
-        *CSSPrimitiveValue::Create(1, CSSPrimitiveValue::UnitType::kNumber));
-    list->Append(
-        *CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kNumber));
-    list->Append(
-        *CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kNumber));
-  } else if (axis_id == CSSValueY) {
-    css_property_parser_helpers::ConsumeIdent(range);
-    list->Append(
-        *CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kNumber));
-    list->Append(
-        *CSSPrimitiveValue::Create(1, CSSPrimitiveValue::UnitType::kNumber));
-    list->Append(
-        *CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kNumber));
-  } else if (axis_id == CSSValueZ) {
-    css_property_parser_helpers::ConsumeIdent(range);
-    list->Append(
-        *CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kNumber));
-    list->Append(
-        *CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kNumber));
-    list->Append(
-        *CSSPrimitiveValue::Create(1, CSSPrimitiveValue::UnitType::kNumber));
-  } else {
-    for (unsigned i = 0; i < 3; i++) {  // 3 dimensions of rotation
-      CSSValue* dimension =
-          css_property_parser_helpers::ConsumeNumber(range, kValueRangeAll);
-      if (!dimension) {
-        if (i == 0)
-          break;
-        return nullptr;
-      }
-      list->Append(*dimension);
-    }
-  }
+  CSSValue* axis = css_property_parser_helpers::ConsumeAxis(range);
+  if (axis)
+    list->Append(*axis);
+  else if (!rotation)
+    return nullptr;
 
   if (!rotation) {
     rotation = css_property_parser_helpers::ConsumeAngle(
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 559595eb..90a2408 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -30,6 +30,7 @@
 
 #include "build/build_config.h"
 #include "third_party/blink/renderer/core/css/basic_shape_functions.h"
+#include "third_party/blink/renderer/core/css/css_axis_value.h"
 #include "third_party/blink/renderer/core/css/css_color_value.h"
 #include "third_party/blink/renderer/core/css/css_content_distribution_value.h"
 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
@@ -108,7 +109,8 @@
                                           const CSSValue& value,
                                           bool for_visited_link) {
   return state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
-      value, state.Style()->GetColor(), for_visited_link);
+      value, state.Style()->GetColor(), state.GetDocument().GetColorScheme(),
+      for_visited_link);
 }
 
 scoped_refptr<StyleSVGResource> StyleBuilderConverter::ConvertElementReference(
@@ -1358,7 +1360,7 @@
       ToCSSIdentifierValue(value).GetValueID() == CSSValueCurrentcolor)
     return StyleColor::CurrentColor();
   return state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
-      value, Color(), for_visited_link);
+      value, Color(), state.GetDocument().GetColorScheme(), for_visited_link);
 }
 
 StyleAutoColor StyleBuilderConverter::ConvertStyleAutoColor(
@@ -1372,7 +1374,7 @@
       return StyleAutoColor::AutoColor();
   }
   return state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
-      value, Color(), for_visited_link);
+      value, Color(), state.GetDocument().GetColorScheme(), for_visited_link);
 }
 
 SVGPaint StyleBuilderConverter::ConvertSVGPaint(StyleResolverState& state,
@@ -1567,14 +1569,16 @@
   }
 
   const CSSValueList& list = ToCSSValueList(value);
-  DCHECK(list.length() == 1 || list.length() == 4);
+  DCHECK(list.length() == 1 || list.length() == 2);
   double x = 0;
   double y = 0;
   double z = 1;
-  if (list.length() == 4) {
-    x = ToCSSPrimitiveValue(list.Item(0)).GetDoubleValue();
-    y = ToCSSPrimitiveValue(list.Item(1)).GetDoubleValue();
-    z = ToCSSPrimitiveValue(list.Item(2)).GetDoubleValue();
+  if (list.length() == 2) {
+    // axis angle
+    const CSSAxisValue& axis = ToCSSAxisValue(list.Item(0));
+    x = axis.X();
+    y = axis.Y();
+    z = axis.Z();
   }
   double angle =
       ToCSSPrimitiveValue(list.Item(list.length() - 1)).ComputeDegrees();
@@ -1715,8 +1719,8 @@
     if (value_id == CSSValueCurrentcolor)
       return value;
     if (StyleColor::IsColorKeyword(value_id)) {
-      Color color =
-          document.GetTextLinkColors().ColorFromCSSValue(value, Color(), false);
+      Color color = document.GetTextLinkColors().ColorFromCSSValue(
+          value, Color(), document.GetColorScheme(), false);
       return *CSSColorValue::Create(color.Rgb());
     }
   }
diff --git a/third_party/blink/renderer/core/css/selector_query.h b/third_party/blink/renderer/core/css/selector_query.h
index 1379b23..b890141 100644
--- a/third_party/blink/renderer/core/css/selector_query.h
+++ b/third_party/blink/renderer/core/css/selector_query.h
@@ -109,7 +109,7 @@
   CSSSelectorList selector_list_;
   // Contains the list of CSSSelector's to match, but without ones that could
   // never match like pseudo elements, div::before. This can be empty, while
-  // m_selectorList will never be empty as SelectorQueryCache::add would have
+  // |selector_list_| will never be empty as SelectorQueryCache::add would have
   // thrown an exception.
   Vector<const CSSSelector*> selectors_;
   AtomicString selector_id_;
diff --git a/third_party/blink/renderer/core/css/style_color.cc b/third_party/blink/renderer/core/css/style_color.cc
index 75ebc0b4..1fc46597 100644
--- a/third_party/blink/renderer/core/css/style_color.cc
+++ b/third_party/blink/renderer/core/css/style_color.cc
@@ -39,8 +39,9 @@
   //   '-internal-inactive-list-box-selection-text'
   //   '-webkit-focus-ring-color'
   //   '-internal-quirk-inherit'
+  //   '-internal-root-color'
   //
-  return (id >= CSSValueAqua && id <= CSSValueInternalQuirkInherit) ||
+  return (id >= CSSValueAqua && id <= CSSValueInternalRootColor) ||
          (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) ||
          id == CSSValueMenu;
 }
diff --git a/third_party/blink/renderer/core/dom/character_data.cc b/third_party/blink/renderer/core/dom/character_data.cc
index aef50d33..956c1942 100644
--- a/third_party/blink/renderer/core/dom/character_data.cc
+++ b/third_party/blink/renderer/core/dom/character_data.cc
@@ -33,11 +33,23 @@
 #include "third_party/blink/renderer/core/events/mutation_event.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
 
 namespace blink {
 
-void CharacterData::Atomize() {
-  data_ = AtomicString(data_);
+void CharacterData::MakeParkableOrAtomize() {
+  if (is_parkable_)
+    return;
+
+  // ParkableStrings have some overhead, don't pay it if we're not going to
+  // park a string at all.
+  if (ParkableStringManager::ShouldPark(*data_.Impl())) {
+    parkable_data_ = ParkableString(data_.ReleaseImpl());
+    data_ = String();
+    is_parkable_ = true;
+  } else {
+    data_ = AtomicString(data_);
+  }
 }
 
 void CharacterData::setData(const String& data) {
@@ -59,20 +71,20 @@
     return String();
   }
 
-  return data_.Substring(offset, count);
+  return data().Substring(offset, count);
 }
 
 void CharacterData::ParserAppendData(const String& data) {
-  String new_str = data_ + data;
+  String new_str = this->data() + data;
 
-  SetDataAndUpdate(new_str, data_.length(), 0, data.length(),
+  SetDataAndUpdate(new_str, this->data().length(), 0, data.length(),
                    kUpdateFromParser);
 }
 
 void CharacterData::appendData(const String& data) {
-  String new_str = data_ + data;
+  String new_str = this->data() + data;
 
-  SetDataAndUpdate(new_str, data_.length(), 0, data.length(),
+  SetDataAndUpdate(new_str, this->data().length(), 0, data.length(),
                    kUpdateFromNonParser);
 
   // FIXME: Should we call textInserted here?
@@ -90,7 +102,7 @@
     return;
   }
 
-  String new_str = data_;
+  String new_str = this->data();
   new_str.insert(data, offset);
 
   SetDataAndUpdate(new_str, offset, 0, data.length(), kUpdateFromNonParser);
@@ -131,7 +143,7 @@
                            exception_state))
     return;
 
-  String new_str = data_;
+  String new_str = data();
   new_str.Remove(offset, real_count);
 
   SetDataAndUpdate(new_str, offset, real_count, 0, kUpdateFromNonParser);
@@ -148,7 +160,7 @@
                            exception_state))
     return;
 
-  String new_str = data_;
+  String new_str = this->data();
   new_str.Remove(offset, real_count);
   new_str.insert(data, offset);
 
@@ -161,11 +173,11 @@
 }
 
 String CharacterData::nodeValue() const {
-  return data_;
+  return data();
 }
 
 bool CharacterData::ContainsOnlyWhitespaceOrEmpty() const {
-  return data_.ContainsOnlyWhitespaceOrEmpty();
+  return data().ContainsOnlyWhitespaceOrEmpty();
 }
 
 void CharacterData::setNodeValue(const String& node_value) {
@@ -177,7 +189,11 @@
                                      unsigned old_length,
                                      unsigned new_length,
                                      UpdateSource source) {
-  String old_data = data_;
+  String old_data = this->data();
+  if (is_parkable_) {
+    is_parkable_ = false;
+    parkable_data_ = ParkableString();
+  }
   data_ = new_data;
 
   DCHECK(!GetLayoutObject() || IsTextNode());
@@ -217,7 +233,7 @@
             Document::kDOMCharacterDataModifiedListener)) {
       DispatchScopedEvent(*MutationEvent::Create(
           event_type_names::kDOMCharacterDataModified, Event::Bubbles::kYes,
-          nullptr, old_data, data_));
+          nullptr, old_data, data()));
     }
     DispatchSubtreeModifiedEvent();
   }
diff --git a/third_party/blink/renderer/core/dom/character_data.h b/third_party/blink/renderer/core/dom/character_data.h
index 456e840..b94b5b6 100644
--- a/third_party/blink/renderer/core/dom/character_data.h
+++ b/third_party/blink/renderer/core/dom/character_data.h
@@ -26,6 +26,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -36,10 +37,16 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  void Atomize();
-  const String& data() const { return data_; }
+  // Makes the data either Parkable or Atomic. This enables de-duplication in
+  // both cases, the first one allowing compression as well.
+  void MakeParkableOrAtomize();
+  String data() const {
+    return is_parkable_ ? parkable_data_.ToString() : data_;
+  }
   void setData(const String&);
-  unsigned length() const { return data_.length(); }
+  unsigned length() const {
+    return is_parkable_ ? parkable_data_.length() : data_.length();
+  }
   String substringData(unsigned offset, unsigned count, ExceptionState&);
   void appendData(const String&);
   void replaceData(unsigned offset,
@@ -52,7 +59,7 @@
 
   bool ContainsOnlyWhitespaceOrEmpty() const;
 
-  StringImpl* DataImpl() { return data_.Impl(); }
+  StringImpl* DataImpl() { return data().Impl(); }
 
   void ParserAppendData(const String&);
 
@@ -60,13 +67,19 @@
   CharacterData(TreeScope& tree_scope,
                 const String& text,
                 ConstructionType type)
-      : Node(&tree_scope, type), data_(!text.IsNull() ? text : g_empty_string) {
+      : Node(&tree_scope, type),
+        is_parkable_(false),
+        data_(!text.IsNull() ? text : g_empty_string) {
     DCHECK(type == kCreateOther || type == kCreateText ||
            type == kCreateEditingText);
   }
 
   void SetDataWithoutUpdate(const String& data) {
     DCHECK(!data.IsNull());
+    if (is_parkable_) {
+      is_parkable_ = false;
+      parkable_data_ = ParkableString();
+    }
     data_ = data;
   }
   enum UpdateSource {
@@ -75,6 +88,8 @@
   };
   void DidModifyData(const String& old_value, UpdateSource);
 
+  bool is_parkable_;
+  ParkableString parkable_data_;
   String data_;
 
  private:
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 920f6681..66d4ec0 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -7970,6 +7970,19 @@
   return false;
 }
 
+void Document::SetColorScheme(ColorScheme color_scheme) {
+  if (color_scheme_ == color_scheme)
+    return;
+  color_scheme_ = color_scheme;
+  PlatformColorsChanged();
+  if (LocalFrameView* view = View()) {
+    if (color_scheme == ColorScheme::kDark)
+      view->SetBaseBackgroundColor(Color::kBlack);
+    else
+      view->SetBaseBackgroundColor(Color::kWhite);
+  }
+}
+
 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 474a8eb..7e67d30 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -64,6 +64,7 @@
 #include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/graphics/color_scheme.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_types.h"
@@ -1532,6 +1533,9 @@
   // associated Web App Manifest, it will return false.
   bool IsInWebAppScope() const;
 
+  ColorScheme GetColorScheme() const { return color_scheme_; }
+  void SetColorScheme(ColorScheme);
+
  protected:
   void DidUpdateSecurityOrigin() final;
 
@@ -1768,6 +1772,7 @@
 
   TextLinkColors text_link_colors_;
   const Member<VisitedLinkState> visited_link_state_;
+  ColorScheme color_scheme_ = ColorScheme::kLight;
 
   bool visually_ordered_;
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 2da7d9bc8..ab356c7 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3750,7 +3750,7 @@
     return g_empty_string;
 
   if (first_text_node && !found_multiple_text_nodes) {
-    first_text_node->Atomize();
+    first_text_node->MakeParkableOrAtomize();
     return first_text_node->data();
   }
 
diff --git a/third_party/blink/renderer/core/dom/text_link_colors.cc b/third_party/blink/renderer/core/dom/text_link_colors.cc
index fd51918..11927e5 100644
--- a/third_party/blink/renderer/core/dom/text_link_colors.cc
+++ b/third_party/blink/renderer/core/dom/text_link_colors.cc
@@ -59,6 +59,7 @@
 
 Color TextLinkColors::ColorFromCSSValue(const CSSValue& value,
                                         Color current_color,
+                                        ColorScheme color_scheme,
                                         bool for_visited_link) const {
   if (value.IsColorValue())
     return ToCSSColorValue(value).Value();
@@ -78,6 +79,8 @@
       return LayoutTheme::GetTheme().FocusRingColor();
     case CSSValueCurrentcolor:
       return current_color;
+    case CSSValueInternalRootColor:
+      return LayoutTheme::GetTheme().RootElementColor(color_scheme);
     default:
       return StyleColor::ColorFromKeyword(value_id);
   }
diff --git a/third_party/blink/renderer/core/dom/text_link_colors.h b/third_party/blink/renderer/core/dom/text_link_colors.h
index 15a21d02..ba44345 100644
--- a/third_party/blink/renderer/core/dom/text_link_colors.h
+++ b/third_party/blink/renderer/core/dom/text_link_colors.h
@@ -32,6 +32,7 @@
 
 #include "base/macros.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/color_scheme.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
@@ -58,6 +59,7 @@
   void ResetActiveLinkColor();
   Color ColorFromCSSValue(const CSSValue&,
                           Color current_color,
+                          ColorScheme color_scheme,
                           bool for_visited_link = false) const;
 
  private:
diff --git a/third_party/blink/renderer/core/editing/ephemeral_range.h b/third_party/blink/renderer/core/editing/ephemeral_range.h
index 5a52b5a..5fe4f97 100644
--- a/third_party/blink/renderer/core/editing/ephemeral_range.h
+++ b/third_party/blink/renderer/core/editing/ephemeral_range.h
@@ -107,7 +107,7 @@
 
   Node* CommonAncestorContainer() const;
 
-  // Returns true if |m_startPosition| == |m_endPosition| or |isNull()|.
+  // Returns true if |start_position_| == |end_position_| or |isNull()|.
   bool IsCollapsed() const;
   bool IsNull() const {
     DCHECK(IsValid());
diff --git a/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator.h b/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator.h
index 8653c5c..f3d72ea 100644
--- a/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator.h
+++ b/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator.h
@@ -127,7 +127,7 @@
   Member<const Node> end_node_;
   int end_offset_;
 
-  // Whether m_node has advanced beyond the iteration range (i.e. start_node_).
+  // Whether |node_| has advanced beyond the iteration range (i.e. start_node_).
   bool have_passed_start_node_;
 
   // Should handle first-letter layoutObject in the next call to handleTextNode.
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index 7e64926..bc0c5eb6 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -750,7 +750,7 @@
   // early-return style.
   // When we haven't been emitting any characters,
   // ShouldRepresentNodeOffsetZero() can create VisiblePositions, which is
-  // expensive. So, we perform the inexpensive checks on m_node to see if it
+  // expensive. So, we perform the inexpensive checks on |node_| to see if it
   // necessitates emitting a character first and will early return before
   // encountering ShouldRepresentNodeOffsetZero()s worse case behavior.
   if (ShouldEmitTabBeforeNode(*node_)) {
diff --git a/third_party/blink/renderer/core/editing/position.h b/third_party/blink/renderer/core/editing/position.h
index f36799c..0973314a 100644
--- a/third_party/blink/renderer/core/editing/position.h
+++ b/third_party/blink/renderer/core/editing/position.h
@@ -257,7 +257,7 @@
     return false;
 
   if (!a.IsOffsetInAnchor()) {
-    // Note: |m_offset| only has meaning when
+    // Note: |offset_| only has meaning when
     // |PositionAnchorType::OffsetInAnchor|.
     return true;
   }
diff --git a/third_party/blink/renderer/core/editing/selection_modifier.cc b/third_party/blink/renderer/core/editing/selection_modifier.cc
index 1b2bf5a5d..618144d 100644
--- a/third_party/blink/renderer/core/editing/selection_modifier.cc
+++ b/third_party/blink/renderer/core/editing/selection_modifier.cc
@@ -240,7 +240,7 @@
   // FIXME: VisibleSelection should be fixed to ensure as an invariant that
   // base/extent always point to the same nodes as start/end, but which points
   // to which depends on the value of isBaseFirst. Then this can be changed
-  // to just return m_sel.extent().
+  // to just return selection_.extent().
   return selection_.IsBaseFirst() ? selection_.VisibleEnd()
                                   : selection_.VisibleStart();
 }
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
index 24f8140..f093d73be 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
@@ -620,9 +620,9 @@
     int word_end = iterator->next();
     if (word_end < 0)
       break;
-    int word_length = word_end - word_start;
-    int misspelling_location = -1;
-    int misspelling_length = 0;
+    size_t word_length = word_end - word_start;
+    size_t misspelling_location = 0;
+    size_t misspelling_length = 0;
     if (WebTextCheckClient* text_checker_client = GetTextCheckerClient()) {
       // SpellCheckWord will write (0, 0) into the output vars, which is what
       // our caller expects if the word is spelled correctly.
@@ -633,7 +633,7 @@
       misspelling_location = 0;
     }
     if (misspelling_length > 0) {
-      DCHECK_GE(misspelling_location, 0);
+      DCHECK_GE(misspelling_location, 0u);
       DCHECK_LE(misspelling_location + misspelling_length, word_length);
       TextCheckingResult misspelling;
       misspelling.decoration = kTextDecorationTypeSpelling;
diff --git a/third_party/blink/renderer/core/events/error_event.cc b/third_party/blink/renderer/core/events/error_event.cc
index c5980a14..8421fe0 100644
--- a/third_party/blink/renderer/core/events/error_event.cc
+++ b/third_party/blink/renderer/core/events/error_event.cc
@@ -103,7 +103,7 @@
 }
 
 ScriptValue ErrorEvent::error(ScriptState* script_state) const {
-  // Don't return |m_error| when we are in the different worlds to avoid
+  // Don't return |error_| when we are in the different worlds to avoid
   // leaking a V8 value.
   // We do not clone Error objects (exceptions), for 2 reasons:
   // 1) Errors carry a reference to the isolated world's global object, and
diff --git a/third_party/blink/renderer/core/events/error_event.h b/third_party/blink/renderer/core/events/error_event.h
index 8d1f966e..e3d1ed4 100644
--- a/third_party/blink/renderer/core/events/error_event.h
+++ b/third_party/blink/renderer/core/events/error_event.h
@@ -79,15 +79,14 @@
   ErrorEvent(ScriptState*, const AtomicString&, const ErrorEventInit*);
   ~ErrorEvent() override;
 
-  // As 'message' is exposed to JavaScript, never return unsanitizedMessage.
+  // As |message| is exposed to JavaScript, never return |unsanitized_message_|.
   const String& message() const { return sanitized_message_; }
   const String& filename() const { return location_->Url(); }
   unsigned lineno() const { return location_->LineNumber(); }
   unsigned colno() const { return location_->ColumnNumber(); }
   ScriptValue error(ScriptState*) const;
 
-  // 'messageForConsole' is not exposed to JavaScript, and prefers
-  // 'm_unsanitizedMessage'.
+  // Not exposed to JavaScript, prefers |unsanitized_message_|.
   const String& MessageForConsole() const {
     return !unsanitized_message_.IsEmpty() ? unsanitized_message_
                                            : sanitized_message_;
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory.cc b/third_party/blink/renderer/core/events/pointer_event_factory.cc
index 371719dd..9b7a27d 100644
--- a/third_party/blink/renderer/core/events/pointer_event_factory.cc
+++ b/third_party/blink/renderer/core/events/pointer_event_factory.cc
@@ -449,8 +449,8 @@
   pointer_id_last_position_mapping_.clear();
 
   // Always add mouse pointer in initialization and never remove it.
-  // No need to add it to m_pointerIncomingIdMapping as it is not going to be
-  // used with the existing APIs
+  // No need to add it to |pointer_incoming_id_mapping_| as it is not going to
+  // be used with the existing APIs
   primary_id_[ToInt(WebPointerProperties::PointerType::kMouse)] = kMouseId;
   pointer_id_mapping_[kMouseId] = PointerAttributes(
       IncomingId(WebPointerProperties::PointerType::kMouse, 0), false, true);
@@ -461,7 +461,7 @@
 PointerId PointerEventFactory::AddIdAndActiveButtons(const IncomingId p,
                                                      bool is_active_buttons,
                                                      bool hovering) {
-  // Do not add extra mouse pointer as it was added in initialization
+  // Do not add extra mouse pointer as it was added in initialization.
   if (p.GetPointerType() == WebPointerProperties::PointerType::kMouse) {
     pointer_id_mapping_[kMouseId] =
         PointerAttributes(p, is_active_buttons, true);
@@ -475,7 +475,7 @@
     return mapped_id;
   }
   int type_int = p.PointerTypeInt();
-  // We do not handle the overflow of m_currentId as it should be very rare
+  // We do not handle the overflow of |current_id_| as it should be very rare.
   PointerId mapped_id = current_id_++;
   if (!id_count_[type_int])
     primary_id_[type_int] = mapped_id;
@@ -487,7 +487,7 @@
 }
 
 bool PointerEventFactory::Remove(const PointerId mapped_id) {
-  // Do not remove mouse pointer id as it should always be there
+  // Do not remove mouse pointer id as it should always be there.
   if (mapped_id == kMouseId ||
       pointer_id_mapping_.find(mapped_id) == pointer_id_mapping_.end())
     return false;
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
index 6d6f21c..70b69ee9 100644
--- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
+++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
@@ -34,7 +34,7 @@
   void SetDefersLoading(bool) override;
   void SetLoadingTaskRunner(base::SingleThreadTaskRunner*) override;
 
-  // Called by |m_observer| to handle destruction of the Document associated
+  // Called by |observer_| to handle destruction of the Document associated
   // with the frame given to the constructor.
   void DocumentDestroyed();
 
@@ -57,13 +57,13 @@
   WebAssociatedURLLoaderClient* client_;
   WebAssociatedURLLoaderOptions options_;
 
-  // An adapter which converts the hreadableLoaderClient method
-  // calls into the WebURLLoaderClient method calls.
+  // Converts ThreadableLoaderClient method calls into WebURLLoaderClient method
+  // calls.
   Persistent<ClientAdapter> client_adapter_;
   Persistent<ThreadableLoader> loader_;
 
-  // A ContextLifecycleObserver for cancelling |m_loader| when the Document
-  // is detached.
+  // A ContextLifecycleObserver for cancelling |loader_| when the Document is
+  // detached.
   Persistent<Observer> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(WebAssociatedURLLoaderImpl);
diff --git a/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc b/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
index 5402a61..57c2ad0 100644
--- a/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
@@ -93,7 +93,7 @@
   // all the time. For instance, resetInputMethod call on RenderViewImpl could
   // be after losing the focus on frame. But since we return the core frame
   // in WebViewImpl::focusedLocalFrameInWidget(), we will reach here with
-  // |m_webLocalFrame| not focused on page.
+  // |web_frame_| not focused on page.
 
   if (WebPlugin* plugin = FocusedPluginIfInputMethodSupported())
     return plugin->FinishComposingText(selection_behavior);
diff --git a/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc b/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc
index 8a9e2ede..b296e44d 100644
--- a/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc
+++ b/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc
@@ -177,10 +177,10 @@
   test::RunPendingTasks();
   EXPECT_EQ(0, WebWidgetClient().VisuallyNonEmptyLayoutCount());
 
-  // We serve the SVG file and check visuallyNonEmptyLayoutCount() before
-  // mainResource.finish() because finishing the main resource causes
+  // We serve the SVG file and check VisuallyNonEmptyLayoutCount() before
+  // main_resource.Finish() because finishing the main resource causes
   // |FrameView::m_isVisuallyNonEmpty| to be true and
-  // visuallyNonEmptyLayoutCount() to be 1 irrespective of the SVG sizes.
+  // VisuallyNonEmptyLayoutCount() to be 1 irrespective of the SVG sizes.
   svg_resource.Start();
   svg_resource.Write(
       "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"65536\" "
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index 78061fc..7f9d083 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -548,7 +548,7 @@
 
     DestroyPage();
 
-    // m_widgetClient might be 0 because this widget might be already closed.
+    // |widget_client_| might be 0 because this widget might be already closed.
     if (widget_client_ && !close_already_called) {
       // closeWidgetSoon() will call this->close() later.
       widget_client_->CloseWidgetSoon();
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index 2bddbc7..3785477 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -1136,9 +1136,9 @@
 void WebPluginContainerImpl::CalculateGeometry(IntRect& window_rect,
                                                IntRect& clip_rect,
                                                IntRect& unobscured_rect) {
-  // document().layoutView() can be null when we receive messages from the
+  // GetDocument().LayoutView() can be null when we receive messages from the
   // plugins while we are destroying a frame.
-  // FIXME: Can we just check m_element->document().isActive() ?
+  // TODO: Can we just check element_->GetDocument().IsActive() ?
   if (element_->GetLayoutObject()->GetDocument().GetLayoutView()) {
     // Take our element and get the clip rect from the enclosing layer and
     // frame view.
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index ccfafca..d0382eda 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -734,9 +734,9 @@
                WebInputEvent::GetName(event.GetType()), "text",
                String(event.text).Utf8());
 
-  // Please refer to the comments explaining the m_suppressNextKeypressEvent
-  // member.
-  // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
+  // Please refer to the comments explaining |suppress_next_keypress_event_|.
+  //
+  // |suppress_next_keypress_event_| is set if the KeyDown is handled by
   // Webkit. A keyDown event is typically associated with a keyPress(char)
   // event and a keyUp event. We reset this flag here as this is a new keyDown
   // event.
@@ -816,8 +816,8 @@
   TRACE_EVENT1("input", "WebViewImpl::handleCharEvent", "text",
                String(event.text).Utf8());
 
-  // Please refer to the comments explaining the m_suppressNextKeypressEvent
-  // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
+  // Please refer to the comments explaining |suppress_next_keypress_event_|
+  // |suppress_next_keypress_event_| is set if the KeyDown is
   // handled by Webkit. A keyDown event is typically associated with a
   // keyPress(char) event and a keyUp event. We reset this flag here as it
   // only applies to the current keyPress event.
@@ -1107,7 +1107,7 @@
   }
 
   // TODO(dglazkov): The only reason why we're using isAnimating and not just
-  // checking for m_layerTreeView->hasPendingPageScaleAnimation() is because of
+  // checking for layer_tree_view_->HasPendingPageScaleAnimation() is because of
   // fake page scale animation plumbing for testing, which doesn't actually
   // initiate a page scale animation.
   if (is_animating) {
@@ -1793,7 +1793,7 @@
     const WebCoalescedInputEvent& coalesced_event) {
   const WebInputEvent& input_event = coalesced_event.Event();
   TRACE_EVENT1("input", "captured mouse event", "type", input_event.GetType());
-  // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
+  // Save |mouse_capture_element_| since |MouseCaptureLost()| will clear it.
   HTMLPlugInElement* element = mouse_capture_element_;
 
   // Not all platforms call mouseCaptureLost() directly.
@@ -2319,7 +2319,7 @@
   if (zoom_factor_for_device_scale_factor_) {
     if (compositor_device_scale_factor_override_) {
       // Adjust the page's DSF so that DevicePixelRatio becomes
-      // m_zoomFactorForDeviceScaleFactor.
+      // |zoom_factor_for_device_scale_factor_|.
       AsView().page->SetDeviceScaleFactorDeprecated(
           zoom_factor_for_device_scale_factor_ /
           compositor_device_scale_factor_override_);
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css
index ec50073..cde04b69 100644
--- a/third_party/blink/renderer/core/html/resources/html.css
+++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -24,7 +24,8 @@
 @namespace "http://www.w3.org/1999/xhtml";
 
 html {
-    display: block
+    display: block;
+    color: -internal-root-color;
 }
 
 /* children of the <head> element all have display:none */
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index edf0948..11df0a8 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -338,8 +338,6 @@
       track_based_logical_height += ScrollbarLogicalHeight();
 
     SetLogicalHeight(track_based_logical_height);
-
-    LayoutUnit old_client_after_edge = ClientLogicalBottom();
     UpdateLogicalHeight();
 
     // Once grid's indefinite height is resolved, we can compute the
@@ -374,7 +372,7 @@
 
     LayoutPositionedObjects(relayout_children || IsDocumentElement());
 
-    ComputeLayoutOverflow(old_client_after_edge);
+    ComputeLayoutOverflow(ClientLogicalBottom());
   }
 
   UpdateAfterLayout();
diff --git a/third_party/blink/renderer/core/layout/layout_theme.cc b/third_party/blink/renderer/core/layout/layout_theme.cc
index 1bcc0e9..e01bd3db 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -53,6 +53,7 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/fallback_theme.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
 #include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
 #include "third_party/blink/renderer/platform/fonts/string_truncator.h"
@@ -977,4 +978,10 @@
   style.ResetBorder();
 }
 
+Color LayoutTheme::RootElementColor(ColorScheme color_scheme) const {
+  if (color_scheme == ColorScheme::kDark)
+    return Color::kWhite;
+  return ComputedStyleInitialValues::InitialColor();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h
index d3b89e4..4137b78 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_selection_types.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/color_scheme.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_types.h"
 #include "third_party/blink/renderer/platform/theme_types.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -156,6 +157,11 @@
   virtual Color PlatformFocusRingColor() const { return Color(0, 0, 0); }
   void SetCustomFocusRingColor(const Color&);
   static Color TapHighlightColor();
+
+  // Root element text color. It can be different from the initial color in
+  // other color schemes than the light theme.
+  Color RootElementColor(ColorScheme) const;
+
   virtual Color PlatformTapHighlightColor() const {
     return LayoutTheme::kDefaultTapHighlightColor;
   }
diff --git a/third_party/blink/renderer/core/layout/layout_theme_test.cc b/third_party/blink/renderer/core/layout/layout_theme_test.cc
index eb40142..81adfc6 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_test.cc
@@ -71,4 +71,53 @@
   EXPECT_EQ(custom_color, OutlineColor(span));
 }
 
+TEST_F(LayoutThemeTest, RootElementColor) {
+  EXPECT_EQ(Color::kBlack,
+            LayoutTheme::GetTheme().RootElementColor(ColorScheme::kLight));
+  EXPECT_EQ(Color::kWhite,
+            LayoutTheme::GetTheme().RootElementColor(ColorScheme::kDark));
+}
+
+TEST_F(LayoutThemeTest, RootElementColorChange) {
+  SetHtmlInnerHTML(R"HTML(
+    <style>
+      #initial { color: initial }
+    </style>
+    <div id="initial"></div>
+  )HTML");
+
+  Element* initial = GetDocument().getElementById("initial");
+  ASSERT_TRUE(initial);
+  EXPECT_EQ(ColorScheme::kLight, GetDocument().GetColorScheme());
+
+  ASSERT_TRUE(GetDocument().documentElement());
+  const ComputedStyle* document_element_style =
+      GetDocument().documentElement()->GetComputedStyle();
+  ASSERT_TRUE(document_element_style);
+  EXPECT_EQ(Color::kBlack, document_element_style->VisitedDependentColor(
+                               GetCSSPropertyColor()));
+
+  const ComputedStyle* initial_style = initial->GetComputedStyle();
+  ASSERT_TRUE(initial_style);
+  EXPECT_EQ(Color::kBlack,
+            initial_style->VisitedDependentColor(GetCSSPropertyColor()));
+
+  // Change color scheme to dark.
+  GetDocument().SetColorScheme(ColorScheme::kDark);
+  EXPECT_EQ(ColorScheme::kDark, GetDocument().GetColorScheme());
+  UpdateAllLifecyclePhasesForTest();
+
+  document_element_style = GetDocument().documentElement()->GetComputedStyle();
+  ASSERT_TRUE(document_element_style);
+  EXPECT_EQ(Color::kWhite, document_element_style->VisitedDependentColor(
+                               GetCSSPropertyColor()));
+
+  initial_style = initial->GetComputedStyle();
+  ASSERT_TRUE(initial_style);
+  // Theming does not change the initial value for color, only the UA style for
+  // the root element.
+  EXPECT_EQ(Color::kBlack,
+            initial_style->VisitedDependentColor(GetCSSPropertyColor()));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc
index 214bb03e..e444a94 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -408,7 +408,7 @@
       description.Split('\n', suggestions);
       data.dictionary_suggestions = suggestions;
     } else if (spell_checker.GetTextCheckerClient()) {
-      int misspelled_offset, misspelled_length;
+      size_t misspelled_offset, misspelled_length;
       spell_checker.GetTextCheckerClient()->CheckSpelling(
           data.misspelled_word, misspelled_offset, misspelled_length,
           &data.dictionary_suggestions);
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.h b/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
index b47adc9..b2d1a16 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
@@ -112,8 +112,6 @@
   void NotifyAnimationFinished(double monotonic_time, int group) override {}
   void NotifyAnimationAborted(double monotonic_time, int group) override {}
 
-  void Dispose();
-
   Document* GetDocument() const override { return document_.Get(); }
   AnimationTimeline* GetTimeline() const override { return timeline_; }
   const String& Name() { return animator_name_; }
@@ -130,11 +128,14 @@
   void SetOutputState(
       const AnimationWorkletOutput::AnimationState& state) override;
 
+  base::Optional<base::TimeDelta> CurrentTime() const;
+
   void SetRunningOnMainThreadForTesting(bool running_on_main_thread) {
     running_on_main_thread_ = running_on_main_thread;
   }
 
   void Trace(blink::Visitor*) override;
+  void Dispose();
 
  private:
   void DestroyCompositorAnimation();
@@ -186,7 +187,6 @@
   void SetPlayState(const Animation::AnimationPlayState& state) {
     play_state_ = state;
   }
-  base::Optional<base::TimeDelta> CurrentTime() const;
 
   unsigned sequence_number_;
 
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
index 3e43f039..0b2acdd 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
@@ -22,6 +22,14 @@
 
 namespace {
 
+// Only expect precision up to 1 microsecond with an additional epsilon to
+// account for float conversion error (mainly due to timeline time getting
+// converted between float and TimeDelta).
+static constexpr double time_error_ms = 0.001 + 1e-13;
+
+#define EXPECT_TIME_NEAR(expected, value) \
+  EXPECT_NEAR(expected, value, time_error_ms)
+
 KeyframeEffectModelBase* CreateEffectModel() {
   StringKeyframeVector frames_mixed_properties;
   Persistent<StringKeyframe> keyframe = StringKeyframe::Create();
@@ -123,18 +131,9 @@
 
 TEST_F(WorkletAnimationTest,
        CurrentTimeFromDocumentTimelineIsOffsetByStartTime) {
-  // Only expect precision up to 1 microsecond with an additional smaller
-  // component to account for double rounding/conversion error.
-  double error =
-      base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF() + 1e-13;
-
   WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
-  base::TimeTicks first_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111);
-  base::TimeTicks second_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 123.4);
 
-  GetDocument().GetAnimationClock().ResetTimeForTesting(first_ticks);
+  SimulateFrame(111);
   worklet_animation_->play(ASSERT_NO_EXCEPTION);
   worklet_animation_->UpdateCompositingState();
 
@@ -144,12 +143,13 @@
   // First state request sets the start time and thus current time should be 0.
   std::unique_ptr<AnimationWorkletInput> input =
       state->TakeWorkletState(id.worklet_id);
-  EXPECT_NEAR(0, input->added_and_updated_animations[0].current_time, error);
+  EXPECT_TIME_NEAR(0, input->added_and_updated_animations[0].current_time);
+
+  SimulateFrame(111 + 123.4);
   state.reset(new AnimationWorkletDispatcherInput);
-  GetDocument().GetAnimationClock().ResetTimeForTesting(second_ticks);
   worklet_animation_->UpdateInputState(state.get());
   input = state->TakeWorkletState(id.worklet_id);
-  EXPECT_NEAR(123.4, input->updated_animations[0].current_time, error);
+  EXPECT_TIME_NEAR(123.4, input->updated_animations[0].current_time);
 }
 
 TEST_F(WorkletAnimationTest,
@@ -180,39 +180,24 @@
       ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
   WorkletAnimation* worklet_animation = CreateWorkletAnimation(
       GetScriptState(), element_, animator_name_, scroll_timeline);
-  WorkletAnimationId id = worklet_animation->GetWorkletAnimationId();
 
   worklet_animation->play(ASSERT_NO_EXCEPTION);
   worklet_animation->UpdateCompositingState();
 
-  // Only expect precision up to 1 microsecond with an additional smaller
-  // component to account for double rounding/conversion error.
-  double error =
-      base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF() + 1e-13;
   scrollable_area->SetScrollOffset(ScrollOffset(0, 40), kProgrammaticScroll);
-  std::unique_ptr<AnimationWorkletDispatcherInput> state =
-      std::make_unique<AnimationWorkletDispatcherInput>();
-  worklet_animation->UpdateInputState(state.get());
-  std::unique_ptr<AnimationWorkletInput> input =
-      state->TakeWorkletState(id.worklet_id);
 
-  EXPECT_NEAR(40, input->added_and_updated_animations[0].current_time, error);
-  state.reset(new AnimationWorkletDispatcherInput);
+  EXPECT_TIME_NEAR(40,
+                   worklet_animation->CurrentTime().value().InMillisecondsF());
 
   scrollable_area->SetScrollOffset(ScrollOffset(0, 70), kProgrammaticScroll);
-  worklet_animation->UpdateInputState(state.get());
-  input = state->TakeWorkletState(id.worklet_id);
-  EXPECT_NEAR(70, input->updated_animations[0].current_time, error);
+  EXPECT_TIME_NEAR(70,
+                   worklet_animation->CurrentTime().value().InMillisecondsF());
 }
 
 TEST_F(WorkletAnimationTest, MainThreadSendsPeekRequestTest) {
   WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
-  base::TimeTicks first_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111);
-  base::TimeTicks second_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 123.4);
 
-  GetDocument().GetAnimationClock().ResetTimeForTesting(first_ticks);
+  SimulateFrame(111.0);
   worklet_animation_->play(ASSERT_NO_EXCEPTION);
   worklet_animation_->UpdateCompositingState();
 
@@ -253,7 +238,9 @@
   state.reset(new AnimationWorkletDispatcherInput);
 
   // Input time changes. Need to peek again.
-  GetDocument().GetAnimationClock().ResetTimeForTesting(second_ticks);
+  GetDocument().GetAnimationClock().ResetTimeForTesting(
+      base::TimeTicks() + ToTimeDelta(111.0 + 123.4));
+
   worklet_animation_->UpdateInputState(state.get());
   input = state->TakeWorkletState(id.worklet_id);
   EXPECT_EQ(input->peeked_animations.size(), 1u);
@@ -266,120 +253,71 @@
 // Verifies correctness of current time when playback rate is set while the
 // animation is in idle state.
 TEST_F(WorkletAnimationTest, DocumentTimelineSetPlaybackRate) {
-  GetDocument().GetAnimationClock().ResetTimeForTesting();
-  GetDocument().Timeline().ResetForTesting();
-  double error = base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF();
-
-  WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
-  base::TimeTicks first_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111.0);
-  base::TimeTicks second_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111.0 + 123.4);
   double playback_rate = 2.0;
 
-  GetDocument().GetAnimationClock().ResetTimeForTesting(first_ticks);
-  DummyExceptionStateForTesting exception_state;
+  SimulateFrame(111.0);
   worklet_animation_->setPlaybackRate(nullptr, playback_rate);
-  worklet_animation_->play(exception_state);
+  worklet_animation_->play(ASSERT_NO_EXCEPTION);
   worklet_animation_->UpdateCompositingState();
-
-  std::unique_ptr<AnimationWorkletDispatcherInput> state =
-      std::make_unique<AnimationWorkletDispatcherInput>();
-  worklet_animation_->UpdateInputState(state.get());
-
-  std::unique_ptr<AnimationWorkletInput> input =
-      state->TakeWorkletState(id.worklet_id);
-
   // Zero current time is not impacted by playback rate.
-  EXPECT_NEAR(0, input->added_and_updated_animations[0].current_time, error);
-  state.reset(new AnimationWorkletDispatcherInput);
-
+  EXPECT_TIME_NEAR(0,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
   // Play the animation until second_ticks.
-  GetDocument().GetAnimationClock().ResetTimeForTesting(second_ticks);
-  worklet_animation_->UpdateInputState(state.get());
-  input = state->TakeWorkletState(id.worklet_id);
-
+  SimulateFrame(111.0 + 123.4);
   // Verify that the current time is updated playback_rate faster than the
   // timeline time.
-  EXPECT_NEAR(123.4 * playback_rate, input->updated_animations[0].current_time,
-              error);
+  EXPECT_TIME_NEAR(123.4 * playback_rate,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
 }
 
 // Verifies correctness of current time when playback rate is set while the
 // animation is playing.
 TEST_F(WorkletAnimationTest, DocumentTimelineSetPlaybackRateWhilePlaying) {
-  GetDocument().GetAnimationClock().ResetTimeForTesting();
-  GetDocument().Timeline().ResetForTesting();
-  double error = base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF();
-
-  WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
-  base::TimeTicks first_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111.0);
-  base::TimeTicks second_ticks =
-      base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111.0 + 123.4);
-  base::TimeTicks third_ticks =
-      base::TimeTicks() +
-      base::TimeDelta::FromMillisecondsD(111.0 + 123.4 + 200.0);
+  SimulateFrame(0);
   double playback_rate = 0.5;
-
   // Start animation.
-  GetDocument().GetAnimationClock().ResetTimeForTesting(first_ticks);
-  DummyExceptionStateForTesting exception_state;
-  worklet_animation_->play(exception_state);
+  SimulateFrame(111.0);
+  worklet_animation_->play(ASSERT_NO_EXCEPTION);
   worklet_animation_->UpdateCompositingState();
-  std::unique_ptr<AnimationWorkletDispatcherInput> state =
-      std::make_unique<AnimationWorkletDispatcherInput>();
-  worklet_animation_->UpdateInputState(state.get());
-  state.reset(new AnimationWorkletDispatcherInput);
-
   // Update playback rate after second tick.
-  GetDocument().GetAnimationClock().ResetTimeForTesting(second_ticks);
-  worklet_animation_->UpdateInputState(state.get());
+  SimulateFrame(111.0 + 123.4);
   worklet_animation_->setPlaybackRate(nullptr, playback_rate);
-  state.reset(new AnimationWorkletDispatcherInput);
-
   // Verify current time after third tick.
-  GetDocument().GetAnimationClock().ResetTimeForTesting(third_ticks);
-  worklet_animation_->UpdateInputState(state.get());
-  std::unique_ptr<AnimationWorkletInput> input =
-      state->TakeWorkletState(id.worklet_id);
-  EXPECT_NEAR(123.4 + 200.0 * playback_rate,
-              input->updated_animations[0].current_time, error);
+  SimulateFrame(111.0 + 123.4 + 200.0);
+  EXPECT_TIME_NEAR(123.4 + 200.0 * playback_rate,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
 }
 
 TEST_F(WorkletAnimationTest, PausePlay) {
-  double error =
-      base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF() + 1e-13;
-
   SimulateFrame(0);
   worklet_animation_->play(ASSERT_NO_EXCEPTION);
   EXPECT_EQ(Animation::kPending, worklet_animation_->PlayState());
   SimulateFrame(0);
   EXPECT_EQ(Animation::kRunning, worklet_animation_->PlayState());
   EXPECT_TRUE(worklet_animation_->Playing());
-  EXPECT_NEAR(0, worklet_animation_->CurrentTime().value().InMillisecondsF(),
-              error);
+  EXPECT_TIME_NEAR(0,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
   SimulateFrame(10);
   worklet_animation_->pause(ASSERT_NO_EXCEPTION);
   EXPECT_EQ(Animation::kPaused, worklet_animation_->PlayState());
   EXPECT_FALSE(worklet_animation_->Playing());
-  EXPECT_NEAR(10, worklet_animation_->CurrentTime().value().InMillisecondsF(),
-              error);
+  EXPECT_TIME_NEAR(10,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
   SimulateFrame(20);
   EXPECT_EQ(Animation::kPaused, worklet_animation_->PlayState());
-  EXPECT_NEAR(10, worklet_animation_->CurrentTime().value().InMillisecondsF(),
-              error);
+  EXPECT_TIME_NEAR(10,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
   worklet_animation_->play(ASSERT_NO_EXCEPTION);
   EXPECT_EQ(Animation::kPending, worklet_animation_->PlayState());
   SimulateFrame(20);
   EXPECT_EQ(Animation::kRunning, worklet_animation_->PlayState());
   EXPECT_TRUE(worklet_animation_->Playing());
-  EXPECT_NEAR(10, worklet_animation_->CurrentTime().value().InMillisecondsF(),
-              error);
+  EXPECT_TIME_NEAR(10,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
   SimulateFrame(30);
   EXPECT_EQ(Animation::kRunning, worklet_animation_->PlayState());
-  EXPECT_NEAR(20, worklet_animation_->CurrentTime().value().InMillisecondsF(),
-              error);
+  EXPECT_TIME_NEAR(20,
+                   worklet_animation_->CurrentTime().value().InMillisecondsF());
 }
 
 }  //  namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
index 470ffea..f6d7045 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -309,7 +309,7 @@
 
   virtual bool EnableDownloadInProductHelp() { return false; }
 
-  const String& GetDisplayedTime(MediaControlTimeDisplayElement* display) {
+  const String GetDisplayedTime(MediaControlTimeDisplayElement* display) {
     return ToText(display->firstChild())->data();
   }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
index 57fa303..99d530b 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -130,7 +130,7 @@
       bool subscribe_audio_output,
       mojom::blink::MediaDevicesListenerPtr listener) override {
     listener_ = std::move(listener);
-  };
+  }
 
   mojom::blink::MediaDevicesDispatcherHostPtr CreateInterfacePtrAndBind() {
     mojom::blink::MediaDevicesDispatcherHostPtr ptr;
diff --git a/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc b/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
index e692189..c9f0ba8f 100644
--- a/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
+++ b/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
@@ -37,7 +37,7 @@
 class TestAnimationWorkletProxyClient : public AnimationWorkletProxyClient {
  public:
   TestAnimationWorkletProxyClient()
-      : AnimationWorkletProxyClient(0, nullptr, nullptr, nullptr, nullptr){};
+      : AnimationWorkletProxyClient(0, nullptr, nullptr, nullptr, nullptr) {}
   void AddGlobalScope(WorkletGlobalScope*) override {}
 };
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 0831adfb..2476278 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -850,6 +850,7 @@
     "graphics/color_behavior.cc",
     "graphics/color_behavior.h",
     "graphics/color_blend.h",
+    "graphics/color_scheme.h",
     "graphics/color_space_gamut.cc",
     "graphics/color_space_gamut.h",
     "graphics/color_space_profile_data.cc",
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
index eb2aad3..22dfb45 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
@@ -187,7 +187,8 @@
   // Don't attempt to park strings smaller than this size.
   static constexpr unsigned int kSizeThreshold = 10000;
   // TODO(lizeb): Consider parking non-main thread strings.
-  return string.length() > kSizeThreshold && IsMainThread();
+  return string.length() > kSizeThreshold && IsMainThread() &&
+         GetCompressionMode() != CompressionMode::kDisabled;
 }
 
 scoped_refptr<ParkableStringImpl> ParkableStringManager::Add(
diff --git a/third_party/blink/renderer/platform/graphics/color_scheme.h b/third_party/blink/renderer/platform/graphics/color_scheme.h
new file mode 100644
index 0000000..e3b4564
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/color_scheme.h
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_SCHEME_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_SCHEME_H_
+
+namespace blink {
+
+// This is the color scheme for rendering web content. The color scheme affects
+// the UA style sheet (setting the text color to white instead of black on the
+// root element for kDark), the frame backdrop color (black instead of white for
+// kDark), theming form controls and scrollbars, etc.
+enum class ColorScheme {
+  kLight,
+  kDark,
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_SCHEME_H_
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index e30fe3e..fcaa534 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -267,7 +267,6 @@
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_top [ Pass ]
 crbug.com/591099 external/wpt/html/dom/interfaces.worker.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html [ Pass ]
-crbug.com/591099 external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html [ Pass Timeout ]
 crbug.com/845902 external/wpt/quirks/line-height-trailing-collapsable-whitespace.html [ Pass ]
 crbug.com/591099 external/wpt/wasm/jsapi/constructor/instantiate.any.html [ Failure ]
 crbug.com/591099 external/wpt/wasm/jsapi/constructor/instantiate.any.worker.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 428d1e9..deae23b 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3074,6 +3074,18 @@
 crbug.com/918664 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/block-size-with-min-or-max-content-table-1a.html [ Failure Pass ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.10 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.11 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html [ Failure Timeout ]
+crbug.com/626703 [ Retina ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html [ Timeout ]
+crbug.com/626703 [ Win7 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Failure Timeout ]
+crbug.com/626703 [ Win10 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Failure Timeout ]
+crbug.com/626703 [ Linux ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.11 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Failure Timeout ]
+crbug.com/626703 [ Retina ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Timeout ]
+crbug.com/626703 [ Win7 ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html [ Timeout ]
 crbug.com/626703 crbug.com/930297 [ Linux ] external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1251.html [ Timeout Pass Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1251.html [ Failure Timeout ]
@@ -3167,8 +3179,6 @@
 crbug.com/626703 [ Android ] external/wpt/css/css-layout-api/auto-block-size-absolute.https.html [ Failure ]
 crbug.com/626703 [ Mac10.10 ] external/wpt/css/css-layout-api/auto-block-size-absolute.https.html [ Failure ]
 crbug.com/626703 external/wpt/infrastructure/testdriver/file_upload.sub.html [ Skip ]
-crbug.com/626703 crbug.com/913932 [ Android Mac ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html [ Failure Timeout ]
-crbug.com/626703 crbug.com/913932 [ Win ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-space-collapse-preserve-breaks-001.xht [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-space-collapse-discard-001.xht [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-space-trim-trim-inner-001.xht [ Failure ]
@@ -6058,3 +6068,6 @@
 crbug.com/929122 [ Linux ] external/wpt/html/dom/interfaces.worker.html [ Timeout Failure ]
 crbug.com/929355 [ Linux ] external/wpt/webrtc/RTCPeerConnection-track-stats.https.html [ Pass Failure ]
 crbug.com/929435 [ Mac ] external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html [ Pass Failure ]
+
+# Sheriff 2019-02-11
+crbug.com/930654 [ Linux ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCIceTransport-extension.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/animations/animationworklet/resources/animation-worklet-tests.js b/third_party/blink/web_tests/animations/animationworklet/resources/animation-worklet-tests.js
index a06dea8..18b96c0 100644
--- a/third_party/blink/web_tests/animations/animationworklet/resources/animation-worklet-tests.js
+++ b/third_party/blink/web_tests/animations/animationworklet/resources/animation-worklet-tests.js
@@ -14,13 +14,24 @@
     }
   }
   rafCallback();
-};
+}
 
 // Wait for two main thread frames to guarantee that compositor has produced
 // at least one frame.
 function waitTwoAnimationFrames(callback) {
   waitForAnimationFrames(2, callback);
-};
+}
+
+function waitForAsyncAnimationFrame() {
+  return new Promise(waitTwoAnimationFrames);
+}
+
+async function waitForDocumentTimelineAdvance() {
+  const timeAtStart = document.timeline.currentTime;
+  do {
+    await new Promise(window.requestAnimationFrame);
+  } while (timeAtStart === document.timeline.currentTime)
+}
 
 // Load test cases in worklet context in sequence and wait until they are resolved.
 function runTests(testcases) {
diff --git a/third_party/blink/web_tests/animations/animationworklet/worklet-animation-currentTime.html b/third_party/blink/web_tests/animations/animationworklet/worklet-animation-currentTime.html
index 917fcbe..f97397f 100644
--- a/third_party/blink/web_tests/animations/animationworklet/worklet-animation-currentTime.html
+++ b/third_party/blink/web_tests/animations/animationworklet/worklet-animation-currentTime.html
@@ -21,25 +21,22 @@
 <div id="target"></div>
 <script src="resources/animation-worklet-tests.js"></script>
 <script>
-async_test(t => {
-runInAnimationWorklet(
-  document.getElementById('simple_animate').textContent
-).then(_ => {
+promise_test(async t => {
+  await runInAnimationWorklet(document.getElementById('simple_animate').textContent);
   const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 });
   const animation = new WorkletAnimation('test_animator', effect);
   const first_opacity = getComputedStyle(target).opacity;
   assert_equals(first_opacity, '1');
   animation.play();
-
-  waitTwoAnimationFrames(() => {
-    // waitTwoAnimationFrames guarantees a compositor frame that could update
-    // the opacity value in the worklet. Meanwhile, getComputedStyle needs an
-    // extra frame to fetch the updated value.
-    window.requestAnimationFrame(t.step_func_done(() => {
-      const second_opacity = getComputedStyle(target).opacity;
-      assert_true(second_opacity < first_opacity);
-    }));
-  });
-});
+  // Wait for one async animation frame to ensure animation is running.
+  await waitForAsyncAnimationFrame();
+  await waitForDocumentTimelineAdvance();
+  assert_greater_than(animation.currentTime, 0);
+  // At this point we are guaranteed that opacity value is updated in the
+  // worklet but  getComputedStyle needs an extra frame to fetch the updated
+  // value to main thread.
+  await new Promise(window.requestAnimationFrame);
+  const second_opacity = getComputedStyle(target).opacity;
+  assert_true(second_opacity < first_opacity);
 }, 'Opacity should change as the animation starts.');
 </script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 660db4f..47d34e3 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -5539,6 +5539,12 @@
      {}
     ]
    ],
+   "payment-request/payment-request-hasenrolledinstrument-method-manual.https.html": [
+    [
+     "/payment-request/payment-request-hasenrolledinstrument-method-manual.https.html",
+     {}
+    ]
+   ],
    "payment-request/payment-request-multiple-show-manual.https.html": [
     [
      "/payment-request/payment-request-multiple-show-manual.https.html",
@@ -6825,6 +6831,54 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-pause-immediately.https.html": [
+    [
+     "/animation-worklet/worklet-animation-pause-immediately.https.html",
+     [
+      [
+       "/animation-worklet/references/translated-box-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "animation-worklet/worklet-animation-pause-resume.https.html": [
+    [
+     "/animation-worklet/worklet-animation-pause-resume.https.html",
+     [
+      [
+       "/animation-worklet/references/translated-box-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "animation-worklet/worklet-animation-set-keyframes.https.html": [
+    [
+     "/animation-worklet/worklet-animation-set-keyframes.https.html",
+     [
+      [
+       "/animation-worklet/worklet-animation-set-keyframes-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "animation-worklet/worklet-animation-set-timing.https.html": [
+    [
+     "/animation-worklet/worklet-animation-set-timing.https.html",
+     [
+      [
+       "/animation-worklet/worklet-animation-set-timing-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "apng/animated-png-timeout.html": [
     [
      "/apng/animated-png-timeout.html",
@@ -30209,6 +30263,18 @@
      {}
     ]
    ],
+   "css/css-align/baseline-of-scrollable-2.html": [
+    [
+     "/css/css-align/baseline-of-scrollable-2.html",
+     [
+      [
+       "/css/css-align/reference/baseline-of-scrollable-2-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-align/content-distribution/place-content-shorthand-007.html": [
     [
      "/css/css-align/content-distribution/place-content-shorthand-007.html",
@@ -48577,6 +48643,102 @@
      {}
     ]
    ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box-with-horizontal-scrollbar.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box-with-vertical-scrollbar.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box-with-scrollbars.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html": [
+    [
+     "/css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html",
+     [
+      [
+       "/css/css-grid/grid-model/reference/100x100-grey-box.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-grid/grid-model/grid-container-ignores-first-letter-002.html": [
     [
      "/css/css-grid/grid-model/grid-container-ignores-first-letter-002.html",
@@ -116497,6 +116659,11 @@
      {}
     ]
    ],
+   "animation-worklet/references/translated-box-ref.html": [
+    [
+     {}
+    ]
+   ],
    "animation-worklet/resources/animator-iframe.html": [
     [
      {}
@@ -116512,6 +116679,16 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-set-keyframes-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "animation-worklet/worklet-animation-set-timing-ref.html": [
+    [
+     {}
+    ]
+   ],
    "apng/META.yml": [
     [
      {}
@@ -125887,6 +126064,11 @@
      {}
     ]
    ],
+   "css/css-align/reference/baseline-of-scrollable-2-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-align/reference/ttwf-reftest-alignContent-ref.html": [
     [
      {}
@@ -138667,6 +138849,26 @@
      {}
     ]
    ],
+   "css/css-grid/grid-model/reference/100x100-grey-box-with-horizontal-scrollbar.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/reference/100x100-grey-box-with-scrollbars.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/reference/100x100-grey-box-with-vertical-scrollbar.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/grid-model/reference/100x100-grey-box.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-grid/grid-model/support/grid.css": [
     [
      {}
@@ -171597,7 +171799,12 @@
      {}
     ]
    ],
-   "html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_iplicit_noopener.html": [
+   "html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_implicit_noopener.html": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener-expected.txt": [
     [
      {}
     ]
@@ -171607,6 +171814,11 @@
      {}
     ]
    ],
+   "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/links/linktypes/alternate-css-ref.html": [
     [
      {}
@@ -178217,6 +178429,16 @@
      {}
     ]
    ],
+   "payment-request/payment-request-hasenrolledinstrument-method-protection.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "payment-request/payment-request-hasenrolledinstrument-method.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "payment-request/payment-request-show-method.https-expected.txt": [
     [
      {}
@@ -202778,6 +203000,12 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-pause.https.html": [
+    [
+     "/animation-worklet/worklet-animation-pause.https.html",
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-with-fill-mode.https.html": [
     [
      "/animation-worklet/worklet-animation-with-fill-mode.https.html",
@@ -245144,9 +245372,15 @@
      {}
     ]
    ],
-   "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html": [
+   "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html": [
     [
-     "/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html",
+     "/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html",
+     {}
+    ]
+   ],
+   "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html": [
+    [
+     "/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html",
      {}
     ]
    ],
@@ -265154,6 +265388,22 @@
      {}
     ]
    ],
+   "payment-request/payment-request-hasenrolledinstrument-method-protection.https.html": [
+    [
+     "/payment-request/payment-request-hasenrolledinstrument-method-protection.https.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "payment-request/payment-request-hasenrolledinstrument-method.https.html": [
+    [
+     "/payment-request/payment-request-hasenrolledinstrument-method.https.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "payment-request/payment-request-id-attribute.https.html": [
     [
      "/payment-request/payment-request-id-attribute.https.html",
@@ -307748,7 +307998,7 @@
    "testharness"
   ],
   "animation-worklet/common.js": [
-   "eb114f24687289fcdd0515ead7dbbc074c7ccbba",
+   "983c22403c44256f11ca470f2f74410ac3b84e08",
    "support"
   ],
   "animation-worklet/current-time.https.html": [
@@ -307771,6 +308021,10 @@
    "9c975814f1ed09b3e78493df177c3c0eddf74cdd",
    "testharness"
   ],
+  "animation-worklet/references/translated-box-ref.html": [
+   "c73f5a177bf70f3a71d981bc9f04b38c5afe9f1c",
+   "support"
+  ],
   "animation-worklet/resources/animator-iframe.html": [
    "e30cc281fcdefd8d029e7bf0ea92a1a9cd7af7e7",
    "support"
@@ -307795,6 +308049,34 @@
    "addb16e7d1751280c8d4f3e0052b808ab807cd7e",
    "reftest"
   ],
+  "animation-worklet/worklet-animation-pause-immediately.https.html": [
+   "f9dcf30bc908adb4e6b260dd00263e434a9b9ae4",
+   "reftest"
+  ],
+  "animation-worklet/worklet-animation-pause-resume.https.html": [
+   "f26a93468c07de8e59a3826cb39c6bdf2618706f",
+   "reftest"
+  ],
+  "animation-worklet/worklet-animation-pause.https.html": [
+   "417db9e37a61193a99908648e4cbc3be4c2e9618",
+   "testharness"
+  ],
+  "animation-worklet/worklet-animation-set-keyframes-ref.html": [
+   "26bf33fdb403877f2e3adf9b8bb3fca6bf8301bb",
+   "support"
+  ],
+  "animation-worklet/worklet-animation-set-keyframes.https.html": [
+   "017408494602ff51aec483ccc6dd0dd2f82bba4e",
+   "reftest"
+  ],
+  "animation-worklet/worklet-animation-set-timing-ref.html": [
+   "8c354a8b06f815d4f8000895964b59c3f6c242e4",
+   "support"
+  ],
+  "animation-worklet/worklet-animation-set-timing.https.html": [
+   "ac3f05f4234ac1036e388536c4237686b07e6037",
+   "reftest"
+  ],
   "animation-worklet/worklet-animation-with-fill-mode.https.html": [
    "b910ab280ec80725eee7894e8331cf72f6c24492",
    "testharness"
@@ -326176,7 +326458,7 @@
    "support"
   ],
   "css/CSS2/reference/filler-text-below-green.xht": [
-   "d4aa114316a8ef553f89d1fd63b6df626840cb40",
+   "f9609b1d8ac99b5ba5f98934e9097118beb7f0e8",
    "support"
   ],
   "css/CSS2/reference/float-applies-to-001-ref.xht": [
@@ -326196,11 +326478,11 @@
    "support"
   ],
   "css/CSS2/reference/no-red-filler-text-ref.xht": [
-   "25fcdae35efde8e5f1dd6a80a0bd36a34d4f43eb",
+   "73c348f151af1f556c30e972bf6f87e2107fe25e",
    "support"
   ],
   "css/CSS2/reference/no-red-on-blank-page-ref.xht": [
-   "04606c197671c28f155310b457ffe87a8b2e0c64",
+   "810e90fd42d7b5fd01783ff43ee00078f9d14a03",
    "support"
   ],
   "css/CSS2/reference/no_red_bold_italic_small-caps_ahem.html": [
@@ -329223,6 +329505,10 @@
    "79db8a85434beb60f7f6ef259bc2eff62d83bea3",
    "reftest"
   ],
+  "css/css-align/baseline-of-scrollable-2.html": [
+   "5511d6d68ad0b531cdd31da352e7a78e3a6b85b7",
+   "reftest"
+  ],
   "css/css-align/content-distribution/parse-align-content-001.html": [
    "c5cd4254f707824dacd0475eab9e8e1c59c02632",
    "testharness"
@@ -329459,6 +329745,10 @@
    "422660aff6b6b486ce3288469b4769e1497b071e",
    "support"
   ],
+  "css/css-align/reference/baseline-of-scrollable-2-ref.html": [
+   "dde290994818279e1637d6f1ed0138385790025a",
+   "support"
+  ],
   "css/css-align/reference/ttwf-reftest-alignContent-ref.html": [
    "a94c1d5e9e85dfe0aec20145b25e55dc5b1a673d",
    "support"
@@ -334400,7 +334690,7 @@
    "reftest"
   ],
   "css/css-color/t31-color-text-a-ref.xht": [
-   "f11a57ffb3e841ced39cfe5f6a538d9341b2ed93",
+   "95a0e03ac8a0559dbf3a2a1276ab28067dac7230",
    "support"
   ],
   "css/css-color/t31-color-text-a.xht": [
@@ -337040,7 +337330,7 @@
    "reftest"
   ],
   "css/css-flexbox/flex-grow-007.html": [
-   "da48135b9812e7f448cfe2c72bf8f382a90f7016",
+   "04a3041ed5c5f9382d89d572fceaeb249b4e69f1",
    "reftest"
   ],
   "css/css-flexbox/flex-items-flexibility.html": [
@@ -337200,7 +337490,7 @@
    "reftest"
   ],
   "css/css-flexbox/flex-shrink-008.html": [
-   "a010448993944fb682e81a990741a5de8387e13a",
+   "c93a3febdef6fd10be4790a57c702abcc025d3de",
    "reftest"
   ],
   "css/css-flexbox/flex-vertical-align-effect.html": [
@@ -349647,6 +349937,38 @@
    "e080ed8c95ce5ab8e1f9d89a3ef8523de8bd88cc",
    "reftest"
   ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html": [
+   "f1b8567f34ea197a02c837c9cec54e0afb51cd71",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html": [
+   "dee656adcdcb899a1a22412e813dee3bc06e25d4",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html": [
+   "3d13eab22b8abb28284a13d7009e06ede20b0e14",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html": [
+   "c4cd8b995dad9f956135b1a6a604d4bb6dc055a6",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html": [
+   "afbde569602009733696669a6bb97b39d6d3a18d",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html": [
+   "4c689acb6010de420d06f2e8eff4aeadedceea2e",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html": [
+   "96faa81db3d5453fa6c5f8fc60ce1ff53f99d29e",
+   "reftest"
+  ],
+  "css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html": [
+   "baab7ca34fc9c783b9b21fd0154b76ee4e459e81",
+   "reftest"
+  ],
   "css/css-grid/grid-model/grid-box-sizing-001.html": [
    "b99029293466ddfb514f401931161d75cbd5917c",
    "testharness"
@@ -349811,6 +350133,22 @@
    "209b6b263a0d1543c81cc25809ac8c834dc97226",
    "reftest"
   ],
+  "css/css-grid/grid-model/reference/100x100-grey-box-with-horizontal-scrollbar.html": [
+   "8f73ef1207be9cad1997d8881beb8b4fd8a835c9",
+   "support"
+  ],
+  "css/css-grid/grid-model/reference/100x100-grey-box-with-scrollbars.html": [
+   "e464ab879f4e97077d26c210804ca1a49c9b9173",
+   "support"
+  ],
+  "css/css-grid/grid-model/reference/100x100-grey-box-with-vertical-scrollbar.html": [
+   "26b4b6927e9b2b0cfcd08efe0c725fe4b90b0506",
+   "support"
+  ],
+  "css/css-grid/grid-model/reference/100x100-grey-box.html": [
+   "0592f6d2ce582c3c89b9d7f5278eed9458531c3c",
+   "support"
+  ],
   "css/css-grid/grid-model/support/grid.css": [
    "78fdd5e975ad61d3a8c39fe4e05694a278753c37",
    "support"
@@ -384436,7 +384774,7 @@
    "reftest"
   ],
   "css/reference/pass_if_filler_text_slanted.xht": [
-   "3d1c7fd0347967e5fb14752bd17068faa38b28e0",
+   "bb2e25cdb57c92ff1f7451fa5d0eb7568648dcd3",
    "support"
   ],
   "css/reference/pass_if_filler_text_underlined-notref.html": [
@@ -415191,16 +415529,28 @@
    "dd2d719134fd7573e85c9a696350cffa1705b661",
    "support"
   ],
-  "html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_iplicit_noopener.html": [
+  "html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_implicit_noopener.html": [
    "bf6a1ae5bfe16e4fd50296636894859a0ee25ec1",
    "support"
   ],
+  "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener-expected.txt": [
+   "160569fe3a52dff95244f6968ada71d58eb3ed3c",
+   "support"
+  ],
+  "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html": [
+   "32bf32c30418fa32e376f6813d72d7e3a74f72d4",
+   "testharness"
+  ],
   "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative-expected.txt": [
    "f6a44d6bfb0ac1777716ca9ea90561f33fc7a587",
    "support"
   ],
-  "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html": [
-   "39903dcd520c52669f7ab15494777a63c6e7c1b1",
+  "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base-expected.txt": [
+   "aab46c1ec6afd0709f9e87e761ad0f0fcc0ebeb5",
+   "support"
+  ],
+  "html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html": [
+   "44b91a2ffb0c5c09cdf2ab4f2246c5f7bb28f5dc",
    "testharness"
   ],
   "html/semantics/links/linktypes/alternate-css-ref.html": [
@@ -433875,6 +434225,26 @@
    "5f888f0389f6c756ede8c3e481ece7bcf8b71ccf",
    "testharness"
   ],
+  "payment-request/payment-request-hasenrolledinstrument-method-manual.https.html": [
+   "a4e8028c07f50514b03a7f10b80e1b3ba80bc505",
+   "manual"
+  ],
+  "payment-request/payment-request-hasenrolledinstrument-method-protection.https-expected.txt": [
+   "6718c1b5bd3c6678f13d83b0dd795e851826ee11",
+   "support"
+  ],
+  "payment-request/payment-request-hasenrolledinstrument-method-protection.https.html": [
+   "4da11304a21427040f72317e3746feebb251d12e",
+   "testharness"
+  ],
+  "payment-request/payment-request-hasenrolledinstrument-method.https-expected.txt": [
+   "6ce53bef255285179312cc571335d25ef1f9f409",
+   "support"
+  ],
+  "payment-request/payment-request-hasenrolledinstrument-method.https.html": [
+   "c5139950d53ec310b3ed5cb835d4d252033f904f",
+   "testharness"
+  ],
   "payment-request/payment-request-id-attribute.https.html": [
    "e5d0c7a66eee67f529cd48fa640f08481f5e5a38",
    "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/reference/filler-text-below-green.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/reference/filler-text-below-green.xht
index d4aa114..f9609b1 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/reference/filler-text-below-green.xht
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/reference/filler-text-below-green.xht
@@ -2,7 +2,6 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
         <title>Filler text below is green reference</title>
-        <link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com"/>
         <style>
           .green { color: green; }
         </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-filler-text-ref.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-filler-text-ref.xht
index 25fcdae..73c348f1 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-filler-text-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-filler-text-ref.xht
@@ -2,7 +2,6 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
         <title>No red visible, filler text, reference</title>
-        <link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com"/>
     </head>
     <body>
         <p>Test passes if there is no red visible on the page.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-on-blank-page-ref.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-on-blank-page-ref.xht
index 04606c1..810e90fd 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-on-blank-page-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/reference/no-red-on-blank-page-ref.xht
@@ -2,7 +2,6 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
         <title>No red visible, blank page, reference</title>
-        <link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com"/>
     </head>
     <body>
         <p>Test passes if there is no red visible on the page.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/baseline-of-scrollable-2.html b/third_party/blink/web_tests/external/wpt/css/css-align/baseline-of-scrollable-2.html
new file mode 100644
index 0000000..5511d6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-align/baseline-of-scrollable-2.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8">
+  <title>
+    CSS Test: baseline of scrollable "details" element should be derived
+    from its margin-box.
+  </title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+  <link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
+  <link rel="match" href="reference/baseline-of-scrollable-2-ref.html">
+  <style>
+    .overflow-ib {
+      overflow: hidden;
+      display: inline-block;
+    }
+
+    details {
+      height: 40px;
+      width: 100px;
+      /* Transparent text & "details-arrow", so that it's easier to make
+         a simple reference case: */
+      color: transparent;
+      border-color: gray;
+      border-style: solid;
+      border-width: 2px 3px 4px 5px;
+      padding: 4px 5px 7px 8px;
+      margin: 1px 2px 3px 4px;
+    }
+</style>
+</head>
+<body>
+  Test passes if the a/b text aligns with the bottom margin-edge of the
+  gray rects.
+  <br><br>
+
+  a
+  <details class="overflow-ib">
+    c<br>d<br>e<br>f<br>g
+  </details>
+  b
+  <br>
+
+  a
+  <details class="overflow-ib" open>
+    c<br>d<br>e<br>f<br>g
+  </details>
+  b
+  <br>
+
+  a
+  <div class="overflow-ib">
+    <details>
+      c<br>d<br>e<br>f<br>g
+    </details>
+  </div>
+  b
+  <br>
+
+  a
+  <div class="overflow-ib">
+    <details open>
+      c<br>d<br>e<br>f<br>g
+    </details>
+  </div>
+  b
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/reference/baseline-of-scrollable-2-ref.html b/third_party/blink/web_tests/external/wpt/css/css-align/reference/baseline-of-scrollable-2-ref.html
new file mode 100644
index 0000000..dde29099
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-align/reference/baseline-of-scrollable-2-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8">
+  <title>
+    CSS Reference Case
+  </title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+  <style>
+    /* For this reference case, we use an empty block in place of the testcase's
+       "details" element, because empty blocks derive their baseline from their
+       margin-box (and that's the behavior that we're expecting from the
+       "details" elements in our testcase). */
+    .details-ref {
+      display: inline-block;
+      height: 40px;
+      width: 100px;
+      border-color: gray;
+      border-style: solid;
+      border-width: 2px 3px 4px 5px;
+      padding: 4px 5px 7px 8px;
+      margin: 1px 2px 3px 4px;
+    }
+</style>
+</head>
+<body>
+  Test passes if the a/b text aligns with the bottom margin-edge of the
+  gray rects.
+  <br><br>
+
+  a
+  <div class="details-ref"></div>
+  b
+  <br>
+
+  a
+  <div class="details-ref"></div>
+  b
+  <br>
+
+  a
+  <div class="details-ref"></div>
+  b
+  <br>
+
+  a
+  <div class="details-ref"></div>
+  b
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/t31-color-text-a-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-color/t31-color-text-a-ref.xht
index f11a57f..95a0e03 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/t31-color-text-a-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/t31-color-text-a-ref.xht
@@ -2,7 +2,6 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 	<head>
 		<title>CSS Notref Black "should be green"</title>
-		<link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com" />
 		<style type="text/css"><![CDATA[
 			#one { color: #000; color: rgb(0,0,0); color: black; }
 		]]></style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-grow-007.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-grow-007.html
index da48135b..04a3041 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-grow-007.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-grow-007.html
@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>CSS Flexbox Test: flex-grow - less than one</title>
-<link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com">
 <link rel="help" title="7.3.1. The 'flex-grow' property" href="http://www.w3.org/TR/css-flexbox-1/#flex-grow-property">
 <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
 <meta name="flags" content="">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shrink-008.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shrink-008.html
index a0104489..c93a3fe 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shrink-008.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shrink-008.html
@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>CSS Flexbox Test: flex-shrink - less than one</title>
-<link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com">
 <link rel="help" title="7.3.1. The 'flex-shrink' property" href="http://www.w3.org/TR/css-flexbox-1/#flex-shrink-property">
 <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
 <meta name="flags" content="">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html
new file mode 100644
index 0000000..f1b8567f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box.html">
+<meta name="assert" content="This test verifies that the scrollbars are not shown on an empty grid even if there are grid areas which exceed the grid container size, since the grid itself is not a box that can cause overflow.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 200px / 200px;
+       width: 100px;
+       height: 100px;
+    }
+</style>
+<p>The test passes if you see a grey square below without any scrollbar.</p>
+<div class="grid"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html
new file mode 100644
index 0000000..dee656a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box.html">
+<meta name="assert" content="This test verifies that the scrollbars are not shown on a grid with an item placed inside the boundaries of the grid container, even if there are grid areas which exceed the grid container size.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 200px / 200px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       width: 100px;
+       height: 100px;
+    }
+</style>
+<p>The test passes if you see a grey square below without any scrollbar.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html
new file mode 100644
index 0000000..3d13eab2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box.html">
+<meta name="assert" content="This test verifies that the scrollbars are not shown on a grid with an item placed inside the boundaries of the grid container, even if there are grid areas which exceed the grid container size.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 100px 100px / 100px 100px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       grid-column: 1;
+       grid-row: 1;
+       width: 100px;
+       height: 100px;
+    }
+</style>
+<p>The test passes if you see a grey square below without any scrollbar.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html
new file mode 100644
index 0000000..c4cd8b99
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box-with-horizontal-scrollbar.html">
+<meta name="assert" content="This test verifies that the horizontal scrollbar is shown on a grid with an item placed below the bottom of the grid container.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 100px 100px / 100px 100px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       grid-column: 1;
+       grid-row: 2;
+       width: 50px;
+       height: 50px;
+    }
+</style>
+<p>The test passes if you see a grey square below and only the horizontal scrollbar is visible.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html
new file mode 100644
index 0000000..afbde569
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box-with-vertical-scrollbar.html">
+<meta name="assert" content="This test verifies that the vertical scrollbar is shown on a grid with an item placed behind the right edge of the grid container.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 100px 100px / 100px 100px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       grid-column: 2;
+       grid-row: 1;
+       width: 50px;
+       height: 50px;
+    }
+</style>
+<p>The test passes if you see a grey square below and only the vertical scrollbar is visible.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html
new file mode 100644
index 0000000..4c689ac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box-with-scrollbars.html">
+<meta name="assert" content="This test verifies that the scrollbars are shown on a grid with an item placed outside the boundaries of the grid container.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 100px 100px / 100px 100px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       grid-column: 2;
+       grid-row: 2;
+       width: 50px;
+       height: 50px;
+    }
+</style>
+<p>The test passes if you see a grey square below and both scrollbars are visible.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html
new file mode 100644
index 0000000..96faa81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box.html">
+<meta name="assert" content="This test verifies that the scrollbars are not shown on a grid with an item with 0px width even when it's placed in a grid area outside the boundaries of the grid container.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 100px 100px / 100px 100px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       grid-column: 2;
+       grid-row: 2;
+       width: 0px;
+       height: 50px;
+    }
+</style>
+<p>The test passes if you see a grey square below without any scrollbar.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html
new file mode 100644
index 0000000..baab7ca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid areas 'overflowing' the grid container size</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-model">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow">
+<link rel="match" href="reference/100x100-grey-box.html">
+<meta name="assert" content="This test verifies that the scrollbars are not shown on a grid with an item with 0px height even when it's placed in a grid area outside the boundaries of the grid container.">
+<link href="support/grid.css" rel="stylesheet">
+<style>
+    .grid {
+       grid: 100px 100px / 100px 100px;
+       width: 100px;
+       height: 100px;
+    }
+    .item {
+       grid-column: 2;
+       grid-row: 2;
+       width: 50px;
+       height: 0px;
+    }
+</style>
+<p>The test passes if you see a grey square below without any scrollbar.</p>
+<div class="grid"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-horizontal-scrollbar.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-horizontal-scrollbar.html
new file mode 100644
index 0000000..8f73ef1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-horizontal-scrollbar.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Reference</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<style>
+    .box {
+       width: 100px;
+       height: 100px;
+       background-color: grey;
+    }
+    .item {
+       width: 150px;
+       height: 50px;
+    }
+</style>
+<p>The test passes if you see a grey square below and only the horizontal scrollbar is visible.</p>
+<div class="box"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-scrollbars.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-scrollbars.html
new file mode 100644
index 0000000..e464ab879
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-scrollbars.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Reference</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<style>
+    .box {
+       width: 100px;
+       height: 100px;
+       background-color: grey;
+    }
+    .item {
+       width: 150px;
+       height: 150px;
+    }
+</style>
+<p>The test passes if you see a grey square below and both scrollbars are visible.</p>
+<div class="box"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-vertical-scrollbar.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-vertical-scrollbar.html
new file mode 100644
index 0000000..26b4b69
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box-with-vertical-scrollbar.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Reference</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<style>
+    .box {
+       width: 100px;
+       height: 100px;
+       background-color: grey;
+    }
+    .item {
+       width: 50px;
+       height: 150px;
+    }
+</style>
+<p>The test passes if you see a grey square below and only the vertical scrollbar is visible.</p>
+<div class="box"><div class="item"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box.html
new file mode 100644
index 0000000..0592f6d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/100x100-grey-box.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>Reference</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
+<style>
+    .box {
+       width: 100px;
+       height: 100px;
+       background-color: grey;
+    }
+</style>
+<p>The test passes if you see a grey square below without any scrollbar.</p>
+<div class="box"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1-ref.html
index 9271c77c..dbc5f05 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1-ref.html
@@ -53,7 +53,7 @@
       .rotate_2 {
         left: 450px;
         transform-origin: 50% 50%;
-        transform: rotate3d(0, 0, 1, 90deg);
+        transform: rotate3d(1, 0, 0, 45deg);
       }
       .row_3 {
         transform: perspective(500px);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1.html
index 4f83e2ea..f21954e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-1.html
@@ -6,7 +6,7 @@
     <link rel="author" title="CJ Ku" href="mailto:cku@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-transforms-2/#individual-transforms">
-    <meta name="assert" content="Tests whether individaul transform works correctlyi by compare the rendering result with transfrom functions of the 'transform' property."/>
+    <meta name="assert" content="Tests whether individual transforms work correctly by comparing the rendering result with transform functions of the 'transform' property."/>
     <link rel="match" href="individual-transform-1-ref.html">
     <style>
       div {
@@ -36,7 +36,7 @@
       .rotate_1 {
         left: 450px;
         transform-origin: 50% 50%;
-        /* test 'rota: te<angle>' */
+        /* test 'rotate: <angle>' */
         rotate: 90deg;
       }
 
@@ -59,8 +59,8 @@
       .rotate_2 {
         left: 450px;
         transform-origin: 50% 50%;
-        /* test 'rotate: <number>{3}<angle>'*/
-        rotate: 0 0 1 90deg;
+        /* test 'rotate: axis <angle>'*/
+        rotate: x 45deg;
       }
       .row_3 {
         transform: perspective(500px);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid-expected.txt
deleted file mode 100644
index 07ec45c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This is a testharness.js-based test.
-PASS e.style['rotate'] = "none" should set the property value
-PASS e.style['rotate'] = "0deg" should set the property value
-PASS e.style['rotate'] = "100 200 300 400grad" should set the property value
-PASS e.style['rotate'] = "400grad 100 200 300" should set the property value
-FAIL e.style['rotate'] = "x 400grad" should set the property value assert_equals: serialization should be canonical expected "x 400grad" but got "1 0 0 400grad"
-FAIL e.style['rotate'] = "400grad x" should set the property value assert_equals: serialization should be canonical expected "x 400grad" but got "1 0 0 400grad"
-FAIL e.style['rotate'] = "1 0 0 400grad" should set the property value assert_equals: serialization should be canonical expected "x 400grad" but got "1 0 0 400grad"
-FAIL e.style['rotate'] = "y 400grad" should set the property value assert_equals: serialization should be canonical expected "y 400grad" but got "0 1 0 400grad"
-FAIL e.style['rotate'] = "400grad y" should set the property value assert_equals: serialization should be canonical expected "y 400grad" but got "0 1 0 400grad"
-FAIL e.style['rotate'] = "0 1 0 400grad" should set the property value assert_equals: serialization should be canonical expected "y 400grad" but got "0 1 0 400grad"
-FAIL e.style['rotate'] = "z 400grad" should set the property value assert_equals: serialization should be canonical expected "z 400grad" but got "0 0 1 400grad"
-FAIL e.style['rotate'] = "400grad z" should set the property value assert_equals: serialization should be canonical expected "z 400grad" but got "0 0 1 400grad"
-FAIL e.style['rotate'] = "0 0 1 400grad" should set the property value assert_equals: serialization should be canonical expected "z 400grad" but got "0 0 1 400grad"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid.html
index 63243b5..ae97322 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/rotate-parsing-valid.html
@@ -12,13 +12,19 @@
 </head>
 <body>
 <script>
+// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization
+
+// Serialize as the keyword none if and only if none was originally specified.
 test_valid_value("rotate", "none");
 
+// If a 2d rotation is specified, the property must serialize as just an <angle>.
 test_valid_value("rotate", "0deg");
 
+// If a 3d rotation is specified, the property must serialize with an axis specified.
 test_valid_value("rotate", "100 200 300 400grad");
 test_valid_value("rotate", "400grad 100 200 300", "100 200 300 400grad");
 
+// If the axis is parallel with the x, y, or z axis, it must serialize as the appropriate keyword.
 test_valid_value("rotate", "x 400grad");
 test_valid_value("rotate", "400grad x", "x 400grad");
 test_valid_value("rotate", "1 0 0 400grad", "x 400grad");
diff --git a/third_party/blink/web_tests/external/wpt/css/reference/pass_if_filler_text_slanted.xht b/third_party/blink/web_tests/external/wpt/css/reference/pass_if_filler_text_slanted.xht
index 3d1c7fd..bb2e25c 100644
--- a/third_party/blink/web_tests/external/wpt/css/reference/pass_if_filler_text_slanted.xht
+++ b/third_party/blink/web_tests/external/wpt/css/reference/pass_if_filler_text_slanted.xht
@@ -3,7 +3,6 @@
 <head>
    <title>Reference rendering - pass if Filler Text slanted to one side</title>
    <link rel="author" title="Opera Software" href="https://opera.com"/>
-   <link rel="author" title="Geoffrey Sneddon" href="mailto:me@gsnedders.com"/>
    <style>
       div {
          font-style: italic;
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_iplicit_noopener.html b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_implicit_noopener.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_iplicit_noopener.html
rename to third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/support/target_blank_implicit_noopener.html
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener-expected.txt
new file mode 100644
index 0000000..160569fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS Anchor element with target=_blank with rel=noopener
+PASS Anchor element with target=_blank with rel=opener
+FAIL Anchor element with target=_blank with implicit rel=noopener assert_equals: expected false but got true
+PASS Anchor element with target=_blank with rel=opener+noopener
+PASS Anchor element with target=_blank with rel=noopener+opener
+PASS Anchor element with target=_blank with rel=noreferrer
+PASS Anchor element with target=_blank with rel=opener+noreferrer
+PASS Anchor element with target=_blank with rel=noopener+opener+noreferrer
+PASS Area element with target=_blank with rel=noopener
+PASS Area element with target=_blank with rel=opener
+FAIL Area element with target=_blank with implicit rel=noopener assert_equals: expected false but got true
+PASS Area element with target=_blank with rel=opener+noopener
+PASS Area element with target=_blank with rel=noopener+opener
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html
new file mode 100644
index 0000000..32bf32c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset=utf-8>
+  <title>Test behavior of target=_blank links</title>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+  <a href="support/target_blank_implicit_noopener.html?a1" id="a1" rel="noopener" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a2" id="a2" rel="opener" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a3" id="a3" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a4" id="a4" rel="opener noopener" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a5" id="a5" rel="noopener opener" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a6" id="a6" rel="noreferrer" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a7" id="a7" rel="opener noreferrer" target="_blank">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a8" id="a8" rel="noopener opener noreferrer" target="_blank">Click me</a>
+
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area1" id="area1" rel="noopener" target="_blank" />
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area2" id="area2" rel="opener" target="_blank" />
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area3" id="area3" target="_blank" />
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area4" id="area4" rel="opener noopener" target="_blank" />
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area5" id="area5" rel="noopener opener" target="_blank" />
+  </img>
+
+  <script>
+
+  let tests = [
+    { id: "a1", hasOpener: false, name: "Anchor element with target=_blank with rel=noopener" },
+    { id: "a2", hasOpener: true, name: "Anchor element with target=_blank with rel=opener" },
+    { id: "a3", hasOpener: false, name: "Anchor element with target=_blank with implicit rel=noopener" },
+    { id: "a4", hasOpener: false, name: "Anchor element with target=_blank with rel=opener+noopener" },
+    { id: "a5", hasOpener: false, name: "Anchor element with target=_blank with rel=noopener+opener" },
+    { id: "a6", hasOpener: false, name: "Anchor element with target=_blank with rel=noreferrer" },
+    { id: "a7", hasOpener: false, name: "Anchor element with target=_blank with rel=opener+noreferrer" },
+    { id: "a8", hasOpener: false, name: "Anchor element with target=_blank with rel=noopener+opener+noreferrer" },
+    { id: "area1", hasOpener: false, name: "Area element with target=_blank with rel=noopener" },
+    { id: "area2", hasOpener: true, name: "Area element with target=_blank with rel=opener" },
+    { id: "area3", hasOpener: false, name: "Area element with target=_blank with implicit rel=noopener" },
+    { id: "area4", hasOpener: false, name: "Area element with target=_blank with rel=opener+noopener" },
+    { id: "area5", hasOpener: false, name: "Area element with target=_blank with rel=noopener+opener" },
+  ];
+
+  tests.forEach(data => {
+    async_test(
+      test => {
+        let bc = new BroadcastChannel(data.id);
+        bc.addEventListener("message", test.step_func_done(e => {
+          assert_equals(e.data.hasOpener, data.hasOpener);
+        }), {once: true});
+
+        document.getElementById(data.id).click();
+      }, data.name);
+  });
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html
deleted file mode 100644
index 39903dc..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <meta charset=utf-8>
-  <title>Test behavior of rel="noopener" links</title>
-  <script src=/resources/testharness.js></script>
-  <script src=/resources/testharnessreport.js></script>
-</head>
-<body>
-  <a href="support/target_blank_iplicit_noopener.html?a1" id="a1" rel="noopener" target="_blank">Click me</a>
-  <a href="support/target_blank_iplicit_noopener.html?a2" id="a2" rel="opener" target="_blank">Click me</a>
-  <a href="support/target_blank_iplicit_noopener.html?a3" id="a3" target="_blank">Click me</a>
-  <a href="support/target_blank_iplicit_noopener.html?a4" id="a4" rel="opener noopener" target="_blank">Click me</a>
-  <a href="support/target_blank_iplicit_noopener.html?a5" id="a5" rel="noopener opener" target="_blank">Click me</a>
-
-  <img src="/images/threecolors.png" />
-    <area shape="rect" coords="0,0,99,50" href="support/target_blank_iplicit_noopener.html?area1" id="area1" rel="noopener" target="_blank" />
-  </img>
-  <img src="/images/threecolors.png" />
-    <area shape="rect" coords="0,0,99,50" href="support/target_blank_iplicit_noopener.html?area2" id="area2" rel="opener" target="_blank" />
-  </img>
-  <img src="/images/threecolors.png" />
-    <area shape="rect" coords="0,0,99,50" href="support/target_blank_iplicit_noopener.html?area3" id="area3" target="_blank" />
-  </img>
-  <img src="/images/threecolors.png" />
-    <area shape="rect" coords="0,0,99,50" href="support/target_blank_iplicit_noopener.html?area4" id="area4" rel="opener noopener" target="_blank" />
-  </img>
-  <img src="/images/threecolors.png" />
-    <area shape="rect" coords="0,0,99,50" href="support/target_blank_iplicit_noopener.html?area5" id="area5" rel="noopener opener" target="_blank" />
-  </img>
-
-  <script>
-
-  let tests = [
-    { id: "a1", hasOpener: false, name: "Anchor element with target=_blank with rel=noopener" },
-    { id: "a2", hasOpener: true, name: "Anchor element with target=_blank with rel=opener" },
-    { id: "a3", hasOpener: false, name: "Anchor element with target=_blank with implicit rel=noopener" },
-    { id: "a4", hasOpener: false, name: "Anchor element with target=_blank with rel=opener+noopener" },
-    { id: "a5", hasOpener: false, name: "Anchor element with target=_blank with rel=noopener+opener" },
-    { id: "area1", hasOpener: false, name: "Area element with target=_blank with rel=noopener" },
-    { id: "area2", hasOpener: true, name: "Area element with target=_blank with rel=opener" },
-    { id: "area3", hasOpener: false, name: "Area element with target=_blank with implicit rel=noopener" },
-    { id: "area4", hasOpener: false, name: "Area element with target=_blank with rel=opener+noopener" },
-    { id: "area5", hasOpener: false, name: "Area element with target=_blank with rel=noopener+opener" },
-  ];
-
-  tests.forEach(data => {
-    async_test(
-      test => {
-        let bc = new BroadcastChannel(data.id);
-        bc.addEventListener("message", test.step_func_done(e => {
-          assert_equals(e.data.hasOpener, data.hasOpener);
-        }), {once: true});
-
-        document.getElementById(data.id).click();
-      }, data.name);
-  });
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base-expected.txt
new file mode 100644
index 0000000..aab46c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS Anchor element with base target=_blank with rel=noopener
+PASS Anchor element with base target=_blank with rel=opener
+FAIL Anchor element with base target=_blank with implicit rel=noopener assert_equals: expected false but got true
+PASS Anchor element with base target=_blank with rel=opener+noopener
+PASS Anchor element with base target=_blank with rel=noopener+opener
+PASS Anchor element with base target=_blank with rel=noreferrer
+PASS Anchor element with base target=_blank with rel=opener+noreferrer
+PASS Anchor element with base target=_blank with rel=noopener+opener+noreferrer
+PASS Area element with base target=_blank with rel=noopener
+PASS Area element with base target=_blank with rel=opener
+FAIL Area element with base target=_blank with implicit rel=noopener assert_equals: expected false but got true
+PASS Area element with base target=_blank with rel=opener+noopener
+PASS Area element with base target=_blank with rel=noopener+opener
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html
new file mode 100644
index 0000000..44b91a2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset=utf-8>
+  <title>Test behavior of base target=_blank links</title>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <base target=_blank>
+</head>
+<body>
+  <a href="support/target_blank_implicit_noopener.html?a1" id="a1" rel="noopener">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a2" id="a2" rel="opener">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a3" id="a3">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a4" id="a4" rel="opener noopener">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a5" id="a5" rel="noopener opener">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a6" id="a6" rel="noreferrer">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a7" id="a7" rel="opener noreferrer">Click me</a>
+  <a href="support/target_blank_implicit_noopener.html?a8" id="a8" rel="noopener opener noreferrer">Click me</a>
+
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area1" id="area1" rel="noopener">
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area2" id="area2" rel="opener">
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area3" id="area3">
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area4" id="area4" rel="opener noopener">
+  </img>
+  <img src="/images/threecolors.png" />
+    <area shape="rect" coords="0,0,99,50" href="support/target_blank_implicit_noopener.html?area5" id="area5" rel="noopener opener">
+  </img>
+
+  <script>
+
+  let tests = [
+    { id: "a1", hasOpener: false, name: "Anchor element with base target=_blank with rel=noopener" },
+    { id: "a2", hasOpener: true, name: "Anchor element with base target=_blank with rel=opener" },
+    { id: "a3", hasOpener: false, name: "Anchor element with base target=_blank with implicit rel=noopener" },
+    { id: "a4", hasOpener: false, name: "Anchor element with base target=_blank with rel=opener+noopener" },
+    { id: "a5", hasOpener: false, name: "Anchor element with base target=_blank with rel=noopener+opener" },
+    { id: "a6", hasOpener: false, name: "Anchor element with base target=_blank with rel=noreferrer" },
+    { id: "a7", hasOpener: false, name: "Anchor element with base target=_blank with rel=opener+noreferrer" },
+    { id: "a8", hasOpener: false, name: "Anchor element with base target=_blank with rel=noopener+opener+noreferrer" },
+    { id: "area1", hasOpener: false, name: "Area element with base target=_blank with rel=noopener" },
+    { id: "area2", hasOpener: true, name: "Area element with base target=_blank with rel=opener" },
+    { id: "area3", hasOpener: false, name: "Area element with base target=_blank with implicit rel=noopener" },
+    { id: "area4", hasOpener: false, name: "Area element with base target=_blank with rel=opener+noopener" },
+    { id: "area5", hasOpener: false, name: "Area element with base target=_blank with rel=noopener+opener" },
+  ];
+
+  tests.forEach(data => {
+    async_test(
+      test => {
+        let bc = new BroadcastChannel(data.id);
+        bc.addEventListener("message", test.step_func_done(e => {
+          assert_equals(e.data.hasOpener, data.hasOpener);
+        }), {once: true});
+
+        document.getElementById(data.id).click();
+      }, data.name);
+  });
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/css-variables/resolve-inherited-css-variables-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/css-variables/resolve-inherited-css-variables-expected.txt
index b2a8ec3..8ad9bffe 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/css-variables/resolve-inherited-css-variables-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/css-variables/resolve-inherited-css-variables-expected.txt
@@ -3,4 +3,5 @@
 compute "var(--color)" for span: blue
 compute "var(--color)" for div: red
 compute "var(--color)" for body: red
+compute "var(--color)" for html: null
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/elements-delete-inline-style-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/elements-delete-inline-style-expected.txt
index f4feac6..8c1acfa5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/elements-delete-inline-style-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/elements-delete-inline-style-expected.txt
@@ -9,6 +9,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After style property removal:
 [expanded] 
 element.style { ()
@@ -17,4 +22,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt
index 7502a99e..f570cb1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt
@@ -13,6 +13,7 @@
     OVERLOADED black - .foo elements-panel-styles.css:21 -> elements-panel-styles.css:21:7
     OVERLOADED red - #container elements-panel-styles.css:10 -> elements-panel-styles.css:10:13
     OVERLOADED magenta !important - html elements-panel-styles.css:61 -> elements-panel-styles.css:61:7
+    OVERLOADED -internal-root-color - html user agent stylesheet
 content: "[before Foo]";
     "[before Foo]" - .foo, .foo::before elements-panel-styles.css:34 -> elements-panel-styles.css:34:21
 display: block;
@@ -126,6 +127,10 @@
 html { (elements-panel-styles.css:61 -> elements-panel-styles.css:61:7)
 /-- overloaded --/     color: magenta !important;
 
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 ======== Pseudo ::before element ========
 [expanded] 
 .foo::before { (elements-panel-styles.css:57 -> elements-panel-styles.css:57:15)
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-invalid-selector-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-invalid-selector-expected.txt
index bb0a5e1..6cd8fb4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-invalid-selector-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-invalid-selector-expected.txt
@@ -11,4 +11,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-keyboard-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-keyboard-expected.txt
index 67bac53..aac29cc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-keyboard-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-keyboard-expected.txt
@@ -12,4 +12,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body-expected.txt
index 51a5349e..f7620c8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body-expected.txt
@@ -14,4 +14,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-expected.txt
index 6c42192..a7c1c88 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-expected.txt
@@ -13,6 +13,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After non-affecting selector modification ===
 [expanded] 
 element.style { ()
@@ -26,6 +31,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After affecting selector modification ===
 [expanded] 
 element.style { ()
@@ -39,4 +49,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-mark-matching-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-mark-matching-expected.txt
index 67d604080..4053df9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-mark-matching-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/commit-selector-mark-matching-expected.txt
@@ -14,6 +14,11 @@
 [$div$] { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+[$html$] { (user agent stylesheet)
+    color: -internal-root-color;
+
 
 Running: changeSelector
 [expanded] 
@@ -26,4 +31,9 @@
 [$div$] { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+[$html$] { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/css-live-edit-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/css-live-edit-expected.txt
index a6f73e4b..05ccc3d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/css-live-edit-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/css-live-edit-expected.txt
@@ -2,6 +2,8 @@
 
 
 Running: testLiveEdit
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 font-size: 20px;
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/cssom-media-insert-crash-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/cssom-media-insert-crash-expected.txt
index 507c282..101d08a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/cssom-media-insert-crash-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/cssom-media-insert-crash-expected.txt
@@ -18,4 +18,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/disable-property-workingcopy-update-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/disable-property-workingcopy-update-expected.txt
index 085a900b..bbcc7de 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/disable-property-workingcopy-update-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/disable-property-workingcopy-update-expected.txt
@@ -31,6 +31,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
 Running: togglePropertyOn
 
@@ -52,4 +57,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt
index b18a0e4..e7dc626 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt
@@ -85,4 +85,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-inspector-stylesheet-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-inspector-stylesheet-expected.txt
index 38eee3c0..dd00bd9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-inspector-stylesheet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-inspector-stylesheet-expected.txt
@@ -18,4 +18,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-media-text-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-media-text-expected.txt
index 46bb6c3..9f66f5c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-media-text-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-media-text-expected.txt
@@ -19,6 +19,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After valid media text modification ===
 [expanded] 
 element.style { ()
@@ -38,6 +43,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After invalid media text modification ===
 [expanded] 
 element.style { ()
@@ -55,4 +65,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/empty-background-url-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/empty-background-url-expected.txt
index 440b5d3a..e1db018 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/empty-background-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/empty-background-url-expected.txt
@@ -11,4 +11,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt
index 0b01cb2c..e04db1d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt
@@ -64,4 +64,8 @@
 div {
    display: block
 }
+html {
+   display: block
+   color: -internal-root-color
+}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/add-import-rule-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/add-import-rule-expected.txt
index 2ad324c..67464ce 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/add-import-rule-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/add-import-rule-expected.txt
@@ -10,6 +10,11 @@
 span { (<style>…</style>)
     color: red;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 == Matched rules after @import added ==
 
@@ -20,4 +25,9 @@
 span { (data:text/css,s…color:green}:1 -> data:text/css,span{color:green}:1:6)
     color: green;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/cssom-shorthand-important-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/cssom-shorthand-important-expected.txt
index 87c491b..323d147 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/cssom-shorthand-important-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/cssom-shorthand-important-expected.txt
@@ -16,4 +16,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt
index 74e1c3a2..2f4328d2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt
@@ -20,6 +20,10 @@
    font-family: arial
    display: block
 }
+html {
+   display: block
+   color: -internal-root-color
+}
 #third::before {
    content: "uno-1"
 }
@@ -32,6 +36,7 @@
 Filtering styles by: font-family
 [ VISIBLE ] Inherited from div#second
 [ VISIBLE ] Inherited from div#first
+[ HIDDEN ]  Inherited from html
 [ HIDDEN ]  Pseudo ::before element
 [ HIDDEN ]  Pseudo ::after element
 
@@ -39,6 +44,7 @@
 Filtering styles by: content
 [ HIDDEN ]  Inherited from div#second
 [ HIDDEN ]  Inherited from div#first
+[ HIDDEN ]  Inherited from html
 [ VISIBLE ] Pseudo ::before element
 [ VISIBLE ] Pseudo ::after element
 
@@ -46,6 +52,7 @@
 Filtering styles by: display
 [ HIDDEN ]  Inherited from div#second
 [ VISIBLE ] Inherited from div#first
+[ VISIBLE ] Inherited from html
 [ HIDDEN ]  Pseudo ::before element
 [ VISIBLE ] Pseudo ::after element
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/force-pseudo-state-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/force-pseudo-state-expected.txt
index 4b2c55d3..951be4a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/force-pseudo-state-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/force-pseudo-state-expected.txt
@@ -22,6 +22,11 @@
 Style Attribute { ()
 /-- overloaded --/     font-weight: normal;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 - <html> [subtreeMarkerCount:1]
     + <head>…</head>
     - <body id="mainBody" class="main1 main2 mainpage" style="font-weight: normal; width: 85%; background-image: url(bar.png)"> [subtreeMarkerCount:1]
@@ -74,6 +79,11 @@
 Style Attribute { ()
 /-- overloaded --/     font-weight: normal;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 - <html> [subtreeMarkerCount:1]
     + <head>…</head>
     - <body id="mainBody" class="main1 main2 mainpage" style="font-weight: normal; width: 85%; background-image: url(bar.png)"> [subtreeMarkerCount:1]
@@ -94,6 +104,11 @@
 Style Attribute { ()
     font-weight: normal;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 - <html>
     + <head>…</head>
     - <body id="mainBody" class="main1 main2 mainpage" style="font-weight: normal; width: 85%; background-image: url(bar.png)">
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-expected.txt
index eb0d0bd..ba85be0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-expected.txt
@@ -1,5 +1,7 @@
 Tests that effectively inactive properties are displayed correctly in the sidebar.
 
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 text-align: right;
@@ -22,4 +24,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inherited-mixed-case-properties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inherited-mixed-case-properties-expected.txt
index e80a48d..b6989cc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inherited-mixed-case-properties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inherited-mixed-case-properties-expected.txt
@@ -1,6 +1,7 @@
 Tests that non-standard mixed-cased properties are displayed in the Styles pane.
 
 color: rgb(0, 0, 0);
+    OVERLOADED -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 -webkit-font-smoothing: antialiased;
@@ -20,4 +21,9 @@
 #container { (<style>…</style>)
     -webkit-FONT-smoothing: antialiased;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inject-stylesheet-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inject-stylesheet-expected.txt
index c31f289..89480a46 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inject-stylesheet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inject-stylesheet-expected.txt
@@ -31,6 +31,7 @@
     solid - #main injected stylesheet
 color: rgb(255, 0, 0);
     red - #main injected stylesheet
+    OVERLOADED -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 -webkit-border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAiElEQ…Ms+LS30CAhBN5nNxeT5hbJ1zwmji2k+aF6NENIPf/hs54f0sZFUVAMigAAAABJRU5ErkJggg==) 100% / 1 / 0px stretch;
@@ -66,6 +67,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 iframe style:
 background-attachment: scroll;
     initial - #iframeBody injected stylesheet
@@ -97,6 +103,8 @@
 background-size: auto;
     initial - #iframeBody injected stylesheet
     OVERLOADED initial - body inject-styleshe…me-data.html:4 -> inject-stylesheet-iframe-data.html:4:9
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - body user agent stylesheet
 margin-bottom: 8px;
@@ -147,4 +155,9 @@
         margin-bottom: 8px;
         margin-left: 8px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/keyframes-rules-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/keyframes-rules-expected.txt
index 5c4e1b1..78afa72 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/keyframes-rules-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/keyframes-rules-expected.txt
@@ -16,4 +16,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/lazy-computed-style-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/lazy-computed-style-expected.txt
index 11ffcb8..91f8def 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/lazy-computed-style-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/lazy-computed-style-expected.txt
@@ -32,6 +32,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ==== All styles (computed should be there) ====
 background-attachment: scroll;
     initial - #inspected <style>…</style>
@@ -55,6 +60,8 @@
     initial - #inspected <style>…</style>
 background-size: auto;
     initial - #inspected <style>…</style>
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 font-family: Courier;
@@ -91,4 +98,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-emulation-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-emulation-expected.txt
index 8bd0c87..af5b22c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-emulation-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-emulation-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 print media emulated:
 [expanded] 
 element.style { ()
@@ -29,6 +34,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 tty media emulated:
 [expanded] 
 element.style { ()
@@ -45,6 +55,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 No media emulated:
 [expanded] 
 element.style { ()
@@ -57,4 +72,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-queries-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-queries-expected.txt
index 2cfbb11..ea3139e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-queries-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-queries-expected.txt
@@ -20,4 +20,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-using-same-url-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-using-same-url-expected.txt
index f99258c..f3f259d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-using-same-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/media-using-same-url-expected.txt
@@ -16,4 +16,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-comments-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-comments-expected.txt
index d706b43..4d3b33f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-comments-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-comments-expected.txt
@@ -20,4 +20,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-unterminated-comment-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-unterminated-comment-expected.txt
index f9cb197a..c825dce 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-unterminated-comment-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-unterminated-comment-expected.txt
@@ -8,6 +8,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 [expanded] 
 element.style { ()
     color: green;
@@ -16,4 +21,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-with-quote-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-with-quote-expected.txt
index fdb3dfb..dce4d9b4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-with-quote-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-declaration-with-quote-expected.txt
@@ -8,4 +8,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-utf8-bom-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-utf8-bom-expected.txt
index 8bd7152..d7eec62 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-utf8-bom-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/parse-utf8-bom-expected.txt
@@ -17,4 +17,9 @@
     margin-inline-end: 0px;
     font-weight: bold;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/paste-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/paste-property-expected.txt
index 3107f9e..3b558d82 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/paste-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/paste-property-expected.txt
@@ -9,6 +9,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After pasting 'margin-left: 1px':
 [expanded] 
 element.style { ()
@@ -19,6 +24,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After pasting 'margin-top: 1px; color: red;':
 [expanded] 
 element.style { ()
@@ -31,6 +41,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After pasting 'foo: bar; moo: zoo' over 'margin-top':
 [expanded] 
 element.style { ()
@@ -44,4 +59,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/perform-undo-perform-of-mergable-action-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/perform-undo-perform-of-mergable-action-expected.txt
index 3f26013..a734d1c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/perform-undo-perform-of-mergable-action-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/perform-undo-perform-of-mergable-action-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After changing property
 [expanded] 
 element.style { ()
@@ -24,6 +29,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After undo
 [expanded] 
 element.style { ()
@@ -36,6 +46,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After perform
 [expanded] 
 element.style { ()
@@ -48,4 +63,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/pseudo-elements-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/pseudo-elements-expected.txt
index 2cc90ff..7598177 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/pseudo-elements-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/pseudo-elements-expected.txt
@@ -23,6 +23,11 @@
 [$div$] { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+[$html$] { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== Pseudo ::before element ========
 [expanded] 
 [$#inspected:before, $].some-other-selector { (<style>…</style>)
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/region-style-crash-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/region-style-crash-expected.txt
index 3e4a8b5..58a52cb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/region-style-crash-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/region-style-crash-expected.txt
@@ -2,6 +2,7 @@
 
 color: rgb(255, 0, 0);
     #ff0000 - #p1 <style>…</style>
+    OVERLOADED -internal-root-color - html user agent stylesheet
 display: block;
     block - p user agent stylesheet
 margin-block-end: 16px;
@@ -27,4 +28,9 @@
     margin-inline-start: 0px;
     margin-inline-end: 0px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/selector-list-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/selector-list-expected.txt
index db860a0..bc4ab296 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/selector-list-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/selector-list-expected.txt
@@ -20,4 +20,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/shadow-dom-rules-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/shadow-dom-rules-expected.txt
index 75cc7a5..bdc4af8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/shadow-dom-rules-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/shadow-dom-rules-expected.txt
@@ -15,4 +15,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from body ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet-expected.txt
index 84d991e..079a042 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet-expected.txt
@@ -13,6 +13,11 @@
 div { (user agent stylesheet)
 /-- overloaded --/     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 Rules after toggling:
 [expanded] 
 element.style { ()
@@ -26,4 +31,9 @@
 div { (user agent stylesheet)
 /-- overloaded --/     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-blank-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-blank-property-expected.txt
index 9983c8a6..aea8232 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-blank-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-blank-property-expected.txt
@@ -9,6 +9,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After insertion at index 0:
 [expanded] 
 element.style { ()
@@ -19,6 +24,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After appending and changing a 'compound' property:
 [expanded] 
 element.style { ()
@@ -31,6 +41,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After insertion at index 2:
 [expanded] 
 element.style { ()
@@ -44,4 +59,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-invalid-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-invalid-property-expected.txt
index 056d3c6..d4ee274f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-invalid-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-invalid-property-expected.txt
@@ -9,6 +9,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After append:
 [expanded] 
 element.style { ()
@@ -18,4 +23,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-colon-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-colon-expected.txt
index 0e2aeb29..d2b8af1f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-colon-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-colon-expected.txt
@@ -13,6 +13,11 @@
 [$div$] { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+[$html$] { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After adding new rule (other):
 [expanded] 
 element.style { ()
@@ -25,5 +30,10 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 Revision added: inspector-stylesheet
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-expected.txt
index f94af57..c2f34a4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-expected.txt
@@ -13,6 +13,11 @@
 [$div$] { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+[$html$] { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After adding new rule (other):
 [expanded] 
 element.style { ()
@@ -25,6 +30,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 [expanded] 
 element.style { ()
 
@@ -35,6 +45,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 [expanded] 
 element.style { ()
 
@@ -45,5 +60,10 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 Revision added: inspector-stylesheet
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-tab-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-tab-expected.txt
index 0e2aeb29..d2b8af1f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-tab-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-tab-expected.txt
@@ -13,6 +13,11 @@
 [$div$] { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+[$html$] { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After adding new rule (other):
 [expanded] 
 element.style { ()
@@ -25,5 +30,10 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 Revision added: inspector-stylesheet
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-to-stylesheet-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-to-stylesheet-expected.txt
index 01da8e6..e00d40b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-to-stylesheet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-add-new-rule-to-stylesheet-expected.txt
@@ -10,4 +10,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cancel-editing-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cancel-editing-expected.txt
index 9ecb2029..ead26dcc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cancel-editing-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cancel-editing-expected.txt
@@ -8,6 +8,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 After append:
 [expanded] 
 element.style { ()
@@ -17,4 +22,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-commit-editing-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-commit-editing-expected.txt
index 45d1034..fa1c958e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-commit-editing-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-commit-editing-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: testCommitEditing
 
@@ -31,4 +36,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-computed-trace-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-computed-trace-expected.txt
index 8a2fe74..c7c5ed13 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-computed-trace-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-computed-trace-expected.txt
@@ -23,6 +23,8 @@
     initial - #id1 <style>…</style>
 background-size: auto;
     initial - #id1 <style>…</style>
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 font-family: Courier;
@@ -41,6 +43,8 @@
 ==== Computed style for ID2 ====
 background-color: rgb(0, 0, 255);
     blue - #id2 <style>…</style>
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 font-family: Courier;
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cssom-important-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cssom-important-property-expected.txt
index d48b600..333f5f5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cssom-important-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-cssom-important-property-expected.txt
@@ -10,4 +10,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-inherited-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-inherited-expected.txt
index 88213ba..fffceb5e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-inherited-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-inherited-expected.txt
@@ -13,6 +13,11 @@
 Style Attribute { ()
     font-weight: bold;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After disable:
 [expanded] 
 element.style { ()
@@ -21,4 +26,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit-expected.txt
index 7fd16f6..c03e05e6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit-expected.txt
@@ -22,4 +22,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua-expected.txt
index b30c5017..43d17dc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua-expected.txt
@@ -10,6 +10,11 @@
     display: block;
 /-- overloaded --/     margin: 8px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After disable
 [expanded] 
 element.style { ()
@@ -20,6 +25,11 @@
     display: block;
     margin: 8px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After enable
 [expanded] 
 element.style { ()
@@ -30,4 +40,9 @@
     display: block;
 /-- overloaded --/     margin: 8px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-variables-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-variables-expected.txt
index 80aa2ebc..b466f61 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-variables-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-3/styles-variables-expected.txt
@@ -1,6 +1,8 @@
 Tests that computed styles expand and allow tracing to style rules.
 
 ==== Computed style for ID1 ====
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 [expanded] 
@@ -19,8 +21,15 @@
 body { (<style>…</style>)
     --a: red;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 value of --a:  red
 ==== Computed style for ID2 ====
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 [expanded] 
@@ -44,8 +53,15 @@
 body { (<style>…</style>)
 /-- overloaded --/     --a: red;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 value of --b:  44px
 ==== Computed style for ID3 ====
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 [expanded] 
@@ -74,8 +90,15 @@
 body { (<style>…</style>)
 /-- overloaded --/     --a: red;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 value of --b:  44px
 ==== Computed style for ID4 ====
+color: rgb(0, 0, 0);
+    -internal-root-color - html user agent stylesheet
 display: block;
     block - div user agent stylesheet
 [expanded] 
@@ -94,5 +117,10 @@
 body { (<style>…</style>)
 /-- overloaded --/     --a: red;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 value of --a: undefined
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/inline-style-sourcemap-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/inline-style-sourcemap-expected.txt
index 4a4e87cd..efed505 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/inline-style-sourcemap-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/inline-style-sourcemap-expected.txt
@@ -20,4 +20,9 @@
         margin-bottom: 8px;
         margin-left: 8px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt
index d9778fe..2c0fad4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt
@@ -15,6 +15,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: editSelector
 [expanded] 
@@ -30,6 +35,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
 Running: editMedia
 [expanded] 
@@ -45,6 +55,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
 Running: addRule
 [expanded] 
@@ -60,6 +75,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
 Running: finish
 [expanded] 
@@ -78,4 +98,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-edit-property-after-invalid-rule-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-edit-property-after-invalid-rule-expected.txt
index cb47c43..55250d3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-edit-property-after-invalid-rule-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-edit-property-after-invalid-rule-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After changing property
 [expanded] 
 element.style { ()
@@ -24,4 +29,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-iframe-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-iframe-expected.txt
index fcc1fcc..18d17b77 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-iframe-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-iframe-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 iframe style:
 [expanded] 
 element.style { ()
@@ -25,4 +30,9 @@
     display: block;
     margin: 8px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-inherited-same-source-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-inherited-same-source-expected.txt
index 8fbeb15..c5b495a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-inherited-same-source-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-inherited-same-source-expected.txt
@@ -11,4 +11,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes-expected.txt
index 67d8f33..46cf2f1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes-expected.txt
@@ -20,6 +20,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== @keyframes animName ========
 [expanded] 
 0%, 20% { (<style>…</style>)
@@ -72,6 +77,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== @keyframes animName ========
 [expanded] 
 0%, 20% { (<style>…</style>)
@@ -124,6 +134,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== @keyframes animName ========
 [expanded] 
 0%, 20% { (<style>…</style>)
@@ -176,6 +191,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== @keyframes animName ========
 [expanded] 
 0%, 20% { (<style>…</style>)
@@ -228,6 +248,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== @keyframes animName ========
 [expanded] 
 0%, 20% { (<style>…</style>)
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes.js
index 4974138..050e15a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-keyframes.js
@@ -27,7 +27,7 @@
   function step1() {
     TestRunner.addResult('=== Before key modification ===');
     ElementsTestRunner.dumpSelectedElementStyles(true);
-    var section = UI.panels.elements._stylesWidget._sectionBlocks[1].sections[1];
+    var section = UI.panels.elements._stylesWidget._sectionBlocks[2].sections[1];
     section.startEditingSelector();
     section._selectorElement.textContent = '1%';
     section._selectorElement.dispatchEvent(TestRunner.createKeyEvent('Enter'));
@@ -52,7 +52,7 @@
   function step4() {
     TestRunner.addResult('=== After redo ===');
     ElementsTestRunner.dumpSelectedElementStyles(true);
-    var section = UI.panels.elements._stylesWidget._sectionBlocks[1].sections[1];
+    var section = UI.panels.elements._stylesWidget._sectionBlocks[2].sections[1];
     section.startEditingSelector();
     section._selectorElement.textContent = '1% /*';
     section._selectorElement.dispatchEvent(TestRunner.createKeyEvent('Enter'));
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt
index 348c0b4c..642aa39 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt
@@ -71,6 +71,7 @@
 [NO STYLE]
 html: [user-agent] {
     ['display':'block'] @[undefined-undefined] 
+    ['color':'-internal-root-color'] @[undefined-undefined] 
 }
 html: [regular, 4:0-4:4] {
     ['font-weight':'400'] @[5:4-5:21] 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overloaded-shorthand-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overloaded-shorthand-expected.txt
index 74a30032..9896aac 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overloaded-shorthand-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overloaded-shorthand-expected.txt
@@ -47,4 +47,9 @@
     /-- overloaded --/     line-height: normal;
     /-- overloaded --/     font-family: Arial, sans-serif;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overriden-properties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overriden-properties-expected.txt
index 04bd8b8..4813ba0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overriden-properties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-overriden-properties-expected.txt
@@ -20,4 +20,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-properties-overload-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-properties-overload-expected.txt
index aa0e98a..45b5e6f0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-properties-overload-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-properties-overload-expected.txt
@@ -56,4 +56,9 @@
 .container { (<style>…</style>)
 /-- overloaded --/     font-size: 10px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-expected.txt
index 1c07e982..14c54b1a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-expected.txt
@@ -27,4 +27,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-inline-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-inline-expected.txt
index a028a91..d3e1c166 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-inline-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-inline-expected.txt
@@ -12,4 +12,9 @@
 div { (user agent stylesheet)
 /-- overloaded --/     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-recovery-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-recovery-expected.txt
index 162e581..0aa69e7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-recovery-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-source-lines-recovery-expected.txt
@@ -19,4 +19,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-from-js-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-from-js-expected.txt
index 257e46e..8a57ee3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-from-js-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-from-js-expected.txt
@@ -31,6 +31,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: testSetStyleCSSText
 <div id="container" style="color: rgb(192, 255, 238);">…</div>
@@ -42,6 +47,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: testSetViaParsedAttributes
 <div id="container" style="color: rgb(192, 255, 238); border: 3px dashed green;">…</div>
@@ -71,6 +81,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: testSetViaAncestorClass
 <div id="child"></div>
@@ -90,6 +105,11 @@
 Style Attribute { ()
     color: rgb(192, 255, 238);
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: testSetViaSiblingAttr
 <div id="childSibling"></div>
@@ -109,4 +129,9 @@
 Style Attribute { ()
     color: rgb(192, 255, 238);
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-1-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-1-expected.txt
index c0837e7..c1445fc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-1-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-1-expected.txt
@@ -41,6 +41,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 
 #### AFTER PROPERTY INSERTION ####
@@ -84,6 +89,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 4 rule ranges are equal.
 4 rule ranges are equal.
 3 rule ranges are equal.
@@ -92,4 +102,5 @@
 3 rule ranges are equal.
 3 rule ranges are equal.
 0 rule ranges are equal.
+0 rule ranges are equal.
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-2-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-2-expected.txt
index f075fb395d..37802cb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-2-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-2-expected.txt
@@ -46,6 +46,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 4 rule ranges are equal.
 4 rule ranges are equal.
 4 rule ranges are equal.
@@ -54,4 +59,5 @@
 3 rule ranges are equal.
 3 rule ranges are equal.
 0 rule ranges are equal.
+0 rule ranges are equal.
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-3-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-3-expected.txt
index 3c85c62a..42ebad4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-3-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-3-expected.txt
@@ -46,6 +46,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 4 rule ranges are equal.
 4 rule ranges are equal.
 3 rule ranges are equal.
@@ -54,4 +59,5 @@
 3 rule ranges are equal.
 3 rule ranges are equal.
 0 rule ranges are equal.
+0 rule ranges are equal.
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt
index 7c7fc22..23c16d4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt
@@ -16,6 +16,11 @@
 article, aside, footer, header, hgroup, main, nav, section { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ======== Pseudo ::before element ========
 [expanded] 
 #pseudo::before { (<style>…</style>)
@@ -33,6 +38,7 @@
     color: red;
 
 0 rule ranges are equal.
+0 rule ranges are equal.
 3 rule ranges are equal.
 3 rule ranges are equal.
 5 rule ranges are equal.
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-with-spaces-in-sourceURL-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-with-spaces-in-sourceURL-expected.txt
index f9e11a8..0c01838 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-with-spaces-in-sourceURL-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-with-spaces-in-sourceURL-expected.txt
@@ -11,4 +11,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt
index ec92bfb0..e5f8d2e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt
@@ -15,4 +15,9 @@
 :not(svg), :not(foreignObject) > svg { (user agent stylesheet)
     transform-origin: 0px 0px;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-new-rule-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-new-rule-expected.txt
index e29a1c8a..bc19f45 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-new-rule-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-new-rule-expected.txt
@@ -15,6 +15,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ===== Style sheet text: =====
 div.foo {}
 
@@ -32,6 +37,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 ===== Style sheet text: =====
 div.foo {}
 =============================
@@ -50,6 +60,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 ===== Style sheet text: =====
 div.foo {}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-property-expected.txt
index a668f21..442ac5c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/undo-add-property-expected.txt
@@ -13,6 +13,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After adding property)
 [expanded] 
 element.style { ()
@@ -26,6 +31,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After undo)
 [expanded] 
 element.style { ()
@@ -38,6 +48,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After redo)
 [expanded] 
 element.style { ()
@@ -51,6 +66,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 === First property ===
 (Initial value)
 [expanded] 
@@ -65,6 +85,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After adding property)
 [expanded] 
 element.style { ()
@@ -79,6 +104,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After undo)
 [expanded] 
 element.style { ()
@@ -92,6 +122,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After redo)
 [expanded] 
 element.style { ()
@@ -106,6 +141,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 === Middle property ===
 (Initial value)
 [expanded] 
@@ -121,6 +161,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After adding property)
 [expanded] 
 element.style { ()
@@ -136,6 +181,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After undo)
 [expanded] 
 element.style { ()
@@ -150,6 +200,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 (After redo)
 [expanded] 
 element.style { ()
@@ -165,4 +220,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/cancel-upon-invalid-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/cancel-upon-invalid-property-expected.txt
index c630e32..ebfbf66 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/cancel-upon-invalid-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/cancel-upon-invalid-property-expected.txt
@@ -11,6 +11,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 [expanded] 
 element.style { ()
 
@@ -23,4 +28,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/edit-css-with-source-url-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/edit-css-with-source-url-expected.txt
index a5f0f1b7..4a3a484f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/edit-css-with-source-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/edit-css-with-source-url-expected.txt
@@ -19,6 +19,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 Editing styles from elements panel:
 Styles edited.
 Dumping matched rules:
@@ -34,6 +39,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 Dumping uiSourceCode content:
 #inspected {
           color: green;
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-deprecated-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-deprecated-expected.txt
index f5c6c781..80273b31 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-deprecated-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-deprecated-expected.txt
@@ -15,4 +15,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-expected.txt
index f5c6c781..80273b31 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-expected.txt
@@ -15,4 +15,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated-expected.txt
index d9f9e1a..ff7bed6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated-expected.txt
@@ -11,4 +11,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-expected.txt
index d9f9e1a..ff7bed6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-expected.txt
@@ -11,4 +11,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/show-all-properties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/show-all-properties-expected.txt
index bc683d2..45381de 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/show-all-properties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/show-all-properties-expected.txt
@@ -62,6 +62,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After showing all properties:
 [expanded] 
 element.style { ()
@@ -273,4 +278,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/styles-parse-invalid-properties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/styles-parse-invalid-properties-expected.txt
index 435ade6..39047cf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/styles-parse-invalid-properties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/styles-parse-invalid-properties-expected.txt
@@ -30,4 +30,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-after-cancelled-editing-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-after-cancelled-editing-expected.txt
index 9a5a66f..449775e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-after-cancelled-editing-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-after-cancelled-editing-expected.txt
@@ -18,6 +18,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: cancelEditing
 
@@ -33,6 +38,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
 Running: onUndoedProperty
 [expanded] 
@@ -45,4 +55,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-change-property-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-change-property-expected.txt
index 07549c1..33303f49 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-change-property-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-change-property-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After changing property
 [expanded] 
 element.style { ()
@@ -24,6 +29,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After undo
 [expanded] 
 element.style { ()
@@ -36,6 +46,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 After redo
 [expanded] 
 element.style { ()
@@ -48,4 +63,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+    color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-set-selector-text-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-set-selector-text-expected.txt
index 83c63f6..cdfe9943 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-set-selector-text-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/undo-set-selector-text-expected.txt
@@ -12,6 +12,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After selector modification ===
 [expanded] 
 element.style { ()
@@ -24,6 +29,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After undo ===
 [expanded] 
 element.style { ()
@@ -36,6 +46,11 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 === After redo ===
 [expanded] 
 element.style { ()
@@ -48,4 +63,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from html ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/startup/shadow-dom-rules-expected.txt b/third_party/blink/web_tests/http/tests/devtools/startup/shadow-dom-rules-expected.txt
index 75cc7a5..bdc4af8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/startup/shadow-dom-rules-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/startup/shadow-dom-rules-expected.txt
@@ -15,4 +15,9 @@
 div { (user agent stylesheet)
     display: block;
 
+======== Inherited from body ========
+[expanded] 
+html { (user agent stylesheet)
+/-- overloaded --/     color: -internal-root-color;
+
 
diff --git a/third_party/blink/web_tests/transforms/rotate-parsing.html b/third_party/blink/web_tests/transforms/rotate-parsing.html
index 48829f01..67693d0d 100644
--- a/third_party/blink/web_tests/transforms/rotate-parsing.html
+++ b/third_party/blink/web_tests/transforms/rotate-parsing.html
@@ -11,23 +11,24 @@
 
 expect('none').parsesAs('none').isComputedTo('none');
 expect('10deg').parsesAs('10deg').isComputedTo('10deg');
-expect('0 0 1 10deg').parsesAs('0 0 1 10deg').isComputedTo('10deg');
+expect('0 0 1 10deg').parsesAs('z 10deg').isComputedTo('10deg');
 expect('-1.5 2 3 10deg').parsesAs('-1.5 2 3 10deg').isComputedTo('-1.5 2 3 10deg');
 expect('45deg 1 2 3').parsesAs('1 2 3 45deg').isComputedTo('1 2 3 45deg');
 
-expect('x 45deg').parsesAs('1 0 0 45deg').isComputedTo('1 0 0 45deg');
-expect('45deg x').parsesAs('1 0 0 45deg').isComputedTo('1 0 0 45deg');
-expect('y 45deg').parsesAs('0 1 0 45deg').isComputedTo('0 1 0 45deg');
-expect('45deg y').parsesAs('0 1 0 45deg').isComputedTo('0 1 0 45deg');
-expect('z 45deg').parsesAs('0 0 1 45deg').isComputedTo('45deg');
-expect('45deg z').parsesAs('0 0 1 45deg').isComputedTo('45deg');
+expect('x 45deg').parsesAs('x 45deg').isComputedTo('1 0 0 45deg');
+expect('45deg x').parsesAs('x 45deg').isComputedTo('1 0 0 45deg');
+expect('y 45deg').parsesAs('y 45deg').isComputedTo('0 1 0 45deg');
+expect('45deg y').parsesAs('y 45deg').isComputedTo('0 1 0 45deg');
+expect('z 45deg').parsesAs('z 45deg').isComputedTo('45deg');
+expect('45deg z').parsesAs('z 45deg').isComputedTo('45deg');
 
 expect('200grad').parsesAs('200grad').isComputedTo('180deg');
 expect('1rad').parsesAs('1rad').isComputedTo('57.2958deg');
-expect('0 2 0 0.25turn').parsesAs('0 2 0 0.25turn').isComputedTo('0 2 0 90deg');
+expect('0 2 0 0.25turn').parsesAs('y 0.25turn').isComputedTo('0 1 0 90deg');
 
 expect('calc(1turn - 270deg)').parsesAs('calc(90deg)').isComputedTo('90deg');
-expect('0 calc(0.5 + 0.5) 1 calc(1turn - 270deg + 400grad)').parsesAs('0 1 1 calc(450deg)').isComputedTo('0 1 1 450deg');
+expect('0 calc(0.5 + 0.5) 1 calc(1turn - 270deg + 400grad)')
+    .parsesAs('0 1 1 calc(450deg)').isComputedTo('0 1 1 450deg');
 
 expect('2').isInvalid();
 expect('1 2deg').isInvalid();
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 63eeb21..e7759e6 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -51471,6 +51471,7 @@
   <int value="40" label="Mountain Shares"/>
   <int value="41" label="User Consents"/>
   <int value="42" label="Send Tab"/>
+  <int value="43" label="Security Events"/>
 </enum>
 
 <enum name="SyncModelTypeStoreInitResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4ddbc14..435bc8e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -144295,6 +144295,7 @@
   <suffix name="PriorityPreferences" label="Priority preferences"/>
   <suffix name="ReadingList" label="Reading list"/>
   <suffix name="SearchEngines" label="Search engines"/>
+  <suffix name="SecurityEvents" label="Security events"/>
   <suffix name="SendTabToSelf" label="Send tab to self"/>
   <suffix name="Sessions" label="Sessions"/>
   <suffix name="SyncedNotificationAppInfo" label="Synced notification app info">
diff --git a/tools/perf/core/bootstrap.py b/tools/perf/core/bootstrap.py
index 3a25f5f..c50ff73 100644
--- a/tools/perf/core/bootstrap.py
+++ b/tools/perf/core/bootstrap.py
@@ -2,97 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Bootstrap Chrome Telemetry by downloading all its files from SVN servers.
-
-Requires a DEPS file to specify which directories on which SVN servers
-are required to run Telemetry. Format of that DEPS file is a subset of the
-normal DEPS file format[1]; currently only only the "deps" dictionary is
-supported and nothing else.
-
-Fetches all files in the specified directories using WebDAV (SVN is WebDAV under
-the hood).
-
-[1] http://dev.chromium.org/developers/how-tos/depottools#TOC-DEPS-file
-"""
-
-import imp
-import logging
 import os
-import urllib
-import urlparse
-
-# Dummy module for DAVclient.
-davclient = None
-
-
-# TODO(eakuefner): Switch this link to tools/perf version after verifying.
-# Link to file containing the 'davclient' WebDAV client library.
-_DAVCLIENT_URL = ('https://src.chromium.org/chrome/trunk/src/tools/'
-                  'telemetry/third_party/davclient/davclient.py')
-
-
-def _DownloadAndImportDAVClientModule():
-  """Dynamically import davclient helper library."""
-  global davclient
-  davclient_src = urllib.urlopen(_DAVCLIENT_URL).read()
-  davclient = imp.new_module('davclient')
-  exec davclient_src in davclient.__dict__  # pylint: disable=exec-used
-
-
-class DAVClientWrapper(object):
-  """Knows how to retrieve subdirectories and files from WebDAV/SVN servers."""
-
-  def __init__(self, root_url):
-    """Initialize SVN server root_url, save files to local dest_dir.
-
-    Args:
-      root_url: string url of SVN/WebDAV server
-    """
-    self.root_url = root_url
-    self.client = davclient.DAVClient(root_url)
-
-  @staticmethod
-  def __norm_path_keys(dict_with_path_keys):
-    """Returns a dictionary with os.path.normpath called on every key."""
-    return dict((os.path.normpath(k), v) for (k, v) in
-                dict_with_path_keys.items())
-
-  def GetDirList(self, path):
-    """Returns string names of all files and subdirs of path on the server."""
-    props = self.__norm_path_keys(self.client.propfind(path, depth=1))
-    # remove this path
-    del props[os.path.normpath(path)]
-    return [os.path.basename(p) for p in props.keys()]
-
-  def IsFile(self, path):
-    """Returns True if the path is a file on the server, False if directory."""
-    props = self.__norm_path_keys(self.client.propfind(path, depth=1))
-    return props[os.path.normpath(path)]['resourcetype'] is None
-
-  def Traverse(self, src_path, dst_path):
-    """Walks the directory hierarchy pointed to by src_path download all files.
-
-    Recursively walks src_path and saves all files and subfolders into
-    dst_path.
-
-    Args:
-      src_path: string path on SVN server to save (absolute path on server).
-      dest_path: string local path (relative or absolute) to save to.
-    """
-    if self.IsFile(src_path):
-      if not os.path.exists(os.path.dirname(dst_path)):
-        logging.info('Creating %s', os.path.dirname(dst_path))
-        os.makedirs(os.path.dirname(dst_path))
-      if os.path.isfile(dst_path):
-        logging.info('Skipping %s', dst_path)
-      else:
-        logging.info('Saving %s to %s', self.root_url + src_path, dst_path)
-        urllib.urlretrieve(self.root_url + src_path, dst_path)
-      return
-    else:
-      for subdir in self.GetDirList(src_path):
-        self.Traverse(os.path.join(src_path, subdir),
-                      os.path.join(dst_path, subdir))
 
 
 def ListAllDepsPaths(deps_file):
@@ -127,35 +37,3 @@
     deps_paths += ListAllDepsPaths(path)
 
   return deps_paths
-
-
-def DownloadDeps(destination_dir, url):
-  """Saves all the dependencies in deps_path.
-
-  Opens and reads url, assuming the contents are in the simple DEPS-like file
-  format specified in the header of this file, then download all
-  files/directories listed to the destination_dir.
-
-  Args:
-    destination_dir: String path to directory to download files into.
-    url: URL containing deps information to be evaluated.
-  """
-  logging.warning('Downloading deps from %s...', url)
-  # TODO(wiltzius): Add a parameter for which revision to pull.
-  _DownloadAndImportDAVClientModule()
-
-  deps = {}
-  deps_includes = {}
-
-  exec urllib.urlopen(url).read()  # pylint: disable=exec-used
-
-  for dst_path, src_path in deps.iteritems():
-    full_dst_path = os.path.join(destination_dir, dst_path)
-    parsed_url = urlparse.urlparse(src_path)
-    root_url = parsed_url.scheme + '://' + parsed_url.netloc
-
-    dav_client = DAVClientWrapper(root_url)
-    dav_client.Traverse(parsed_url.path, full_dst_path)
-
-  for url in deps_includes.values():
-    DownloadDeps(destination_dir, url)
diff --git a/tools/perf/page_sets/system_health/system_health_story.py b/tools/perf/page_sets/system_health/system_health_story.py
index 535421d..bd09a818 100644
--- a/tools/perf/page_sets/system_health/system_health_story.py
+++ b/tools/perf/page_sets/system_health/system_health_story.py
@@ -7,6 +7,7 @@
 
 from telemetry.page import page
 from telemetry.page import shared_page_state
+from telemetry.util import wpr_modes
 
 
 # Extra wait time after the page has loaded required by the loading metric. We
@@ -54,8 +55,8 @@
   NAME = NotImplemented
   URL = NotImplemented
   ABSTRACT_STORY = True
-  # TODO(crbug.com/862077): SKIP_LOGIN is a temporary hack to skip the login
-  # flow during replay. Switch this to False when recording.
+  # Skip the login flow in replay mode
+  # If you want to replay the login flow in your story, set SKIP_LOGIN to False
   SKIP_LOGIN = True
   SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS
   TAGS = []
@@ -114,7 +115,7 @@
     pass
 
   def RunNavigateSteps(self, action_runner):
-    if not self.SKIP_LOGIN:
+    if not (self.SKIP_LOGIN and self.wpr_mode == wpr_modes.WPR_REPLAY):
       self._Login(action_runner)
     super(SystemHealthStory, self).RunNavigateSteps(action_runner)
 
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index a90813fd..f378c3b 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -281,6 +281,7 @@
  <item id="user_info_fetcher" hash_code="22265491" type="0" content_hash_code="72016232" os_list="linux,windows" file_path="components/policy/core/common/cloud/user_info_fetcher.cc"/>
  <item id="viz_devtools_server" hash_code="16292315" type="0" content_hash_code="70061664" os_list="linux,windows" file_path="components/ui_devtools/devtools_server.cc"/>
  <item id="web_history_counter" hash_code="137457845" type="1" second_id="110307337" content_hash_code="49663381" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/counters/history_counter.cc"/>
+ <item id="web_history_delete_url" hash_code="41749213" type="1" second_id="110307337" content_hash_code="25943026" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/history_service.cc"/>
  <item id="web_history_expire" hash_code="60946824" type="1" second_id="110307337" content_hash_code="92626030" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/browsing_history_service.cc"/>
  <item id="web_history_expire_between_dates" hash_code="126122632" type="1" second_id="110307337" content_hash_code="34304787" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/history_service.cc"/>
  <item id="web_history_query" hash_code="17400350" type="1" second_id="110307337" content_hash_code="36075147" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/browsing_history_service.cc"/>
diff --git a/ui/base/clipboard/BUILD.gn b/ui/base/clipboard/BUILD.gn
index e18f111..4ac85f4 100644
--- a/ui/base/clipboard/BUILD.gn
+++ b/ui/base/clipboard/BUILD.gn
@@ -84,17 +84,25 @@
 
   if (use_aura) {
     # Aura clipboard.
-    if (use_x11 && is_desktop_linux) {
-      sources += [
-        "clipboard_aurax11.cc",
-        "clipboard_aurax11.h",
-      ]
-      configs += [ "//build/config/linux:x11" ]
-      deps += [
-        "//ui/base",
-        "//ui/base/x",
-        "//ui/gfx/x",
-      ]
+    # Chromecast uses clipboard_aura now.
+    if (is_desktop_linux && !is_chromecast) {
+      if (use_ozone) {
+        sources += [
+          "clipboard_ozone.cc",
+          "clipboard_ozone.h",
+        ]
+      } else if (use_x11) {
+        sources += [
+          "clipboard_aurax11.cc",
+          "clipboard_aurax11.h",
+        ]
+        configs += [ "//build/config/linux:x11" ]
+        deps += [
+          "//ui/base",
+          "//ui/base/x",
+          "//ui/gfx/x",
+        ]
+      }
     } else if (!is_win) {
       # This file is used for all non-X11, non-Windows aura Builds.
       sources += [
@@ -115,6 +123,10 @@
       "CoreFoundation.framework",
     ]
   }
+
+  if (use_ozone) {
+    deps += [ "//ui/ozone" ]
+  }
 }
 
 jumbo_source_set("clipboard_test_support") {
diff --git a/ui/base/clipboard/DEPS b/ui/base/clipboard/DEPS
index e963fe5..2d253fb 100644
--- a/ui/base/clipboard/DEPS
+++ b/ui/base/clipboard/DEPS
@@ -1,4 +1,7 @@
 include_rules = [
+  "-ui/ozone/*",
   "+jni",
   "+third_party/mozilla",
+  "+ui/ozone/public/ozone_platform.h",
+  "+ui/ozone/public/platform_clipboard.h",
 ]
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc
new file mode 100644
index 0000000..54c9c5b
--- /dev/null
+++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -0,0 +1,449 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/clipboard_ozone.h"
+
+#include <limits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/timer/timer.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+namespace ui {
+
+namespace {
+
+// The amount of time to wait for a request to complete before aborting it.
+constexpr base::TimeDelta kRequestTimeoutMs =
+    base::TimeDelta::FromMilliseconds(10000);
+
+}  // namespace
+
+// A helper class, which uses a request pattern to asynchronously communicate
+// with the ozone::PlatformClipboard and fetch clipboard data with mimes
+// specified.
+class ClipboardOzone::AsyncClipboardOzone {
+ public:
+  explicit AsyncClipboardOzone(PlatformClipboard* platform_clipboard)
+      : platform_clipboard_(platform_clipboard), weak_factory_(this) {
+    // Set a callback to listen to requests to increase the clipboard sequence
+    // number.
+    auto update_sequence_cb =
+        base::BindRepeating(&AsyncClipboardOzone::UpdateClipboardSequenceNumber,
+                            weak_factory_.GetWeakPtr());
+    platform_clipboard_->SetSequenceNumberUpdateCb(
+        std::move(update_sequence_cb));
+  }
+
+  ~AsyncClipboardOzone() = default;
+
+  base::span<uint8_t> ReadClipboardDataAndWait(ClipboardType type,
+                                               const std::string& mime_type) {
+    // TODO(tonikitoo): add selection support.
+    if (type == ClipboardType::CLIPBOARD_TYPE_SELECTION)
+      return base::span<uint8_t>();
+
+    // We can use a fastpath if we are the owner of the selection.
+    if (platform_clipboard_->IsSelectionOwner()) {
+      auto it = offered_data_.find(mime_type);
+      if (it == offered_data_.end())
+        return base::span<uint8_t>();
+      return base::make_span(it->second.data(), it->second.size());
+    }
+
+    auto request = std::make_unique<Request>(RequestType::kRead);
+    request->requested_mime_type = mime_type;
+    ProcessRequestAndWaitForResult(request.get());
+
+    offered_data_ = std::move(request->data_map);
+    auto it = offered_data_.find(mime_type);
+    if (it == offered_data_.end())
+      return base::span<uint8_t>();
+    return base::make_span(it->second.data(), it->second.size());
+  }
+
+  std::vector<std::string> RequestMimeTypes() {
+    // We can use a fastpath if we are the owner of the selection.
+    if (platform_clipboard_->IsSelectionOwner()) {
+      std::vector<std::string> mime_types;
+      for (const auto& item : offered_data_)
+        mime_types.push_back(item.first);
+      return mime_types;
+    }
+
+    auto request = std::make_unique<Request>(RequestType::kGetMime);
+    ProcessRequestAndWaitForResult(request.get());
+    return std::move(request->mime_types);
+  }
+
+  void OfferData() {
+    auto request = std::make_unique<Request>(RequestType::kOffer);
+    request->data_map = offered_data_;
+    ProcessRequestAndWaitForResult(request.get());
+
+    UpdateClipboardSequenceNumber();
+  }
+
+  void InsertData(std::vector<uint8_t> data, const std::string& mime_type) {
+    DCHECK(offered_data_.find(mime_type) == offered_data_.end());
+    offered_data_[mime_type] = std::move(data);
+  }
+
+  void ClearOfferedData() { offered_data_.clear(); }
+
+  uint64_t GetSequenceNumber(ClipboardType type) {
+    if (type == ClipboardType::CLIPBOARD_TYPE_COPY_PASTE)
+      return clipboard_sequence_number_;
+    // TODO(tonikitoo): add sequence number for the selection clipboard type.
+    return 0;
+  }
+
+ private:
+  enum class RequestType {
+    kRead = 0,
+    kOffer = 1,
+    kGetMime = 2,
+  };
+
+  // A structure, which holds request data to process inquiries from
+  // the ClipboardOzone.
+  struct Request {
+    explicit Request(RequestType type) : current_type(type) {}
+    ~Request() = default;
+
+    // Describes the type of the request.
+    RequestType current_type;
+
+    // A closure that is used to signal the request is processed.
+    base::OnceClosure request_closure;
+
+    // Used for kRead and kOffer requests. It contains either data offered by
+    // Chromium to a system clipboard or a read data offered by the system
+    // clipboard.
+    PlatformClipboard::DataMap data_map;
+
+    // Identifies which mime type the client is interested to read from the
+    // system clipboard during kRead requests.
+    std::string requested_mime_type;
+
+    // A vector of mime types returned as a result to a kGetMime request to get
+    // available mime types.
+    std::vector<std::string> mime_types;
+  };
+
+  void ProcessRequestAndWaitForResult(Request* request) {
+    DCHECK(!abort_timer_.IsRunning());
+    DCHECK(!pending_request_);
+
+    // TODO(https://crbug.com/913422): the implementation is known to be
+    // dangerous, and may cause blocks in ui thkRead. But base::Clipboard was
+    // designed to have synchrous APIs rather than asynchronous ones that at
+    // least two system clipboards on X11 and Wayland provide.
+    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+    request->request_closure = run_loop.QuitClosure();
+
+    pending_request_ = request;
+    switch (pending_request_->current_type) {
+      case (RequestType::kRead):
+        ProcessReadRequest(request);
+        break;
+      case (RequestType::kOffer):
+        ProcessOfferRequest(request);
+        break;
+      case (RequestType::kGetMime):
+        ProcessGetMimeRequest(request);
+        break;
+    }
+
+    if (!pending_request_)
+      return;
+
+    // Set a timeout timer after which the request will be aborted.
+    abort_timer_.Start(FROM_HERE, kRequestTimeoutMs, this,
+                       &AsyncClipboardOzone::AbortStaledRequest);
+    run_loop.Run();
+  }
+
+  void AbortStaledRequest() {
+    if (pending_request_)
+      std::move(pending_request_->request_closure).Run();
+  }
+
+  void ProcessReadRequest(Request* request) {
+    auto callback = base::BindOnce(&AsyncClipboardOzone::OnTextRead,
+                                   weak_factory_.GetWeakPtr());
+    DCHECK(platform_clipboard_);
+    platform_clipboard_->RequestClipboardData(
+        request->requested_mime_type, &request->data_map, std::move(callback));
+  }
+
+  void ProcessOfferRequest(Request* request) {
+    auto callback = base::BindOnce(&AsyncClipboardOzone::OnOfferDone,
+                                   weak_factory_.GetWeakPtr());
+    DCHECK(platform_clipboard_);
+    platform_clipboard_->OfferClipboardData(request->data_map,
+                                            std::move(callback));
+  }
+
+  void ProcessGetMimeRequest(Request* request) {
+    auto callback = base::BindOnce(&AsyncClipboardOzone::OnGotMimeTypes,
+                                   weak_factory_.GetWeakPtr());
+    DCHECK(platform_clipboard_);
+    platform_clipboard_->GetAvailableMimeTypes(std::move(callback));
+  }
+
+  void OnTextRead(const base::Optional<std::vector<uint8_t>>& data) {
+    CompleteRequest();
+  }
+
+  void OnOfferDone() { CompleteRequest(); }
+
+  void OnGotMimeTypes(const std::vector<std::string>& mime_types) {
+    pending_request_->mime_types = std::move(mime_types);
+    CompleteRequest();
+  }
+
+  void CompleteRequest() {
+    abort_timer_.Stop();
+    auto closure = std::move(pending_request_->request_closure);
+    pending_request_ = nullptr;
+    std::move(closure).Run();
+  }
+
+  void UpdateClipboardSequenceNumber() { ++clipboard_sequence_number_; }
+
+  // Cached clipboard data, which is pending to be written. Must be cleared on
+  // every new write to the |platform_clipboard_|.
+  PlatformClipboard::DataMap offered_data_;
+
+  // A current pending request being processed.
+  Request* pending_request_ = nullptr;
+
+  // Aborts |pending_request| after Request::timeout.
+  base::RepeatingTimer abort_timer_;
+
+  // Provides communication to a system clipboard under ozone level.
+  PlatformClipboard* platform_clipboard_ = nullptr;
+
+  uint64_t clipboard_sequence_number_ = 0;
+
+  base::WeakPtrFactory<AsyncClipboardOzone> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncClipboardOzone);
+};
+
+// Clipboard factory method.
+Clipboard* Clipboard::Create() {
+  return new ClipboardOzone;
+}
+
+// ClipboardOzone implementation.
+ClipboardOzone::ClipboardOzone() {
+  async_clipboard_ozone_ =
+      std::make_unique<ClipboardOzone::AsyncClipboardOzone>(
+          OzonePlatform::GetInstance()->GetPlatformClipboard());
+}
+
+ClipboardOzone::~ClipboardOzone() = default;
+
+void ClipboardOzone::OnPreShutdown() {}
+
+uint64_t ClipboardOzone::GetSequenceNumber(ClipboardType type) const {
+  return async_clipboard_ozone_->GetSequenceNumber(type);
+}
+
+bool ClipboardOzone::IsFormatAvailable(const ClipboardFormatType& format,
+                                       ClipboardType type) const {
+  DCHECK(CalledOnValidThread());
+  // TODO(tonikitoo): add selection support.
+  if (type == ClipboardType::CLIPBOARD_TYPE_SELECTION)
+    return false;
+
+  auto available_types = async_clipboard_ozone_->RequestMimeTypes();
+  for (auto mime_type : available_types) {
+    if (format.ToString() == mime_type) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void ClipboardOzone::Clear(ClipboardType type) {
+  async_clipboard_ozone_->ClearOfferedData();
+  async_clipboard_ozone_->OfferData();
+}
+
+void ClipboardOzone::ReadAvailableTypes(ClipboardType type,
+                                        std::vector<base::string16>* types,
+                                        bool* contains_filenames) const {
+  DCHECK(CalledOnValidThread());
+  types->clear();
+
+  // TODO(tonikitoo): add selection support.
+  if (type == ClipboardType::CLIPBOARD_TYPE_SELECTION)
+    return;
+
+  auto available_types = async_clipboard_ozone_->RequestMimeTypes();
+  for (auto mime_type : available_types)
+    types->push_back(base::UTF8ToUTF16(mime_type));
+}
+
+void ClipboardOzone::ReadText(ClipboardType type,
+                              base::string16* result) const {
+  DCHECK(CalledOnValidThread());
+
+  auto clipboard_data =
+      async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeText);
+  *result = base::UTF8ToUTF16(base::StringPiece(
+      reinterpret_cast<char*>(clipboard_data.data()), clipboard_data.size()));
+}
+
+void ClipboardOzone::ReadAsciiText(ClipboardType type,
+                                   std::string* result) const {
+  DCHECK(CalledOnValidThread());
+  auto clipboard_data =
+      async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeText);
+  result->assign(clipboard_data.begin(), clipboard_data.end());
+}
+
+void ClipboardOzone::ReadHTML(ClipboardType type,
+                              base::string16* markup,
+                              std::string* src_url,
+                              uint32_t* fragment_start,
+                              uint32_t* fragment_end) const {
+  DCHECK(CalledOnValidThread());
+  markup->clear();
+  if (src_url)
+    src_url->clear();
+  *fragment_start = 0;
+  *fragment_end = 0;
+
+  auto clipboard_data =
+      async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeHTML);
+  *markup = base::UTF8ToUTF16(base::StringPiece(
+      reinterpret_cast<char*>(clipboard_data.data()), clipboard_data.size()));
+  DCHECK(markup->length() <= std::numeric_limits<uint32_t>::max());
+  *fragment_end = static_cast<uint32_t>(markup->length());
+}
+
+void ClipboardOzone::ReadRTF(ClipboardType type, std::string* result) const {
+  DCHECK(CalledOnValidThread());
+  auto clipboard_data =
+      async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeRTF);
+  result->assign(clipboard_data.begin(), clipboard_data.end());
+}
+
+SkBitmap ClipboardOzone::ReadImage(ClipboardType type) const {
+  DCHECK(CalledOnValidThread());
+  auto clipboard_data =
+      async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypePNG);
+  SkBitmap bitmap;
+  if (gfx::PNGCodec::Decode(clipboard_data.data(), clipboard_data.size(),
+                            &bitmap))
+    return SkBitmap(bitmap);
+  return SkBitmap();
+}
+
+void ClipboardOzone::ReadCustomData(ClipboardType clipboard_type,
+                                    const base::string16& type,
+                                    base::string16* result) const {
+  DCHECK(CalledOnValidThread());
+  auto custom_data = async_clipboard_ozone_->ReadClipboardDataAndWait(
+      clipboard_type, kMimeTypeWebCustomData);
+  ui::ReadCustomDataForType(custom_data.data(), custom_data.size(), type,
+                            result);
+}
+
+void ClipboardOzone::ReadBookmark(base::string16* title,
+                                  std::string* url) const {
+  DCHECK(CalledOnValidThread());
+  // TODO(msisov): This was left NOTIMPLEMENTED() in all the Linux platforms.
+  NOTIMPLEMENTED();
+}
+
+void ClipboardOzone::ReadData(const ClipboardFormatType& format,
+                              std::string* result) const {
+  DCHECK(CalledOnValidThread());
+  auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait(
+      ClipboardType::CLIPBOARD_TYPE_COPY_PASTE, format.ToString());
+  result->assign(clipboard_data.begin(), clipboard_data.end());
+}
+
+void ClipboardOzone::WriteObjects(ClipboardType type,
+                                  const ObjectMap& objects) {
+  DCHECK(CalledOnValidThread());
+  if (type == ClipboardType::CLIPBOARD_TYPE_COPY_PASTE) {
+    async_clipboard_ozone_->ClearOfferedData();
+
+    for (const auto& object : objects)
+      DispatchObject(static_cast<ObjectType>(object.first), object.second);
+
+    async_clipboard_ozone_->OfferData();
+  }
+}
+
+void ClipboardOzone::WriteText(const char* text_data, size_t text_len) {
+  std::vector<uint8_t> data(text_data, text_data + text_len);
+  async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeText);
+}
+
+void ClipboardOzone::WriteHTML(const char* markup_data,
+                               size_t markup_len,
+                               const char* url_data,
+                               size_t url_len) {
+  std::vector<uint8_t> data(markup_data, markup_data + markup_len);
+  async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeHTML);
+}
+
+void ClipboardOzone::WriteRTF(const char* rtf_data, size_t data_len) {
+  std::vector<uint8_t> data(rtf_data, rtf_data + data_len);
+  async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeRTF);
+}
+
+void ClipboardOzone::WriteBookmark(const char* title_data,
+                                   size_t title_len,
+                                   const char* url_data,
+                                   size_t url_len) {
+  // Writes a Mozilla url (UTF16: URL, newline, title)
+  base::string16 bookmark =
+      base::UTF8ToUTF16(base::StringPiece(url_data, url_len)) +
+      base::ASCIIToUTF16("\n") +
+      base::UTF8ToUTF16(base::StringPiece(title_data, title_len));
+
+  std::vector<uint8_t> data(
+      reinterpret_cast<const uint8_t*>(bookmark.data()),
+      reinterpret_cast<const uint8_t*>(bookmark.data() + bookmark.size()));
+  async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeMozillaURL);
+}
+
+void ClipboardOzone::WriteWebSmartPaste() {
+  async_clipboard_ozone_->InsertData(std::vector<uint8_t>(),
+                                     kMimeTypeWebkitSmartPaste);
+}
+
+void ClipboardOzone::WriteBitmap(const SkBitmap& bitmap) {
+  std::vector<unsigned char> output;
+  if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output))
+    async_clipboard_ozone_->InsertData(std::move(output), kMimeTypePNG);
+}
+
+void ClipboardOzone::WriteData(const ClipboardFormatType& format,
+                               const char* data_data,
+                               size_t data_len) {
+  std::vector<uint8_t> data(data_data, data_data + data_len);
+  async_clipboard_ozone_->InsertData(data, format.ToString());
+}
+
+}  // namespace ui
diff --git a/ui/base/clipboard/clipboard_ozone.h b/ui/base/clipboard/clipboard_ozone.h
new file mode 100644
index 0000000..6a91fe1
--- /dev/null
+++ b/ui/base/clipboard/clipboard_ozone.h
@@ -0,0 +1,76 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_OZONE_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_OZONE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/base/clipboard/clipboard.h"
+
+namespace ui {
+
+class ClipboardOzone : public Clipboard {
+ private:
+  friend class Clipboard;
+
+  ClipboardOzone();
+  ~ClipboardOzone() override;
+
+  // Clipboard overrides:
+  void OnPreShutdown() override;
+  uint64_t GetSequenceNumber(ClipboardType type) const override;
+  bool IsFormatAvailable(const ClipboardFormatType& format,
+                         ClipboardType type) const override;
+  void Clear(ClipboardType type) override;
+  void ReadAvailableTypes(ClipboardType type,
+                          std::vector<base::string16>* types,
+                          bool* contains_filenames) const override;
+  void ReadText(ClipboardType type, base::string16* result) const override;
+  void ReadAsciiText(ClipboardType type, std::string* result) const override;
+  void ReadHTML(ClipboardType type,
+                base::string16* markup,
+                std::string* src_url,
+                uint32_t* fragment_start,
+                uint32_t* fragment_end) const override;
+  void ReadRTF(ClipboardType type, std::string* result) const override;
+  SkBitmap ReadImage(ClipboardType type) const override;
+  void ReadCustomData(ClipboardType clipboard_type,
+                      const base::string16& type,
+                      base::string16* result) const override;
+  void ReadBookmark(base::string16* title, std::string* url) const override;
+  void ReadData(const ClipboardFormatType& format,
+                std::string* result) const override;
+  void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
+  void WriteText(const char* text_data, size_t text_len) override;
+  void WriteHTML(const char* markup_data,
+                 size_t markup_len,
+                 const char* url_data,
+                 size_t url_len) override;
+  void WriteRTF(const char* rtf_data, size_t data_len) override;
+  void WriteBookmark(const char* title_data,
+                     size_t title_len,
+                     const char* url_data,
+                     size_t url_len) override;
+  void WriteWebSmartPaste() override;
+  void WriteBitmap(const SkBitmap& bitmap) override;
+  void WriteData(const ClipboardFormatType& format,
+                 const char* data_data,
+                 size_t data_len) override;
+
+  class AsyncClipboardOzone;
+
+  std::unique_ptr<AsyncClipboardOzone> async_clipboard_ozone_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClipboardOzone);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_CLIPBOARD_CLIPBOARD_OZONE_H_
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index 0dde00d..ce83df2c 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -189,8 +189,8 @@
   EXPECT_EQ(rtf, result);
 }
 
-// TODO(dnicoara) Enable test once Ozone implements clipboard support:
-// crbug.com/361707
+// TODO(msisov, tonikitoo): Enable test once ClipboardOzone implements
+// selection support. https://crbug.com/911992
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE)
 TYPED_TEST(ClipboardTest, MultipleBufferTest) {
   base::string16 text(ASCIIToUTF16("Standard")), text_result;
@@ -376,8 +376,10 @@
   this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text);
   EXPECT_EQ(UTF16ToUTF8(url), ascii_text);
 
+// TODO(tonikitoo, msisov): enable back for ClipboardOzone implements
+// selection support. https://crbug.com/911992
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
-    !defined(OS_CHROMEOS)
+    !defined(OS_CHROMEOS) && !defined(USE_OZONE)
   ascii_text.clear();
   this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_SELECTION, &ascii_text);
   EXPECT_EQ(UTF16ToUTF8(url), ascii_text);
diff --git a/ui/events/blink/prediction/empty_predictor.cc b/ui/events/blink/prediction/empty_predictor.cc
index dd4097c..75cee1d 100644
--- a/ui/events/blink/prediction/empty_predictor.cc
+++ b/ui/events/blink/prediction/empty_predictor.cc
@@ -8,7 +8,7 @@
 
 EmptyPredictor::EmptyPredictor() {
   Reset();
-};
+}
 
 EmptyPredictor::~EmptyPredictor() = default;
 
diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc
index 3939c1a..3e82f76 100644
--- a/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/wayland_connection.cc
@@ -251,6 +251,13 @@
   return !!data_source_;
 }
 
+void WaylandConnection::SetSequenceNumberUpdateCb(
+    PlatformClipboard::SequenceNumberUpdateCb cb) {
+  CHECK(update_sequence_cb_.is_null())
+      << " The callback can be installed only once.";
+  update_sequence_cb_ = std::move(cb);
+}
+
 ozone::mojom::WaylandConnectionPtr WaylandConnection::BindInterface() {
   // This mustn't be called twice or when the zwp_linux_dmabuf interface is not
   // available.
@@ -332,6 +339,11 @@
   data_map_ = nullptr;
 }
 
+void WaylandConnection::UpdateClipboardSequenceNumber() {
+  if (!update_sequence_cb_.is_null())
+    update_sequence_cb_.Run();
+}
+
 void WaylandConnection::OnDispatcherListChanged() {
   StartProcessingEvents();
 }
diff --git a/ui/ozone/platform/wayland/wayland_connection.h b/ui/ozone/platform/wayland/wayland_connection.h
index 61c6940..bb00ae47 100644
--- a/ui/ozone/platform/wayland/wayland_connection.h
+++ b/ui/ozone/platform/wayland/wayland_connection.h
@@ -120,6 +120,7 @@
   void DataSourceCancelled();
   void SetClipboardData(const std::string& contents,
                         const std::string& mime_type);
+  void UpdateClipboardSequenceNumber();
 
   // PlatformClipboard.
   void OfferClipboardData(
@@ -132,6 +133,8 @@
   void GetAvailableMimeTypes(
       PlatformClipboard::GetMimeTypesClosure callback) override;
   bool IsSelectionOwner() override;
+  void SetSequenceNumberUpdateCb(
+      PlatformClipboard::SequenceNumberUpdateCb cb) override;
 
   // Returns bound pointer to own mojo interface.
   ozone::mojom::WaylandConnectionPtr BindInterface();
@@ -236,6 +239,10 @@
   // so that we can asynchronously write to it.
   PlatformClipboard::DataMap* data_map_ = nullptr;
 
+  // Notifies whenever clipboard sequence number is changed. Can be empty if not
+  // set.
+  PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
+
   // Stores the callback to be invoked upon data reading from clipboard.
   RequestDataClosure read_clipboard_closure_;
 
diff --git a/ui/ozone/platform/wayland/wayland_data_device.cc b/ui/ozone/platform/wayland/wayland_data_device.cc
index 0677426..92e96de0 100644
--- a/ui/ozone/platform/wayland/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/wayland_data_device.cc
@@ -224,6 +224,8 @@
                                     wl_data_offer* offer) {
   auto* self = static_cast<WaylandDataDevice*>(data);
 
+  self->connection_->UpdateClipboardSequenceNumber();
+
   DCHECK(!self->new_offer_);
   self->new_offer_.reset(new WaylandDataOffer(offer));
 }
diff --git a/ui/ozone/public/platform_clipboard.h b/ui/ozone/public/platform_clipboard.h
index df59409..4963e24d 100644
--- a/ui/ozone/public/platform_clipboard.h
+++ b/ui/ozone/public/platform_clipboard.h
@@ -26,6 +26,10 @@
   using Data = std::vector<uint8_t>;
   using DataMap = std::unordered_map<std::string, Data>;
 
+  // SequenceNumberUpdateCb is a repeating callback, which can be used to tell
+  // a client of the PlatformClipboard to increment clipboard's sequence number
+  using SequenceNumberUpdateCb = base::RepeatingCallback<void()>;
+
   // Offers a given clipboard data 'data_map' to the host system clipboard.
   //
   // It is common that host clipboard implementations simply get offered
@@ -71,6 +75,9 @@
   // caches the clipboard data, and wants to know if it is possible to use
   // the cached data in order to reply faster to read-clipboard operations.
   virtual bool IsSelectionOwner() = 0;
+
+  // See comment above SequenceNumberUpdateCb. Can be called once.
+  virtual void SetSequenceNumberUpdateCb(SequenceNumberUpdateCb cb) = 0;
 };
 
 }  // namespace ui