diff --git a/AUTHORS b/AUTHORS
index e7b6183..eb66b2cb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -214,6 +214,7 @@
 Debug Wang <debugwang@tencent.com>
 Deepak Dilip Borade <deepak.db@samsung.com>
 Deepak Mittal <deepak.m1@samsung.com>
+Deepak Sharma <deepak.sharma@amd.com>
 Deepak Singla <deepak.s@samsung.com>
 Deokjin Kim <deokjin81.kim@samsung.com>
 Derek Halman <d.halman@gmail.com>
diff --git a/DEPS b/DEPS
index 90565694..0bddd4485 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': '34a2a76e209486e2baf42b18b4993380e67d11e3',
+  'skia_revision': '5ba2a8a5b24f6ad0e2f05b2c80e25b31b842d0e7',
   # 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': '8d1908ecc1ef0422d33878dbacc27a34013bb8f3',
+  'v8_revision': 'a92414793e83062fde46f6a4b74e074e13d808e4',
   # 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.
@@ -138,15 +138,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'b6c1c66d25476bf7041e8a790f3fbfddc53e0674',
+  'angle_revision': '028df5f51e45f50ebfef480fd93fc9325a7bf0b8',
   # 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': '0eba65b14b60f9a1937c0c123eb0190b676a2d9d',
+  'swiftshader_revision': '6d74ab852bf2cbada5b3f7cd07402f72d01c45f4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '34fb6244cfec267b4f25024b534416f94a866f82',
+  'pdfium_revision': '81e11ef441b306675e4eb5d3b9056643c84f86d0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -173,7 +173,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '908d9f47b1b2d9027ad421d4c7e4c55c96532deb',
+  'nacl_revision': '1ed9878b8eb68c1e0d0268754dafcf83e747fa8f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -189,7 +189,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '1f97ac96e633e90e0f7053d051b07234817de37c',
+  'catapult_revision': 'ede50ff4d8592b6e77a64ae1a685c096575190e7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -205,7 +205,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'feed_revision': '3293f23ae831c666be27273fbf2a73d9b2fe7552',
+  'feed_revision': 'd21310a7afa812e54d9d235de12cb409a0fd28c4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
@@ -253,7 +253,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '695b68d1009b9ed6274a9970e19acf029494fe4d',
+  'dawn_revision': '81da14f45c611fbc86cc1c03a18235d2a0084324',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -737,7 +737,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2b0f8cfb744046b3bae6a08c54cff73500da0b31',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'fa1c43790f94b7694f53dba46462b31741f715e8',
       'condition': 'checkout_linux',
   },
 
@@ -762,7 +762,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'efc7e91fa76494f7f134926a384f4c0101ae982c',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5c00a22f22e448ab64e8642259a759693e46fd72',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1080,7 +1080,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/ow2_asm',
-              'version': '0dcaea8bd839b3f2eb8415c327b40e8e398a373e',
+              'version': 'NNAhdJzMdnutUVqfSJm5v0tVazA9l3Dd6CRwH6N4Q5kC',
           },
       ],
       'condition': 'checkout_android',
@@ -1097,7 +1097,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '7081b4fe0f79da24f4e5bdd482573beb70e57257',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '1721b1ab70ad2b695fbcb3390e48c2607fb323cd',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1186,7 +1186,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/robolectric',
-              'version': 'Q-aurrjcIq02dl2ws-M-IhnIydurvTbUMR_xD_zBJ0YC',
+              'version': 'iRFT1e5YFmRn5cbV0cAkQ5vDUXFmQ4qPYqStmmDfiMMC',
           },
       ],
       'condition': 'checkout_android',
@@ -1194,10 +1194,21 @@
   },
 
   'src/third_party/robolectric/robolectric': {
-      'url': Var('chromium_git') + '/external/robolectric.git' + '@' + '7e067f1112e1502caa742f7be72d37b5678d3403',
+      'url': Var('chromium_git') + '/external/robolectric.git' + '@' + '3d6dcabf5521e028c8efc2778ab6bd8c7b6d923c',
       'condition': 'checkout_android',
   },
 
+  'src/third_party/androidx': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/androidx',
+              'version': 'BgU0HKOH7unGo87kXkIKJlPMmaSOCFhvUKcIr9aborwC',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
   'src/third_party/sfntly/src':
     Var('chromium_git') + '/external/github.com/googlei18n/sfntly.git' + '@' + Var('sfntly_revision'),
 
@@ -1260,7 +1271,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a0f51b2e123f39c9ff12e621b0b47dd28dd64424',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '106d92d4c930088d2e7ae6ca74fa863a5edb9db8',
+    Var('webrtc_git') + '/src.git' + '@' + 'afb5dbbf4ef5a8462380f3ba4a61937f6b802e35',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1288,7 +1299,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/${{platform}}',
-          'version': 'git_revision:21cbe1f4cc524c5d54d563951bc4c0687d57a8e7',
+          'version': 'git_revision:67cbd2d75725e090d94a952d6b1f9055b19099d4',
         },
       ],
       'dep_type': 'cipd',
@@ -1301,7 +1312,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@af2885953ccf44817567480ab8dc21c81d15e921',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c872b367e3f8e0a4a89951c0f85d3743f1a140ec',
     'condition': 'checkout_src_internal',
   },
 
@@ -2623,18 +2634,6 @@
     ],
   },
   {
-    'name': 'gvr_static_shim_android_arm_ndk1',
-    'pattern': '\\.sha1',
-    'condition': 'checkout_android',
-    'action': [ 'python',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-gvr-static-shim',
-                '-s', 'src/third_party/gvr-android-sdk/libgvr_shim_static_arm_ndk1.a.sha1',
-    ],
-  },
-  {
     'name': 'gvr_static_shim_android_arm_Cr',
     'pattern': '\\.sha1',
     'condition': 'checkout_android',
@@ -2659,18 +2658,6 @@
     ],
   },
   {
-    'name': 'gvr_static_shim_android_arm64_ndk1',
-    'pattern': '\\.sha1',
-    'condition': 'checkout_android',
-    'action': [ 'python',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-gvr-static-shim',
-                '-s', 'src/third_party/gvr-android-sdk/libgvr_shim_static_arm64_ndk1.a.sha1',
-    ],
-  },
-  {
     'name': 'gvr_static_shim_android_arm64_Cr',
     'pattern': '\\.sha1',
     'condition': 'checkout_android',
diff --git a/WATCHLISTS b/WATCHLISTS
index e8cff481..eec0184 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2344,7 +2344,7 @@
                      'sergeyu@chromium.org',
                      'spang+watch@chromium.org',
                      'wez@chromium.org'],
-    'page_info' : ['raymes+watch@chromium.org'],
+    'page_info' : ['permissions-reviews@chromium.org'],
     'page_load_metrics' : ['bmcquade+watch@chromium.org',
                            'csharrison+watch@chromium.org',
                            'loading-reviews+metrics@chromium.org',
@@ -2369,7 +2369,6 @@
                     'hanxi+watch@chromium.org',
                     'mlamouri+watch-permissions@chromium.org',
                     'permissions-reviews@chromium.org',
-                    'raymes+watch@chromium.org',
                     'timloh+watch@chromium.org'],
     'picture_in_picture': ['beaufort.francois+pip@gmail.com'],
     'policy_templates': ['ljusten+watch@chromium.org'],
@@ -2510,8 +2509,7 @@
     'webrtc_browser_tests': ['phoglund+watch@chromium.org'],
     'website_settings': ['dullweber+watch@chromium.org',
                          'markusheintz@chromium.org',
-                         'msramek+watch@chromium.org',
-                         'raymes+watch@chromium.org'],
+                         'msramek+watch@chromium.org'],
     'webui_backend': ['dbeam+watch-webui-backend@chromium.org'],
     'windows_sandboxing': ['wfh+watch@chromium.org'],
     'x11': ['derat+watch@chromium.org',
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc
index 4306d26..172c506 100644
--- a/ash/app_list/views/assistant/assistant_page_view.cc
+++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -47,6 +47,12 @@
       views::Painter::CreateSolidRoundRectPainter(
           SK_ColorWHITE, search_box::kSearchBoxBorderCornerRadius)));
 
+  mask_ = views::Painter::CreatePaintedLayer(
+      views::Painter::CreateSolidRoundRectPainter(
+          SK_ColorBLACK, search_box::kSearchBoxBorderCornerRadius));
+  mask_->layer()->SetFillsBoundsOpaquely(false);
+  layer()->SetMaskLayer(mask_->layer());
+
   SetLayoutManager(std::make_unique<views::FillLayout>());
 }
 
@@ -66,6 +72,10 @@
   assistant_main_view_->RequestFocus();
 }
 
+void AssistantPageView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  mask_->layer()->SetBounds(GetLocalBounds());
+}
+
 void AssistantPageView::OnMouseEvent(ui::MouseEvent* event) {
   switch (event->type()) {
     case ui::ET_MOUSE_PRESSED:
diff --git a/ash/app_list/views/assistant/assistant_page_view.h b/ash/app_list/views/assistant/assistant_page_view.h
index 352ef1f..41a0af8 100644
--- a/ash/app_list/views/assistant/assistant_page_view.h
+++ b/ash/app_list/views/assistant/assistant_page_view.h
@@ -14,6 +14,10 @@
 class AssistantViewDelegate;
 }  // namespace ash
 
+namespace ui {
+class LayerOwner;
+}  // namespace ui
+
 namespace app_list {
 
 class AssistantMainView;
@@ -33,6 +37,7 @@
   const char* GetClassName() const override;
   gfx::Size CalculatePreferredSize() const override;
   void RequestFocus() override;
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
 
   // ui::EventHandler:
   void OnMouseEvent(ui::MouseEvent* event) override;
@@ -49,6 +54,9 @@
   ContentsView* contents_view_ = nullptr;
   AssistantMainView* assistant_main_view_ = nullptr;
 
+  // Used to enforce round corners on the Assistant view hierarchy.
+  std::unique_ptr<ui::LayerOwner> mask_;
+
   DISALLOW_COPY_AND_ASSIGN(AssistantPageView);
 };
 
diff --git a/ash/app_list/views/assistant/dialog_plate.cc b/ash/app_list/views/assistant/dialog_plate.cc
index 1bd41c7..482d745e 100644
--- a/ash/app_list/views/assistant/dialog_plate.cc
+++ b/ash/app_list/views/assistant/dialog_plate.cc
@@ -36,7 +36,7 @@
 // Appearance.
 // TODO(wutao): need to be finalized.
 constexpr int kDialogLeftPaddingDip = 16;
-constexpr int kDialogRightPaddingDip = 8;
+constexpr int kDialogRightPaddingDip = 16;
 constexpr int kSmallIconSizeDip = 18;
 constexpr int kIconSizeDip = 24;
 constexpr int kButtonSizeDip = 32;
@@ -310,13 +310,12 @@
   keyboard_layout_container_->layer()->SetFillsBoundsOpaquely(false);
   keyboard_layout_container_->layer()->SetOpacity(0.f);
 
-  constexpr int kHorizontalPaddingDip = 16;
-
+  constexpr int kLeftPaddingDip = 16;
   views::BoxLayout* layout_manager =
       keyboard_layout_container_->SetLayoutManager(
           std::make_unique<views::BoxLayout>(
               views::BoxLayout::Orientation::kHorizontal,
-              gfx::Insets(0, kHorizontalPaddingDip)));
+              gfx::Insets(0, kLeftPaddingDip, 0, 0)));
 
   layout_manager->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
@@ -358,22 +357,13 @@
   voice_layout_container_->layer()->SetFillsBoundsOpaquely(false);
   voice_layout_container_->layer()->SetOpacity(0.f);
 
-  constexpr int kLeftPaddingDip = 8;
   views::BoxLayout* layout_manager = voice_layout_container_->SetLayoutManager(
       std::make_unique<views::BoxLayout>(
-          views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets(0, kLeftPaddingDip, 0, 0)));
+          views::BoxLayout::Orientation::kHorizontal));
 
   layout_manager->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
 
-  // Keyboard input toggle.
-  keyboard_input_toggle_ = ash::AssistantButton::Create(
-      this, ash::kKeyboardIcon, kButtonSizeDip, kIconSizeDip,
-      IDS_ASH_ASSISTANT_DIALOG_PLATE_KEYBOARD_ACCNAME,
-      ash::AssistantButtonId::kKeyboardInputToggle);
-  voice_layout_container_->AddChildView(keyboard_input_toggle_);
-
   // Spacer.
   views::View* spacer = new views::View();
   voice_layout_container_->AddChildView(spacer);
@@ -403,12 +393,18 @@
       /*back_button_width=*/kButtonSizeDip +
       /*separator_padding=*/kSeparatorPaddingDip +
       /*separator_thickness=*/1 +
-      /*molecule_icon_width=*/kIconSizeDip +
-      /*keyboard_input_toggle_left_padding=*/kLeftPaddingDip +
+      /*molecule_icon_width=*/kIconSizeDip -
       /*keyboard_input_toggle_width*/ kButtonSizeDip;
   spacer->SetPreferredSize(gfx::Size(spacing, 1));
   voice_layout_container_->AddChildView(spacer);
 
+  // Keyboard input toggle.
+  keyboard_input_toggle_ = ash::AssistantButton::Create(
+      this, ash::kKeyboardIcon, kButtonSizeDip, kIconSizeDip,
+      IDS_ASH_ASSISTANT_DIALOG_PLATE_KEYBOARD_ACCNAME,
+      ash::AssistantButtonId::kKeyboardInputToggle);
+  voice_layout_container_->AddChildView(keyboard_input_toggle_);
+
   input_modality_layout_container_->AddChildView(voice_layout_container_);
 }
 
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc
index 209926a..88f5e8b52 100644
--- a/ash/assistant/assistant_interaction_controller.cc
+++ b/ash/assistant/assistant_interaction_controller.cc
@@ -130,9 +130,20 @@
     return;
   }
 
+  // Explicitly call ShowUi() to set the correct Assistant entry point.
+  // ShowUi() will no-op if UI is already shown.
   assistant_controller_->ui_controller()->ShowUi(
       AssistantEntryPoint::kDeepLink);
-  StartTextInteraction(query.value(), /*allow_tts=*/false,
+
+  // A text query originating from a deep link will carry forward the allowance/
+  // forbiddance of TTS from the previous response. This is predominately aimed
+  // at addressing the use case of tapping a card from a previous query response
+  // in which case we are essentially continuing the preceding interaction. Deep
+  // links are also potentially fired from notifications or other sources. If we
+  // need to allow deep link creators the ability to set |allow_tts| explicitly,
+  // we can expose a deep link parameter when the need arises.
+  StartTextInteraction(query.value(), /*allow_tts=*/model_.response() &&
+                                          model_.response()->has_tts(),
                        /*query_source=*/AssistantQuerySource::kDeepLink);
 }
 
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index f58395d..9a42ce693 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -126,6 +126,7 @@
 
   deps = [
     "//ash/public/cpp/vector_icons",
+    "//chromeos:chromeos_constants",
     "//chromeos/dbus:power_manager_proto",
     "//components/prefs",
     "//mojo/public/cpp/bindings",
diff --git a/ash/public/cpp/DEPS b/ash/public/cpp/DEPS
index b969121..e06dd0c 100644
--- a/ash/public/cpp/DEPS
+++ b/ash/public/cpp/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+chromeos/constants",
   "+components/prefs",
   "+services/data_decoder/public",
   "+services/device/public",
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index 5f50698..db0a6ed 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -7,6 +7,7 @@
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
+#include "chromeos/constants/chromeos_switches.h"
 
 namespace app_list_features {
 
@@ -76,7 +77,8 @@
 }
 
 bool IsEmbeddedAssistantUIEnabled() {
-  return base::FeatureList::IsEnabled(kEnableEmbeddedAssistantUI);
+  return chromeos::switches::IsAssistantEnabled() &&
+         base::FeatureList::IsEnabled(kEnableEmbeddedAssistantUI);
 }
 
 std::string AnswerServerUrl() {
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index b38bc78..d7aadec 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -816,6 +816,16 @@
   return open_windows;
 }
 
+views::View* ShelfView::FindFirstOrLastFocusableChild(bool last) const {
+  if (last) {
+    return overflow_button_->visible()
+               ? overflow_button_
+               : view_model_->view_at(last_visible_index());
+  } else {
+    return view_model_->view_at(first_visible_index());
+  }
+}
+
 void ShelfView::DestroyDragIconProxy() {
   drag_image_.reset();
   drag_image_offset_ = gfx::Vector2d(0, 0);
@@ -1193,6 +1203,13 @@
       IndexOfLastItemThatFitsSize(available_size - button_spacing);
   bool show_overflow = last_visible_index_ < model_->item_count() - 1;
 
+  // In the main shelf, the first visible index is either the back button (in
+  // tablet mode) or the launcher button (otherwise).
+  if (!is_overflow_mode()) {
+    first_visible_index_ =
+        IsTabletModeEnabled() ? kBackButtonIndex : kAppListButtonIndex;
+  }
+
   // Create space for the overflow button and place it in the last visible
   // position.
   if (show_overflow && last_visible_index_ > 0)
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 7cfc45b8..a658aba 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -264,6 +264,8 @@
   const std::vector<aura::Window*> GetOpenWindowsForShelfView(
       views::View* view);
 
+  views::View* FindFirstOrLastFocusableChild(bool last) const;
+
   // Return the view model for test purposes.
   const views::ViewModel* view_model_for_test() const {
     return view_model_.get();
@@ -508,9 +510,12 @@
   // item in |model_|.
   std::unique_ptr<views::ViewModel> view_model_;
 
-  // Index of the first visible launcher item. This is not always zero because
-  // the overflow view (also a kind of shelf view) only shows a subset of items.
-  int first_visible_index_ = 0;
+  // Index of the first visible launcher item. This is either:
+  // * 0 (back button) for the main shelf when tablet mode is on
+  // * 1 (app list button) for the main shelf when tablet mode is off
+  // * > 1 when this shelf view is the overflow shelf view and only shows a
+  //   subset of items.
+  mutable int first_visible_index_ = 0;
 
   // Last index of a launcher button that is visible
   // (does not go into overflow).
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 004f192..cd6139e3 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -264,12 +264,15 @@
 }
 
 views::View* ShelfWidget::DelegateView::GetDefaultFocusableChild() {
-  // If views-based login shelf is shown, we want to focus either its first or
-  // last child, otherwise focus on the first child as default.
-  if (IsUsingViewsShelf())
+  if (!IsUsingViewsShelf())
+    return GetFirstFocusableChild();
+
+  if (shelf_widget_->login_shelf_view_->visible())
     return FindFirstOrLastFocusableChild(shelf_widget_->login_shelf_view_,
                                          default_last_focusable_child_);
-  return GetFirstFocusableChild();
+  else
+    return shelf_widget_->shelf_view_->FindFirstOrLastFocusableChild(
+        default_last_focusable_child_);
 }
 
 void ShelfWidget::DelegateView::UpdateShelfBackground(SkColor color) {
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc
index d744c5d6..6a6d6df 100644
--- a/ash/system/power/power_button_controller.cc
+++ b/ash/system/power/power_button_controller.cc
@@ -533,7 +533,7 @@
     return;
 
   std::unique_ptr<base::DictionaryValue> position_info =
-      base::DictionaryValue::From(base::JSONReader::Read(
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
           cl->GetSwitchValueASCII(switches::kAshPowerButtonPosition)));
   if (!position_info) {
     LOG(ERROR) << switches::kAshPowerButtonPosition << " flag has no value";
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc
index 76182b1..3e99e4e 100644
--- a/ash/system/status_area_widget_delegate.cc
+++ b/ash/system/status_area_widget_delegate.cc
@@ -68,11 +68,6 @@
 }
 
 bool StatusAreaWidgetDelegate::ShouldFocusOut(bool reverse) {
-  if (Shell::Get()->session_controller()->GetSessionState() ==
-      SessionState::ACTIVE) {
-    return false;
-  }
-
   views::View* focused_view = GetFocusManager()->GetFocusedView();
   return (reverse && focused_view == GetFirstFocusableChild()) ||
          (!reverse && focused_view == GetLastFocusableChild());
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 2f1e7bc..8e5d22d 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -11,6 +11,7 @@
 #include "ash/login/ui/lock_screen.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shelf/login_shelf_view.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_widget.h"
@@ -268,15 +269,23 @@
       shelf->GetStatusAreaWidget()->status_area_widget_delegate();
   if (!delegate || !delegate->ShouldFocusOut(reverse))
     return;
-  // Focus shelf widget when shift+tab is used and views-based shelf is shown.
-  if (reverse && ShelfWidget::IsUsingViewsShelf()) {
+
+  // At this point, we know we should focus out of the status widget.
+  // If we're not using a views-based shelf, delegate to system tray focus
+  // observers to decide where the focus goes next.
+  if (!ShelfWidget::IsUsingViewsShelf()) {
+    Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse);
+    return;
+  }
+
+  // If we are using a views-based shelf:
+  // * If we're going in reverse, always focus the shelf.
+  // * If we're going forward, focus the shelf in an active session, and let
+  //   the system tray focus observers focus the lock/login view otherwise.
+  if (reverse) {
     shelf->shelf_widget()->set_default_last_focusable_child(reverse);
     Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget());
   } else {
-    // Focus should leave the system tray if:
-    // 1) Tab is used, or
-    // 2) Shift+tab is used but views-based shelf is disabled. The shelf is not
-    // part of the system tray in this case.
     Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse);
   }
 }
diff --git a/ash/wm/pip/pip_window_resizer_unittest.cc b/ash/wm/pip/pip_window_resizer_unittest.cc
index afe33cc..3707086e 100644
--- a/ash/wm/pip/pip_window_resizer_unittest.cc
+++ b/ash/wm/pip/pip_window_resizer_unittest.cc
@@ -94,6 +94,7 @@
   }
 
  protected:
+  views::Widget* widget() { return widget_.get(); }
   aura::Window* window() { return window_; }
   FakeWindowState* test_state() { return test_state_; }
 
@@ -220,15 +221,8 @@
 
 TEST_F(PipWindowResizerTest, PipWindowCanBeSwipeDismissed) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 8, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 8, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Drag to the left.
@@ -236,20 +230,13 @@
 
   // Should be dismissed when the drag completes.
   resizer->CompleteDrag();
-  EXPECT_TRUE(widget->IsClosed());
+  EXPECT_TRUE(widget()->IsClosed());
 }
 
 TEST_F(PipWindowResizerTest, PipWindowPartiallySwipedDoesNotDismiss) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 8, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 8, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Drag to the left, but only a little bit.
@@ -257,113 +244,78 @@
 
   // Should not be dismissed when the drag completes.
   resizer->CompleteDrag();
-  EXPECT_FALSE(widget->IsClosed());
-  EXPECT_EQ(gfx::Rect(8, 8, 100, 100), test_state->last_bounds());
+  EXPECT_FALSE(widget()->IsClosed());
+  EXPECT_EQ(gfx::Rect(8, 8, 100, 100), test_state()->last_bounds());
 }
 
 TEST_F(PipWindowResizerTest, PipWindowInSwipeToDismissGestureLocksToAxis) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 8, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 8, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Drag to the left, but only a little bit, to start a swipe-to-dismiss.
   resizer->Drag(CalculateDragPoint(*resizer, -30, 0), 0);
-  EXPECT_EQ(gfx::Rect(-22, 8, 100, 100), test_state->last_bounds());
+  EXPECT_EQ(gfx::Rect(-22, 8, 100, 100), test_state()->last_bounds());
 
   // Now try to drag down, it should be locked to the horizontal axis.
   resizer->Drag(CalculateDragPoint(*resizer, -30, 30), 0);
-  EXPECT_EQ(gfx::Rect(-22, 8, 100, 100), test_state->last_bounds());
+  EXPECT_EQ(gfx::Rect(-22, 8, 100, 100), test_state()->last_bounds());
 }
 
 TEST_F(PipWindowResizerTest,
        PipWindowMovedAwayFromScreenEdgeNoLongerCanSwipeToDismiss) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 16, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 16, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Drag to the right and up a bit.
   resizer->Drag(CalculateDragPoint(*resizer, 30, -8), 0);
-  EXPECT_EQ(gfx::Rect(38, 8, 100, 100), test_state->last_bounds());
+  EXPECT_EQ(gfx::Rect(38, 8, 100, 100), test_state()->last_bounds());
 
   // Now try to drag to the left start a swipe-to-dismiss. It should stop
   // at the edge of the work area.
   resizer->Drag(CalculateDragPoint(*resizer, -30, -8), 0);
-  EXPECT_EQ(gfx::Rect(8, 8, 100, 100), test_state->last_bounds());
+  EXPECT_EQ(gfx::Rect(8, 8, 100, 100), test_state()->last_bounds());
 }
 
 TEST_F(PipWindowResizerTest, PipWindowAtCornerLocksToOneAxisOnSwipeToDismiss) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 8, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 8, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Try dragging up and to the left. It should lock onto the axis with the
   // largest displacement.
   resizer->Drag(CalculateDragPoint(*resizer, -30, -40), 0);
-  EXPECT_EQ(gfx::Rect(8, -32, 100, 100), test_state->last_bounds());
+  EXPECT_EQ(gfx::Rect(8, -32, 100, 100), test_state()->last_bounds());
 }
 
 TEST_F(
     PipWindowResizerTest,
     PipWindowMustBeDraggedMostlyInDirectionOfDismissToInitiateSwipeToDismiss) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 8, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 8, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Try a lot downward and a bit to the left. Swiping should not be initiated.
   resizer->Drag(CalculateDragPoint(*resizer, -30, 50), 0);
-  EXPECT_EQ(gfx::Rect(8, 58, 100, 100), test_state->last_bounds());
+  EXPECT_EQ(gfx::Rect(8, 58, 100, 100), test_state()->last_bounds());
 }
 
 TEST_F(PipWindowResizerTest,
        PipWindowDoesNotMoveUntilStatusOfSwipeToDismissGestureIsKnown) {
   UpdateWorkArea("400x400");
-  PreparePipWindow(gfx::Rect(200, 200, 100, 100));
-  auto widget = CreateWidgetForTest(gfx::Rect(8, 8, 100, 100));
-  auto* window = widget->GetNativeWindow();
-  FakeWindowState* test_state =
-      new FakeWindowState(mojom::WindowStateType::PIP);
-  wm::GetWindowState(window)->SetStateObject(
-      std::unique_ptr<wm::WindowState::State>(test_state));
-  std::unique_ptr<PipWindowResizer> resizer(
-      CreateResizerForTest(HTCAPTION, window));
+  PreparePipWindow(gfx::Rect(8, 8, 100, 100));
+  std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
   ASSERT_TRUE(resizer.get());
 
   // Move a small amount - this should not trigger any bounds change, since
   // we don't know whether a swipe will start or not.
   resizer->Drag(CalculateDragPoint(*resizer, -4, 0), 0);
-  EXPECT_TRUE(test_state->last_bounds().IsEmpty());
+  EXPECT_TRUE(test_state()->last_bounds().IsEmpty());
 }
 
 TEST_F(PipWindowResizerTest, PipWindowIsFlungToEdge) {
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
index a3832a0..38b3c060 100644
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -27,10 +27,10 @@
         Log.d("Foo", "Bar");
 
         List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-        assertEquals("Only one log should be written", 1, logs.size());
 
-        assertTrue("The origin of the log message (" + logs.get(0).msg + ") looks wrong.",
-                logs.get(0).msg.matches("\\[LogTest.java:\\d+\\].*"));
+        assertTrue("The origin of the log message (" + logs.get(logs.size() - 1).msg
+                        + ") looks wrong.",
+                logs.get(logs.size() - 1).msg.matches("\\[LogTest.java:\\d+\\].*"));
     }
 
     @Test
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
index 88b0837..8a7be32 100644
--- a/base/debug/task_annotator.cc
+++ b/base/debug/task_annotator.cc
@@ -35,14 +35,14 @@
 
 TaskAnnotator::~TaskAnnotator() = default;
 
-void TaskAnnotator::WillQueueTask(const char* queue_function,
+void TaskAnnotator::WillQueueTask(const char* trace_event_name,
                                   PendingTask* pending_task) {
-  if (queue_function) {
-    TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
-                           queue_function,
-                           TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)),
-                           TRACE_EVENT_FLAG_FLOW_OUT);
-  }
+  DCHECK(trace_event_name);
+  DCHECK(pending_task);
+  TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                         trace_event_name,
+                         TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)),
+                         TRACE_EVENT_FLAG_FLOW_OUT);
 
   DCHECK(!pending_task->task_backtrace[0])
       << "Task backtrace was already set, task posted twice??";
@@ -58,16 +58,16 @@
   }
 }
 
-void TaskAnnotator::RunTask(const char* queue_function,
+void TaskAnnotator::RunTask(const char* trace_event_name,
                             PendingTask* pending_task) {
+  DCHECK(trace_event_name);
+  DCHECK(pending_task);
+
   ScopedTaskRunActivity task_activity(*pending_task);
 
-  if (queue_function) {
-    TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
-                           queue_function,
-                           TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)),
-                           TRACE_EVENT_FLAG_FLOW_IN);
-  }
+  TRACE_EVENT_WITH_FLOW0(
+      TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), trace_event_name,
+      TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)), TRACE_EVENT_FLAG_FLOW_IN);
 
   // Before running the task, store the task backtrace with the chain of
   // PostTasks that resulted in this call and deliberately alias it to ensure
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
index fedca7d5..5ff5619 100644
--- a/base/debug/task_annotator.h
+++ b/base/debug/task_annotator.h
@@ -30,14 +30,11 @@
 
   // Called to indicate that a task is about to be queued to run in the future,
   // giving one last chance for this TaskAnnotator to add metadata to
-  // |pending_task| before it is moved into the queue. |queue_function| is used
-  // as the trace flow event name. |queue_function| can be null if the caller
-  // doesn't want trace flow events logged to toplevel.flow.
-  void WillQueueTask(const char* queue_function, PendingTask* pending_task);
+  // |pending_task| before it is moved into the queue.
+  void WillQueueTask(const char* trace_event_name, PendingTask* pending_task);
 
-  // Run a previously queued task. |queue_function| should match what was
-  // passed into |DidQueueTask| for this task.
-  void RunTask(const char* queue_function, PendingTask* pending_task);
+  // Run a previously queued task.
+  void RunTask(const char* trace_event_name, PendingTask* pending_task);
 
   // Creates a process-wide unique ID to represent this task in trace events.
   // This will be mangled with a Process ID hash to reduce the likelyhood of
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
index c8ecc21..03c8cff 100644
--- a/base/json/json_parser_unittest.cc
+++ b/base/json/json_parser_unittest.cc
@@ -226,7 +226,7 @@
   // Error strings should not be modified in case of success.
   std::string error_message;
   int error_code = 0;
-  std::unique_ptr<Value> root = JSONReader::ReadAndReturnError(
+  Optional<Value> root = JSONReader::ReadAndReturnError(
       "[42]", JSON_PARSE_RFC, &error_code, &error_message);
   EXPECT_TRUE(error_message.empty());
   EXPECT_EQ(0, error_code);
@@ -236,7 +236,7 @@
   // error here ----------------------------------^
   root = JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC, &error_code,
                                         &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
             error_message);
   EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
@@ -249,7 +249,7 @@
   // error here ----------------------^
   root = JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
             error_message);
   EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
@@ -257,7 +257,7 @@
   // Test each of the error conditions
   root = JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, &error_code,
                                         &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
       JSONReader::kUnexpectedDataAfterRoot), error_message);
   EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code);
@@ -269,55 +269,55 @@
   }
   root = JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 200, JSONReader::kTooMuchNesting),
             error_message);
   EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code);
 
   root = JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC, &error_code,
                                         &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
             error_message);
   EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
 
   root = JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2,
       JSONReader::kUnquotedDictionaryKey), error_message);
   EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code);
 
   root = JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
             error_message);
 
   root = JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC, &error_code,
                                         &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
             error_message);
   EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
 
   root = JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
             error_message);
   EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
 
   root = JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
             error_message);
   EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
 
   root = JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC,
                                         &error_code, &error_message);
-  EXPECT_FALSE(root.get());
+  EXPECT_FALSE(root);
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
             error_message);
   EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
@@ -336,9 +336,9 @@
       "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
   std::string error_message;
   int error_code = 0;
-  std::unique_ptr<Value> root = JSONReader::ReadAndReturnError(
+  Optional<Value> root = JSONReader::ReadAndReturnError(
       kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message);
-  EXPECT_TRUE(root.get()) << error_message;
+  EXPECT_TRUE(root) << error_message;
 }
 
 TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) {
@@ -410,24 +410,19 @@
     StringPiece input =
         MakeNotNullTerminatedInput(test_case.input, &input_owner);
 
-    std::unique_ptr<Value> result = JSONReader::Read(input);
-    if (test_case.parse_success) {
-      EXPECT_TRUE(result);
-    } else {
-      EXPECT_FALSE(result);
-    }
+    Optional<Value> result = JSONReader::Read(input);
+    EXPECT_EQ(test_case.parse_success, result.has_value());
 
     if (!result)
       continue;
 
-    double double_value = 0;
-    EXPECT_TRUE(result->GetAsDouble(&double_value));
-    EXPECT_EQ(test_case.value, double_value);
+    ASSERT_TRUE(result->is_double() || result->is_int());
+    EXPECT_EQ(test_case.value, result->GetDouble());
   }
 }
 
 TEST_F(JSONParserTest, UnterminatedInputs) {
-  const char* kCases[] = {
+  const char* const kCases[] = {
       // clang-format off
       "/",
       "//",
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index d05a956..73b0449 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -47,28 +47,25 @@
 JSONReader::~JSONReader() = default;
 
 // static
-std::unique_ptr<Value> JSONReader::Read(StringPiece json,
-                                        int options,
-                                        int max_depth) {
+Optional<Value> JSONReader::Read(StringPiece json, int options, int max_depth) {
   internal::JSONParser parser(options, max_depth);
-  Optional<Value> root = parser.Parse(json);
-  return root ? std::make_unique<Value>(std::move(*root)) : nullptr;
+  return parser.Parse(json);
 }
 
 std::unique_ptr<Value> JSONReader::ReadDeprecated(StringPiece json,
                                                   int options,
                                                   int max_depth) {
-  return Read(json, options, max_depth);
+  Optional<Value> value = Read(json, options, max_depth);
+  return value ? Value::ToUniquePtrValue(std::move(*value)) : nullptr;
 }
 
 // static
-std::unique_ptr<Value> JSONReader::ReadAndReturnError(
-    StringPiece json,
-    int options,
-    int* error_code_out,
-    std::string* error_msg_out,
-    int* error_line_out,
-    int* error_column_out) {
+Optional<Value> JSONReader::ReadAndReturnError(StringPiece json,
+                                               int options,
+                                               int* error_code_out,
+                                               std::string* error_msg_out,
+                                               int* error_line_out,
+                                               int* error_column_out) {
   internal::JSONParser parser(options);
   Optional<Value> root = parser.Parse(json);
   if (!root) {
@@ -82,7 +79,7 @@
       *error_column_out = parser.error_column();
   }
 
-  return root ? std::make_unique<Value>(std::move(*root)) : nullptr;
+  return root;
 }
 
 // static
@@ -93,8 +90,10 @@
     std::string* error_msg_out,
     int* error_line_out,
     int* error_column_out) {
-  return ReadAndReturnError(json, options, error_code_out, error_msg_out,
-                            error_line_out, error_column_out);
+  Optional<Value> value =
+      ReadAndReturnError(json, options, error_code_out, error_msg_out,
+                         error_line_out, error_column_out);
+  return value ? Value::ToUniquePtrValue(std::move(*value)) : nullptr;
 }
 
 // static
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index aa91034..1b6b5b2 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -32,6 +32,7 @@
 #include <string>
 
 #include "base/base_export.h"
+#include "base/optional.h"
 #include "base/strings/string_piece.h"
 
 namespace base {
@@ -91,14 +92,14 @@
 
   ~JSONReader();
 
-  // Work in progress. Please use ReadDeprecated() for now.
-  // https://crbug.com/925165
-  // A new version of Read() that returns a Value will be available as soon as
-  // all existing callers have been migrated to ReadDeprecated().
-  static std::unique_ptr<Value> Read(StringPiece json,
-                                     int options = JSON_PARSE_RFC,
-                                     int max_depth = kStackMaxDepth);
+  // Reads and parses |json|, returning a Value.
+  // If |json| is not a properly formed JSON string, returns a Value of type
+  // NONE.
+  static Optional<Value> Read(StringPiece json,
+                              int options = JSON_PARSE_RFC,
+                              int max_depth = kStackMaxDepth);
 
+  // Deprecated. Use the Read() method above.
   // Reads and parses |json|, returning a Value.
   // If |json| is not a properly formed JSON string, returns nullptr.
   // Wrap this in base::FooValue::From() to check the Value is of type Foo and
@@ -107,19 +108,18 @@
                                                int options = JSON_PARSE_RFC,
                                                int max_depth = kStackMaxDepth);
 
-  // Work in progress. Please use ReadAndReturnErrorDeprecated() for now.
-  // https://crbug.com/925165
-  // A new version of ReadAndReturnError() that returns a Value will be
-  // available as soon as all existing callers have been migrated to
-  // ReadAndReturnErrorDeprecated().
-  static std::unique_ptr<Value> ReadAndReturnError(
-      StringPiece json,
-      int options,  // JSONParserOptions
-      int* error_code_out,
-      std::string* error_msg_out,
-      int* error_line_out = nullptr,
-      int* error_column_out = nullptr);
+  // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
+  // are optional. If specified and nullptr is returned, they will be populated
+  // an error code and a formatted error message (including error location if
+  // appropriate). Otherwise, they will be unmodified.
+  static Optional<Value> ReadAndReturnError(StringPiece json,
+                                            int options,  // JSONParserOptions
+                                            int* error_code_out,
+                                            std::string* error_msg_out,
+                                            int* error_line_out = nullptr,
+                                            int* error_column_out = nullptr);
 
+  // Deprecated. Use the ReadAndReturnError() method above.
   // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
   // are optional. If specified and nullptr is returned, they will be populated
   // an error code and a formatted error message (including error location if
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index c74aa0b9..2f3ac73 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -248,34 +248,38 @@
 }
 
 TEST(JSONReaderTest, BasicArray) {
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader::Read("[true, false, null]"));
+  Optional<Value> list = JSONReader::Read("[true, false, null]");
   ASSERT_TRUE(list);
-  EXPECT_EQ(3U, list->GetSize());
+  ASSERT_TRUE(list->is_list());
+  EXPECT_EQ(3U, list->GetList().size());
 
   // Test with trailing comma.  Should be parsed the same as above.
-  std::unique_ptr<Value> root2 =
+  Optional<Value> root2 =
       JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS);
-  EXPECT_TRUE(list->Equals(root2.get()));
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*list, *root2);
 }
 
 TEST(JSONReaderTest, EmptyArray) {
-  std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read("[]"));
+  Optional<Value> list = JSONReader::Read("[]");
   ASSERT_TRUE(list);
-  EXPECT_EQ(0U, list->GetSize());
+  ASSERT_TRUE(list->is_list());
+  EXPECT_TRUE(list->GetList().empty());
 }
 
 TEST(JSONReaderTest, NestedArrays) {
-  std::unique_ptr<ListValue> list = ListValue::From(
-      JSONReader::Read("[[true], [], [false, [], [null]], null]"));
+  Optional<Value> list =
+      JSONReader::Read("[[true], [], [false, [], [null]], null]");
   ASSERT_TRUE(list);
-  EXPECT_EQ(4U, list->GetSize());
+  ASSERT_TRUE(list->is_list());
+  EXPECT_EQ(4U, list->GetList().size());
 
   // Lots of trailing commas.
-  std::unique_ptr<Value> root2 =
+  Optional<Value> root2 =
       JSONReader::Read("[[true], [], [false, [], [null, ]  , ], null,]",
                        JSON_ALLOW_TRAILING_COMMAS);
-  EXPECT_TRUE(list->Equals(root2.get()));
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*list, *root2);
 }
 
 TEST(JSONReaderTest, InvalidArrays) {
@@ -295,16 +299,14 @@
 
 TEST(JSONReaderTest, ArrayTrailingComma) {
   // Valid if we set |allow_trailing_comma| to true.
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS));
+  Optional<Value> list =
+      JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(list);
-  EXPECT_EQ(1U, list->GetSize());
-  Value* tmp_value = nullptr;
-  ASSERT_TRUE(list->Get(0, &tmp_value));
-  EXPECT_TRUE(tmp_value->is_bool());
-  bool bool_value = false;
-  EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value));
-  EXPECT_TRUE(bool_value);
+  ASSERT_TRUE(list->is_list());
+  ASSERT_EQ(1U, list->GetList().size());
+  const Value& value1 = list->GetList()[0];
+  ASSERT_TRUE(value1.is_bool());
+  EXPECT_TRUE(value1.GetBool());
 }
 
 TEST(JSONReaderTest, ArrayTrailingCommaNoEmptyElements) {
@@ -317,30 +319,33 @@
 }
 
 TEST(JSONReaderTest, EmptyDictionary) {
-  std::unique_ptr<DictionaryValue> dict_val =
-      DictionaryValue::From(JSONReader::Read("{}"));
+  Optional<Value> dict_val = JSONReader::Read("{}");
   ASSERT_TRUE(dict_val);
+  ASSERT_TRUE(dict_val->is_dict());
 }
 
 TEST(JSONReaderTest, CompleteDictionary) {
-  auto dict_val = DictionaryValue::From(JSONReader::Read(
-      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
+  Optional<Value> dict_val = JSONReader::Read(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }");
   ASSERT_TRUE(dict_val);
-  double double_val = 0.0;
-  EXPECT_TRUE(dict_val->GetDouble("number", &double_val));
-  EXPECT_DOUBLE_EQ(9.87654321, double_val);
-  Value* null_val = nullptr;
-  ASSERT_TRUE(dict_val->Get("null", &null_val));
+  ASSERT_TRUE(dict_val->is_dict());
+  auto double_val = dict_val->FindDoubleKey("number");
+  ASSERT_TRUE(double_val);
+  EXPECT_DOUBLE_EQ(9.87654321, *double_val);
+  const Value* null_val =
+      dict_val->FindKeyOfType("null", base::Value::Type::NONE);
+  ASSERT_TRUE(null_val);
   EXPECT_TRUE(null_val->is_none());
-  std::string str_val;
-  EXPECT_TRUE(dict_val->GetString("S", &str_val));
-  EXPECT_EQ("str", str_val);
+  const std::string* str_val = dict_val->FindStringKey("S");
+  ASSERT_TRUE(str_val);
+  EXPECT_EQ("str", *str_val);
 
-  std::unique_ptr<Value> root2 = JSONReader::Read(
+  Optional<Value> root2 = JSONReader::Read(
       "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
       JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  ASSERT_TRUE(root2->is_dict());
+  EXPECT_EQ(*dict_val, *root2);
 
   // Test newline equivalence.
   root2 = JSONReader::Read(
@@ -351,7 +356,8 @@
       "}\n",
       JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  ASSERT_TRUE(root2->is_dict());
+  EXPECT_EQ(*dict_val, *root2);
 
   root2 = JSONReader::Read(
       "{\r\n"
@@ -361,55 +367,64 @@
       "}\r\n",
       JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  ASSERT_TRUE(root2->is_dict());
+  EXPECT_EQ(*dict_val, *root2);
 }
 
 TEST(JSONReaderTest, NestedDictionaries) {
-  std::unique_ptr<DictionaryValue> dict_val =
-      DictionaryValue::From(JSONReader::Read(
-          "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"));
+  Optional<Value> dict_val = JSONReader::Read(
+      "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}");
   ASSERT_TRUE(dict_val);
-  DictionaryValue* inner_dict = nullptr;
-  ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict));
-  ListValue* inner_array = nullptr;
-  ASSERT_TRUE(inner_dict->GetList("array", &inner_array));
-  EXPECT_EQ(1U, inner_array->GetSize());
-  bool bool_value = true;
-  EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value));
-  EXPECT_FALSE(bool_value);
-  inner_dict = nullptr;
-  EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
+  ASSERT_TRUE(dict_val->is_dict());
+  const Value* inner_dict =
+      dict_val->FindKeyOfType("inner", base::Value::Type::DICTIONARY);
+  ASSERT_TRUE(inner_dict);
+  const Value* inner_array =
+      inner_dict->FindKeyOfType("array", base::Value::Type::LIST);
+  ASSERT_TRUE(inner_array);
+  EXPECT_EQ(1U, inner_array->GetList().size());
+  auto bool_value = dict_val->FindBoolKey("false");
+  ASSERT_TRUE(bool_value);
+  EXPECT_FALSE(*bool_value);
+  inner_dict = dict_val->FindKeyOfType("d", base::Value::Type::DICTIONARY);
+  EXPECT_TRUE(inner_dict);
 
-  std::unique_ptr<Value> root2 = JSONReader::Read(
+  Optional<Value> root2 = JSONReader::Read(
       "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
       JSON_ALLOW_TRAILING_COMMAS);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*dict_val, *root2);
 }
 
 TEST(JSONReaderTest, DictionaryKeysWithPeriods) {
-  std::unique_ptr<DictionaryValue> dict_val = DictionaryValue::From(
-      JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"));
+  Optional<Value> dict_val =
+      JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}");
   ASSERT_TRUE(dict_val);
-  int integer_value = 0;
-  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
-  EXPECT_EQ(3, integer_value);
-  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value));
-  EXPECT_EQ(2, integer_value);
-  DictionaryValue* inner_dict = nullptr;
-  ASSERT_TRUE(
-      dict_val->GetDictionaryWithoutPathExpansion("d.e.f", &inner_dict));
-  EXPECT_EQ(1U, inner_dict->size());
-  EXPECT_TRUE(
-      inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", &integer_value));
-  EXPECT_EQ(1, integer_value);
+  ASSERT_TRUE(dict_val->is_dict());
 
-  dict_val =
-      DictionaryValue::From(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}"));
-  ASSERT_TRUE(dict_val);
-  EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value));
-  EXPECT_EQ(2, integer_value);
-  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
-  EXPECT_EQ(1, integer_value);
+  auto integer_value = dict_val->FindIntKey("a.b");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(3, *integer_value);
+  integer_value = dict_val->FindIntKey("c");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(2, *integer_value);
+  const Value* inner_dict =
+      dict_val->FindKeyOfType("d.e.f", base::Value::Type::DICTIONARY);
+  ASSERT_TRUE(inner_dict);
+  EXPECT_EQ(1U, inner_dict->DictSize());
+  integer_value = inner_dict->FindIntKey("g.h.i.j");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(1, *integer_value);
+
+  dict_val = JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}");
+  ASSERT_TRUE(dict_val->is_dict());
+  const Value* integer_path_value =
+      dict_val->FindPathOfType({"a", "b"}, base::Value::Type::INTEGER);
+  ASSERT_TRUE(integer_path_value);
+  EXPECT_EQ(2, integer_path_value->GetInt());
+  integer_value = dict_val->FindIntKey("a.b");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(1, *integer_value);
 }
 
 TEST(JSONReaderTest, InvalidDictionaries) {
@@ -452,9 +467,10 @@
   for (int i = 0; i < 5000; ++i)
     not_evil.append("[],");
   not_evil.append("[]]");
-  std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read(not_evil));
+  Optional<Value> list = JSONReader::Read(not_evil);
   ASSERT_TRUE(list);
-  EXPECT_EQ(5001U, list->GetSize());
+  ASSERT_TRUE(list->is_list());
+  EXPECT_EQ(5001U, list->GetList().size());
 }
 
 TEST(JSONReaderTest, UTF8Input) {
@@ -522,27 +538,24 @@
 }
 
 TEST(JSONReaderTest, LiteralRoots) {
-  std::unique_ptr<Value> root = JSONReader::Read("null");
+  Optional<Value> root = JSONReader::Read("null");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
 
   root = JSONReader::Read("true");
   ASSERT_TRUE(root);
-  bool bool_value;
-  EXPECT_TRUE(root->GetAsBoolean(&bool_value));
-  EXPECT_TRUE(bool_value);
+  ASSERT_TRUE(root->is_bool());
+  EXPECT_TRUE(root->GetBool());
 
   root = JSONReader::Read("10");
   ASSERT_TRUE(root);
-  int integer_value;
-  EXPECT_TRUE(root->GetAsInteger(&integer_value));
-  EXPECT_EQ(10, integer_value);
+  ASSERT_TRUE(root->is_int());
+  EXPECT_EQ(10, root->GetInt());
 
   root = JSONReader::Read("\"root\"");
   ASSERT_TRUE(root);
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ("root", str_val);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ("root", root->GetString());
 }
 
 TEST(JSONReaderTest, ReadFromFile) {
@@ -571,7 +584,7 @@
   std::unique_ptr<Value> list_value_1;
 
   {
-    std::unique_ptr<Value> root = JSONReader::Read(
+    std::unique_ptr<Value> root = JSONReader::ReadDeprecated(
         "{"
         "  \"test\": {"
         "    \"foo\": true,"
@@ -655,11 +668,8 @@
 
 TEST(JSONReaderTest, MaxNesting) {
   std::string json(R"({"outer": { "inner": {"foo": true}}})");
-  std::unique_ptr<Value> root;
-  root = JSONReader::Read(json, JSON_PARSE_RFC, 3);
-  ASSERT_FALSE(root);
-  root = JSONReader::Read(json, JSON_PARSE_RFC, 4);
-  ASSERT_TRUE(root);
+  EXPECT_FALSE(JSONReader::Read(json, JSON_PARSE_RFC, 3));
+  EXPECT_TRUE(JSONReader::Read(json, JSON_PARSE_RFC, 4));
 }
 
 }  // namespace base
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
index f9c45a40..f979090 100644
--- a/base/json/json_string_value_serializer.cc
+++ b/base/json/json_string_value_serializer.cc
@@ -50,6 +50,6 @@
 std::unique_ptr<Value> JSONStringValueDeserializer::Deserialize(
     int* error_code,
     std::string* error_str) {
-  return base::JSONReader::ReadAndReturnError(json_string_, options_,
-                                              error_code, error_str);
+  return base::JSONReader::ReadAndReturnErrorDeprecated(json_string_, options_,
+                                                        error_code, error_str);
 }
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc
index 0946820..72ed38ac 100644
--- a/base/json/json_value_converter_unittest.cc
+++ b/base/json/json_value_converter_unittest.cc
@@ -106,10 +106,11 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  Optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+  EXPECT_TRUE(converter.Convert(*value, &message));
 
   EXPECT_EQ(1, message.foo);
   EXPECT_EQ("bar", message.bar);
@@ -148,10 +149,11 @@
       "  }]\n"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  Optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   NestedMessage message;
   base::JSONValueConverter<NestedMessage> converter;
-  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+  EXPECT_TRUE(converter.Convert(*value, &message));
 
   EXPECT_EQ(1.0, message.foo);
   EXPECT_EQ(1, message.child.foo);
@@ -185,15 +187,16 @@
   const char normal_data[] =
       "{\n"
       "  \"foo\": 1,\n"
-      "  \"bar\": 2,\n" // "bar" is an integer here.
+      "  \"bar\": 2,\n"  // "bar" is an integer here.
       "  \"baz\": true,\n"
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  Optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  EXPECT_FALSE(converter.Convert(*value, &message));
   // Do not check the values below.  |message| may be modified during
   // Convert() even it fails.
 }
@@ -206,11 +209,12 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  Optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
   // Convert() still succeeds even if the input doesn't have "bar" field.
-  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+  EXPECT_TRUE(converter.Convert(*value, &message));
 
   EXPECT_EQ(1, message.foo);
   EXPECT_TRUE(message.baz);
@@ -229,10 +233,11 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  Optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  EXPECT_FALSE(converter.Convert(*value, &message));
   // No check the values as mentioned above.
 }
 
@@ -246,10 +251,11 @@
       "  \"ints\": [1, false]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  Optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  EXPECT_FALSE(converter.Convert(*value, &message));
   // No check the values as mentioned above.
 }
 
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
index d25f950..9c4e8bb9 100644
--- a/base/json/json_value_serializer_unittest.cc
+++ b/base/json/json_value_serializer_unittest.cc
@@ -76,14 +76,13 @@
 }
 
 void ValidateJsonList(const std::string& json) {
-  std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read(json));
+  Optional<Value> list = JSONReader::Read(json);
   ASSERT_TRUE(list);
-  ASSERT_EQ(1U, list->GetSize());
-  Value* elt = nullptr;
-  ASSERT_TRUE(list->Get(0, &elt));
-  int value = 0;
-  ASSERT_TRUE(elt && elt->GetAsInteger(&value));
-  ASSERT_EQ(1, value);
+  ASSERT_TRUE(list->is_list());
+  ASSERT_EQ(1U, list->GetList().size());
+  const Value& elt = list->GetList()[0];
+  ASSERT_TRUE(elt.is_int());
+  ASSERT_EQ(1, elt.GetInt());
 }
 
 // Test proper JSON deserialization from string is working.
@@ -378,15 +377,13 @@
   ValidateJsonList("[ 1 //// ,2\r\n ]");
 
   // It's ok to have a comment in a string.
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader::Read("[\"// ok\\n /* foo */ \"]"));
+  Optional<Value> list = JSONReader::Read("[\"// ok\\n /* foo */ \"]");
   ASSERT_TRUE(list);
-  ASSERT_EQ(1U, list->GetSize());
-  Value* elt = nullptr;
-  ASSERT_TRUE(list->Get(0, &elt));
-  std::string value;
-  ASSERT_TRUE(elt && elt->GetAsString(&value));
-  ASSERT_EQ("// ok\n /* foo */ ", value);
+  ASSERT_TRUE(list->is_list());
+  ASSERT_EQ(1U, list->GetList().size());
+  const Value& elt = list->GetList()[0];
+  ASSERT_TRUE(elt.is_string());
+  ASSERT_EQ("// ok\n /* foo */ ", elt.GetString());
 
   // You can't nest comments.
   ASSERT_FALSE(JSONReader::Read("/* /* inner */ outer */ [ 1 ]"));
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index 01fea05f..f54f414 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -359,48 +359,49 @@
   std::string json(StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_FULL));
 
   // Check for valid JSON.
-  std::unique_ptr<Value> root = JSONReader::Read(json);
-  ASSERT_TRUE(root.get());
-
-  DictionaryValue* root_dict = nullptr;
-  ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+  Optional<Value> root = JSONReader::Read(json);
+  ASSERT_TRUE(root);
+  ASSERT_TRUE(root->is_dict());
 
   // No query should be set.
-  ASSERT_FALSE(root_dict->HasKey("query"));
+  ASSERT_FALSE(root->FindKey("query"));
 
-  ListValue* histogram_list = nullptr;
-  ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
-  ASSERT_EQ(2u, histogram_list->GetSize());
+  const Value* histogram_list =
+      root->FindKeyOfType("histograms", base::Value::Type::LIST);
+
+  ASSERT_TRUE(histogram_list);
+  ASSERT_EQ(2u, histogram_list->GetList().size());
 
   // Examine the first histogram.
-  DictionaryValue* histogram_dict = nullptr;
-  ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
+  const Value& histogram_dict = histogram_list->GetList()[0];
+  ASSERT_TRUE(histogram_dict.is_dict());
 
-  int sample_count;
-  ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count));
-  EXPECT_EQ(2, sample_count);
+  auto sample_count = histogram_dict.FindIntKey("count");
+  ASSERT_TRUE(sample_count);
+  EXPECT_EQ(2, *sample_count);
 
-  ListValue* buckets_list = nullptr;
-  ASSERT_TRUE(histogram_dict->GetList("buckets", &buckets_list));
+  const Value* buckets_list =
+      histogram_dict.FindKeyOfType("buckets", base::Value::Type::LIST);
+  ASSERT_TRUE(buckets_list);
   EXPECT_EQ(2u, buckets_list->GetList().size());
 
   // Check the serialized JSON with a different verbosity level.
   json = StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_OMIT_BUCKETS);
   root = JSONReader::Read(json);
-  ASSERT_TRUE(root.get());
-  root_dict = nullptr;
-  ASSERT_TRUE(root->GetAsDictionary(&root_dict));
-  histogram_list = nullptr;
-  ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
-  ASSERT_EQ(2u, histogram_list->GetSize());
-  histogram_dict = nullptr;
-  ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
-  sample_count = 0;
-  ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count));
-  EXPECT_EQ(2, sample_count);
-  buckets_list = nullptr;
+  ASSERT_TRUE(root);
+  ASSERT_TRUE(root->is_dict());
+  histogram_list = root->FindKeyOfType("histograms", base::Value::Type::LIST);
+  ASSERT_TRUE(histogram_list);
+  ASSERT_EQ(2u, histogram_list->GetList().size());
+  const Value& histogram_dict2 = histogram_list->GetList()[0];
+  ASSERT_TRUE(histogram_dict2.is_dict());
+  sample_count = histogram_dict2.FindIntKey("count");
+  ASSERT_TRUE(sample_count);
+  EXPECT_EQ(2, *sample_count);
+  buckets_list =
+      histogram_dict2.FindKeyOfType("buckets", base::Value::Type::LIST);
   // Bucket information should be omitted.
-  ASSERT_FALSE(histogram_dict->GetList("buckets", &buckets_list));
+  ASSERT_FALSE(buckets_list);
 }
 
 TEST_P(StatisticsRecorderTest, IterationTest) {
@@ -638,7 +639,8 @@
 
 class TestHistogramProvider : public StatisticsRecorder::HistogramProvider {
  public:
-  TestHistogramProvider(std::unique_ptr<PersistentHistogramAllocator> allocator)
+  explicit TestHistogramProvider(
+      std::unique_ptr<PersistentHistogramAllocator> allocator)
       : allocator_(std::move(allocator)), weak_factory_(this) {
     StatisticsRecorder::RegisterHistogramProvider(weak_factory_.GetWeakPtr());
   }
diff --git a/base/sampling_heap_profiler/OWNERS b/base/sampling_heap_profiler/OWNERS
index 87c96616..10b970d 100644
--- a/base/sampling_heap_profiler/OWNERS
+++ b/base/sampling_heap_profiler/OWNERS
@@ -1 +1,2 @@
 alph@chromium.org
+per-file module_cache*=wittman@chromium.org
diff --git a/base/task/task_scheduler/task_tracker.cc b/base/task/task_scheduler/task_tracker.cc
index 80ca168..43b20e5 100644
--- a/base/task/task_scheduler/task_tracker.cc
+++ b/base/task/task_scheduler/task_tracker.cc
@@ -72,14 +72,6 @@
   out->append(tmp);
 }
 
-// These name conveys that a Task is posted to/run by the task scheduler without
-// revealing its implementation details.
-constexpr char kQueueFunctionName[] = "TaskScheduler PostTask";
-constexpr char kRunFunctionName[] = "TaskScheduler RunTask";
-
-constexpr char kTaskSchedulerFlowTracingCategory[] =
-    TRACE_DISABLED_BY_DEFAULT("task_scheduler.flow");
-
 // Constructs a histogram to track latency which is logging to
 // "TaskScheduler.{histogram_name}.{histogram_label}.{task_type_suffix}".
 HistogramBase* GetLatencyHistogram(StringPiece histogram_name,
@@ -443,14 +435,7 @@
   if (task->delayed_run_time.is_null())
     subtle::NoBarrier_AtomicIncrement(&num_incomplete_undelayed_tasks_, 1);
 
-  {
-    TRACE_EVENT_WITH_FLOW0(
-        kTaskSchedulerFlowTracingCategory, kQueueFunctionName,
-        TRACE_ID_MANGLE(task_annotator_.GetTaskTraceID(*task)),
-        TRACE_EVENT_FLAG_FLOW_OUT);
-  }
-
-  task_annotator_.WillQueueTask(nullptr, task);
+  task_annotator_.WillQueueTask("TaskScheduler_PostTask", task);
 
   return true;
 }
@@ -623,7 +608,7 @@
     }
 
     if (can_run_task) {
-      TRACE_TASK_EXECUTION(kRunFunctionName, task);
+      TRACE_TASK_EXECUTION("TaskScheduler_RunTask", task);
 
       const char* const execution_mode =
           task.single_thread_task_runner_ref
@@ -633,19 +618,10 @@
       // TODO(gab): In a better world this would be tacked on as an extra arg
       // to the trace event generated above. This is not possible however until
       // http://crbug.com/652692 is resolved.
-      TRACE_EVENT1("task_scheduler", "TaskTracker::RunTask", "task_info",
+      TRACE_EVENT1("task_scheduler", "TaskScheduler_TaskInfo", "task_info",
                    std::make_unique<TaskTracingInfo>(traits, execution_mode,
                                                      sequence_token));
 
-      {
-        // Put this in its own scope so it preceeds rather than overlaps with
-        // RunTask() in the trace view.
-        TRACE_EVENT_WITH_FLOW0(
-            kTaskSchedulerFlowTracingCategory, kQueueFunctionName,
-            TRACE_ID_MANGLE(task_annotator_.GetTaskTraceID(task)),
-            TRACE_EVENT_FLAG_FLOW_IN);
-      }
-
       RunTaskWithShutdownBehavior(traits.shutdown_behavior(), &task);
     }
 
@@ -935,19 +911,19 @@
 
 NOINLINE void TaskTracker::RunContinueOnShutdown(Task* task) {
   const int line_number = __LINE__;
-  task_annotator_.RunTask(nullptr, task);
+  task_annotator_.RunTask("TaskScheduler_RunTask_ContinueOnShutdown", task);
   base::debug::Alias(&line_number);
 }
 
 NOINLINE void TaskTracker::RunSkipOnShutdown(Task* task) {
   const int line_number = __LINE__;
-  task_annotator_.RunTask(nullptr, task);
+  task_annotator_.RunTask("TaskScheduler_RunTask_SkipOnShutdown", task);
   base::debug::Alias(&line_number);
 }
 
 NOINLINE void TaskTracker::RunBlockShutdown(Task* task) {
   const int line_number = __LINE__;
-  task_annotator_.RunTask(nullptr, task);
+  task_annotator_.RunTask("TaskScheduler_RunTask_BlockShutdown", task);
   base::debug::Alias(&line_number);
 }
 
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index f91a652..f369754e 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -723,21 +723,16 @@
 
 bool ParseEventsFromJson(const std::string& json,
                          std::vector<TraceEvent>* output) {
-  std::unique_ptr<base::Value> root = base::JSONReader::Read(json);
+  base::Optional<base::Value> root = base::JSONReader::Read(json);
 
-  base::ListValue* root_list = nullptr;
-  if (!root.get() || !root->GetAsList(&root_list))
+  if (!root || !root->is_list())
     return false;
 
-  for (size_t i = 0; i < root_list->GetSize(); ++i) {
-    base::Value* item = nullptr;
-    if (root_list->Get(i, &item)) {
-      TraceEvent event;
-      if (event.SetFromJSON(item))
-        output->push_back(std::move(event));
-      else
-        return false;
-    }
+  for (const auto& item : root->GetList()) {
+    TraceEvent event;
+    if (!event.SetFromJSON(&item))
+      return false;
+    output->push_back(std::move(event));
   }
 
   return true;
diff --git a/base/test/values_test_util.cc b/base/test/values_test_util.cc
index c901753..9ad1597 100644
--- a/base/test/values_test_util.cc
+++ b/base/test/values_test_util.cc
@@ -80,7 +80,7 @@
   // options for JSON data that is assumed to be generated by the code under
   // test rather than written by hand as part of a unit test.
   std::string error_msg;
-  std::unique_ptr<Value> value = base::JSONReader::ReadAndReturnError(
+  Optional<Value> value = base::JSONReader::ReadAndReturnError(
       json, base::JSON_PARSE_RFC, nullptr, &error_msg);
   if (!value) {
     *listener << "Failed to parse \"" << json << "\": " << error_msg;
@@ -105,8 +105,9 @@
 
 std::unique_ptr<Value> ParseJson(base::StringPiece json) {
   std::string error_msg;
-  std::unique_ptr<Value> result = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error_msg);
+  std::unique_ptr<Value> result =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error_msg);
   if (!result) {
     ADD_FAILURE() << "Failed to parse \"" << json << "\": " << error_msg;
     result = std::make_unique<Value>();
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
index 72adf46b..8f4f894f 100644
--- a/base/trace_event/builtin_categories.h
+++ b/base/trace_event/builtin_categories.h
@@ -194,7 +194,6 @@
   X(TRACE_DISABLED_BY_DEFAULT("SyncFileSystem"))                         \
   X(TRACE_DISABLED_BY_DEFAULT("system_stats"))                           \
   X(TRACE_DISABLED_BY_DEFAULT("task_scheduler_diagnostics"))             \
-  X(TRACE_DISABLED_BY_DEFAULT("task_scheduler.flow"))                    \
   X(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"))                          \
   X(TRACE_DISABLED_BY_DEFAULT("v8.compile"))                             \
   X(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"))                        \
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
index 6b208d4..6c9dc03 100644
--- a/base/trace_event/trace_config.cc
+++ b/base/trace_event/trace_config.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <utility>
 
 #include "base/json/json_reader.h"
@@ -408,7 +409,7 @@
 }
 
 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
-  auto dict = DictionaryValue::From(JSONReader::Read(config_string));
+  auto dict = DictionaryValue::From(JSONReader::ReadDeprecated(config_string));
   if (dict)
     InitializeFromConfigDict(*dict);
   else
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
index 5cfd4e5..17932d80 100644
--- a/base/trace_event/trace_config_unittest.cc
+++ b/base/trace_event/trace_config_unittest.cc
@@ -342,7 +342,7 @@
   EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
 
   std::unique_ptr<Value> default_value(
-      JSONReader::Read(kDefaultTraceConfigString));
+      JSONReader::ReadDeprecated(kDefaultTraceConfigString));
   DCHECK(default_value);
   const DictionaryValue* default_dict = nullptr;
   bool is_dict = default_value->GetAsDictionary(&default_dict);
@@ -355,7 +355,7 @@
   EXPECT_STREQ("", default_tc.ToCategoryFilterString().c_str());
 
   std::unique_ptr<Value> custom_value(
-      JSONReader::Read(kCustomTraceConfigString));
+      JSONReader::ReadDeprecated(kCustomTraceConfigString));
   DCHECK(custom_value);
   const DictionaryValue* custom_dict = nullptr;
   is_dict = custom_value->GetAsDictionary(&custom_dict);
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 47272e1..5c24ab1c 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -33,7 +33,6 @@
 #include "base/trace_event/event_name_filter.h"
 #include "base/trace_event/heap_profiler_event_filter.h"
 #include "base/trace_event/trace_buffer.h"
-#include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_filter.h"
 #include "base/trace_event/trace_event_filter_test_utils.h"
 #include "base/values.h"
@@ -193,8 +192,8 @@
   trace_buffer_.AddFragment(events_str->data());
   trace_buffer_.Finish();
 
-  std::unique_ptr<Value> root =
-      base::JSONReader::Read(json_output_.json_output, JSON_PARSE_RFC);
+  std::unique_ptr<Value> root = base::JSONReader::ReadDeprecated(
+      json_output_.json_output, JSON_PARSE_RFC);
 
   if (!root.get()) {
     LOG(ERROR) << json_output_.json_output;
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 0b18059..be9c879 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -242,6 +242,7 @@
     ":clang_revision",
     ":compiler_cpu_abi",
     ":compiler_codegen",
+    ":compiler_deterministic",
   ]
 
   # In general, Windows is totally different, but all the other builds share
@@ -294,26 +295,6 @@
     }
   }
 
-  # Eliminate build metadata (__DATE__, __TIME__ and __TIMESTAMP__) for
-  # deterministic build.  See https://crbug.com/314403
-  if (!is_official_build) {
-    if (is_win && !is_clang) {
-      cflags += [
-        "/wd4117",  # Trying to define or undefine a predefined macro.
-        "/D__DATE__=",
-        "/D__TIME__=",
-        "/D__TIMESTAMP__=",
-      ]
-    } else {
-      cflags += [
-        "-Wno-builtin-macro-redefined",
-        "-D__DATE__=",
-        "-D__TIME__=",
-        "-D__TIMESTAMP__=",
-      ]
-    }
-  }
-
   if (is_clang && is_debug) {
     # Allow comparing the address of references and 'this' against 0
     # in debug builds. Technically, these can never be null in
@@ -525,45 +506,6 @@
     cflags += [ "-fdiagnostics-absolute-paths" ]
   }
 
-  # Makes builds independent of absolute file path.
-  if (symbol_level != 0 && is_clang && strip_absolute_paths_from_debug_symbols) {
-    # If debug option is given, clang includes $cwd in debug info by default.
-    # For such build, this flag generates reproducible obj files even we use
-    # different build directory like "out/feature_a" and "out/feature_b" if
-    # we build same files with same compile flag.
-    # Other paths are already given in relative, no need to normalize them.
-    cflags += [
-      "-Xclang",
-      "-fdebug-compilation-dir",
-      "-Xclang",
-      ".",
-    ]
-
-    if (is_win && use_lld) {
-      if (symbol_level == 2 || (is_clang && using_sanitizer)) {
-        # Absolutize source file path for PDB. Pass the real build directory
-        # if the pdb contains source-level debug information.
-        ldflags += [ "/PDBSourcePath:" + rebase_path(root_build_dir) ]
-      } else {
-        # On Windows, (non-sanitizier) symbol_level 1 builds don't contain
-        # debug information in obj files; the linker just creates enough
-        # debug info at link time to produce symbolized stacks (without line
-        # numbers). In that case, there's no downside in using a fake fixed
-        # base directory for paths in the pdb. This makes the pdb output
-        # fully deterministic and independent of the build directory.
-        assert(symbol_level == 1 && !(is_clang && using_sanitizer))
-        ldflags += [ "/PDBSourcePath:o:\fake\prefix" ]
-      }
-    }
-  }
-
-  # Tells the compiler not to use absolute paths when passing the default
-  # paths to the tools it invokes. We don't want this because we don't
-  # really need it and it can mess up the goma cache entries.
-  if (is_clang && !is_nacl) {
-    cflags += [ "-no-canonical-prefixes" ]
-  }
-
   # C11/C++11 compiler flags setup.
   # ---------------------------
   if (is_linux || is_android || (is_nacl && is_clang) || current_os == "aix") {
@@ -1134,6 +1076,77 @@
   asmflags = cflags
 }
 
+# This provides options that make the build deterministic, so that the same
+# revision produces the same output, independent of the name of the build
+# directory and of the computer the build is done on.
+# The relative path from build dir to source dir makes it into the build
+# outputs, so it's recommended that you use a build dir two levels deep
+# (e.g. "out/Release") so that you get the same "../.." path as all the bots
+# in your build outputs.
+config("compiler_deterministic") {
+  cflags = []
+  ldflags = []
+
+  # Eliminate build metadata (__DATE__, __TIME__ and __TIMESTAMP__) for
+  # deterministic build.  See https://crbug.com/314403
+  if (!is_official_build) {
+    if (is_win && !is_clang) {
+      cflags += [
+        "/wd4117",  # Trying to define or undefine a predefined macro.
+        "/D__DATE__=",
+        "/D__TIME__=",
+        "/D__TIMESTAMP__=",
+      ]
+    } else {
+      cflags += [
+        "-Wno-builtin-macro-redefined",
+        "-D__DATE__=",
+        "-D__TIME__=",
+        "-D__TIMESTAMP__=",
+      ]
+    }
+  }
+
+  # Makes builds independent of absolute file path.
+  if (symbol_level != 0 && is_clang && strip_absolute_paths_from_debug_symbols) {
+    # If debug option is given, clang includes $cwd in debug info by default.
+    # For such build, this flag generates reproducible obj files even we use
+    # different build directory like "out/feature_a" and "out/feature_b" if
+    # we build same files with same compile flag.
+    # Other paths are already given in relative, no need to normalize them.
+    cflags += [
+      "-Xclang",
+      "-fdebug-compilation-dir",
+      "-Xclang",
+      ".",
+    ]
+
+    if (is_win && use_lld) {
+      if (symbol_level == 2 || (is_clang && using_sanitizer)) {
+        # Absolutize source file path for PDB. Pass the real build directory
+        # if the pdb contains source-level debug information.
+        ldflags += [ "/PDBSourcePath:" + rebase_path(root_build_dir) ]
+      } else {
+        # On Windows, (non-sanitizier) symbol_level 1 builds don't contain
+        # debug information in obj files; the linker just creates enough
+        # debug info at link time to produce symbolized stacks (without line
+        # numbers). In that case, there's no downside in using a fake fixed
+        # base directory for paths in the pdb. This makes the pdb output
+        # fully deterministic and independent of the build directory.
+        assert(symbol_level == 1 && !(is_clang && using_sanitizer))
+        ldflags += [ "/PDBSourcePath:o:\fake\prefix" ]
+      }
+    }
+  }
+
+  # Tells the compiler not to use absolute paths when passing the default
+  # paths to the tools it invokes. We don't want this because we don't
+  # really need it and it can mess up the goma cache entries.
+  if (is_clang && !is_nacl) {
+    cflags += [ "-no-canonical-prefixes" ]
+  }
+}
+
 config("clang_revision") {
   if (is_clang && clang_base_path == default_clang_base_path) {
     update_args = [
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 93e58674..b71cdd5 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-6c3c8c98f7b3184140d110083e0d32d2f6405aae
\ No newline at end of file
+1fc0baed845689e66b8d5ef29fd5dfa2faff7b93
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index c826aa4..ea84c45 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8c767248ffb52088b77fb5301eb72367ec7c9871
\ No newline at end of file
+dd5081f6b891bef3ab5e36e7005a4f8be10ff7f2
\ No newline at end of file
diff --git a/buildtools/OWNERS b/buildtools/OWNERS
new file mode 100644
index 0000000..e8022b6
--- /dev/null
+++ b/buildtools/OWNERS
@@ -0,0 +1,3 @@
+dpranke@chromium.org
+thakis@chromium.org
+thomasanderson@chromium.org
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index fcdef58..7d07aa39 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -158,13 +158,10 @@
       visible_layer_rect(), layer_to_content_scale_x, layer_to_content_scale_y);
   scaled_visible_layer_rect.Intersect(gfx::Rect(scaled_bounds));
 
-  EffectNode* effect_node = GetEffectTree().Node(effect_tree_index_);
   state->SetAll(scaled_draw_transform, gfx::Rect(scaled_bounds),
                 scaled_visible_layer_rect, draw_properties().clip_rect,
                 draw_properties().is_clipped, contents_opaque,
-                draw_properties().opacity,
-                effect_node->has_render_surface ? SkBlendMode::kSrcOver
-                                                : effect_node->blend_mode,
+                draw_properties().opacity, SkBlendMode::kSrcOver,
                 GetSortingContextId());
 }
 
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 72c00d9..0050c722 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -116,13 +116,6 @@
   RunPixelTest(test_type_, content_root, expected_bitmap);
 }
 
-void LayerTreeHostPixelResourceTest::RunPixelResourceTestWithLayerList(
-    scoped_refptr<Layer> root_layer,
-    base::FilePath file_name,
-    PropertyTrees* property_trees) {
-  RunPixelTestWithLayerList(test_type_, root_layer, file_name, property_trees);
-}
-
 ParameterizedPixelResourceTest::ParameterizedPixelResourceTest()
     : LayerTreeHostPixelResourceTest(::testing::get<0>(GetParam()),
                                      ::testing::get<1>(GetParam())) {}
diff --git a/cc/test/layer_tree_pixel_resource_test.h b/cc/test/layer_tree_pixel_resource_test.h
index 55f8500..29de0644 100644
--- a/cc/test/layer_tree_pixel_resource_test.h
+++ b/cc/test/layer_tree_pixel_resource_test.h
@@ -31,10 +31,6 @@
   void RunPixelResourceTest(scoped_refptr<Layer> content_root,
                             const SkBitmap& expected_bitmap);
 
-  void RunPixelResourceTestWithLayerList(scoped_refptr<Layer> root_layer,
-                                         base::FilePath file_name,
-                                         PropertyTrees* property_trees);
-
  protected:
   PixelResourceTestCase test_case_;
   Layer::LayerMaskType mask_type_;
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 8526bd0..a8a89de 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -17,7 +17,6 @@
 #include "cc/test/pixel_test_output_surface.h"
 #include "cc/test/pixel_test_utils.h"
 #include "cc/test/test_in_process_context_provider.h"
-#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_result.h"
@@ -34,7 +33,6 @@
 LayerTreePixelTest::LayerTreePixelTest()
     : pixel_comparator_(new ExactPixelComparator(true)),
       test_type_(PIXEL_TEST_GL),
-      property_trees_(nullptr),
       pending_texture_mailbox_callbacks_(0) {}
 
 LayerTreePixelTest::~LayerTreePixelTest() = default;
@@ -120,16 +118,7 @@
 void LayerTreePixelTest::BeginTest() {
   Layer* target =
       readback_target_ ? readback_target_ : layer_tree_host()->root_layer();
-  if (!property_trees_) {
-    target->RequestCopyOfOutput(CreateCopyOutputRequest());
-  } else {
-    layer_tree_host()->property_trees()->effect_tree.AddCopyRequest(
-        target->effect_tree_index(), CreateCopyOutputRequest());
-    layer_tree_host()
-        ->property_trees()
-        ->effect_tree.Node(target->effect_tree_index())
-        ->has_copy_request = true;
-  }
+  target->RequestCopyOfOutput(CreateCopyOutputRequest());
   PostSetNeedsCommitToMainThread();
 }
 
@@ -161,8 +150,6 @@
   layer->SetIsDrawable(true);
   layer->SetBounds(rect.size());
   layer->SetPosition(gfx::PointF(rect.origin()));
-  layer->SetOffsetToTransformParent(
-      gfx::Vector2dF(rect.origin().x(), rect.origin().y()));
   layer->SetBackgroundColor(color);
   return layer;
 }
@@ -239,48 +226,6 @@
   RunTest(CompositorMode::THREADED);
 }
 
-void LayerTreePixelTest::RunPixelTestWithLayerList(
-    PixelTestType test_type,
-    scoped_refptr<Layer> root_layer,
-    base::FilePath file_name,
-    PropertyTrees* property_trees) {
-  test_type_ = test_type;
-  content_root_ = root_layer;
-  property_trees_ = property_trees;
-  readback_target_ = nullptr;
-  ref_file_ = file_name;
-  RunTest(CompositorMode::THREADED);
-}
-
-void LayerTreePixelTest::InitializeForLayerListMode(
-    scoped_refptr<Layer>* root_layer,
-    PropertyTrees* property_trees) {
-  ClipNode clip_node;
-  property_trees->clip_tree.Insert(clip_node, 0);
-
-  EffectNode root_effect;
-  root_effect.clip_id = 1;
-  root_effect.stable_id = 1;
-  root_effect.transform_id = 1;
-  root_effect.has_render_surface = true;
-  property_trees->effect_tree.Insert(root_effect, 0);
-
-  ScrollNode scroll_node;
-  property_trees->scroll_tree.Insert(scroll_node, 0);
-
-  TransformNode transform_node;
-  property_trees->transform_tree.Insert(transform_node, 0);
-
-  *root_layer = Layer::Create();
-  (*root_layer)->SetBounds(gfx::Size(100, 100));
-  (*root_layer)->SetEffectTreeIndex(1);
-  (*root_layer)->SetClipTreeIndex(1);
-  (*root_layer)->SetScrollTreeIndex(1);
-  (*root_layer)->SetTransformTreeIndex(1);
-  (*root_layer)
-      ->set_property_tree_sequence_number(property_trees->sequence_number);
-}
-
 void LayerTreePixelTest::RunSingleThreadedPixelTest(
     PixelTestType test_type,
     scoped_refptr<Layer> content_root,
@@ -305,15 +250,10 @@
 }
 
 void LayerTreePixelTest::SetupTree() {
-  if (property_trees_) {
-    layer_tree_host()->SetRootLayer(content_root_);
-    layer_tree_host()->SetPropertyTreesForTesting(property_trees_);
-  } else {
-    scoped_refptr<Layer> root = Layer::Create();
-    root->SetBounds(content_root_->bounds());
-    root->AddChild(content_root_);
-    layer_tree_host()->SetRootLayer(root);
-  }
+  scoped_refptr<Layer> root = Layer::Create();
+  root->SetBounds(content_root_->bounds());
+  root->AddChild(content_root_);
+  layer_tree_host()->SetRootLayer(root);
   LayerTreeTest::SetupTree();
 }
 
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index 4c37dc66..3c95b739 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -11,10 +11,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "cc/test/layer_tree_test.h"
-#include "cc/trees/clip_node.h"
-#include "cc/trees/effect_node.h"
-#include "cc/trees/scroll_node.h"
-#include "cc/trees/transform_node.h"
 #include "components/viz/common/resources/single_release_callback.h"
 #include "ui/gl/gl_implementation.h"
 
@@ -75,12 +71,6 @@
       int border_width,
       SkColor border_color);
 
-  // Initializes the root layer and root PropertyTrees for layer list mode.
-  // In this mode, all other layers are direct children of |root_layer| and
-  // any property nodes are descendants of node id 1 in the respective trees.
-  void InitializeForLayerListMode(scoped_refptr<Layer>* root_layer,
-                                  PropertyTrees* property_trees);
-
   void RunPixelTest(PixelTestType type,
                     scoped_refptr<Layer> content_root,
                     base::FilePath file_name);
@@ -88,11 +78,6 @@
                     scoped_refptr<Layer> content_root,
                     const SkBitmap& expected_bitmap);
 
-  void RunPixelTestWithLayerList(PixelTestType type,
-                                 scoped_refptr<Layer> root_layer,
-                                 base::FilePath file_name,
-                                 PropertyTrees* property_trees);
-
   void RunSingleThreadedPixelTest(PixelTestType test_type,
                                   scoped_refptr<Layer> content_root,
                                   base::FilePath file_name);
@@ -126,7 +111,6 @@
   std::unique_ptr<PixelComparator> pixel_comparator_;
   PixelTestType test_type_;
   scoped_refptr<Layer> content_root_;
-  PropertyTrees* property_trees_;
   Layer* readback_target_;
   base::FilePath ref_file_;
   SkBitmap expected_bitmap_;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 1ac087a9..cb3c29d 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1832,11 +1832,6 @@
   return LayerListReverseIterator<Layer>(nullptr);
 }
 
-void LayerTreeHost::SetPropertyTreesForTesting(
-    const PropertyTrees* property_trees) {
-  property_trees_ = *property_trees;
-}
-
 void LayerTreeHost::SetNeedsDisplayOnAllLayers() {
   for (auto* layer : *this)
     layer->SetNeedsDisplay();
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 5634ca05..c78f8565 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -496,8 +496,6 @@
   PropertyTrees* property_trees() { return &property_trees_; }
   const PropertyTrees* property_trees() const { return &property_trees_; }
 
-  void SetPropertyTreesForTesting(const PropertyTrees* property_trees);
-
   void SetNeedsDisplayOnAllLayers();
 
   void RegisterLayer(Layer* layer);
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index a75e460..e58aadb 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -93,205 +93,6 @@
                        base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png")));
 }
 
-class LayerTreeHostLayerListPixelTest : public ParameterizedPixelResourceTest {
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->use_layer_lists = true;
-  }
-};
-
-INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(LayerTreeHostLayerListPixelTest);
-
-TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffect) {
-  PropertyTrees property_trees;
-  scoped_refptr<Layer> root_layer;
-  InitializeForLayerListMode(&root_layer, &property_trees);
-
-  EffectNode isolation_effect;
-  isolation_effect.clip_id = 1;
-  isolation_effect.stable_id = 2;
-  isolation_effect.has_render_surface = true;
-  isolation_effect.transform_id = 1;
-  property_trees.effect_tree.Insert(isolation_effect, 1);
-
-  EffectNode mask_effect;
-  mask_effect.clip_id = 1;
-  mask_effect.stable_id = 2;
-  mask_effect.transform_id = 1;
-  mask_effect.blend_mode = SkBlendMode::kDstIn;
-  property_trees.effect_tree.Insert(mask_effect, 2);
-
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
-  background->set_property_tree_sequence_number(property_trees.sequence_number);
-  background->SetClipTreeIndex(1);
-  background->SetEffectTreeIndex(1);
-  background->SetScrollTreeIndex(1);
-  background->SetTransformTreeIndex(1);
-  root_layer->AddChild(background);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(25, 25, 50, 50), kCSSGreen);
-  green->set_property_tree_sequence_number(property_trees.sequence_number);
-  green->SetClipTreeIndex(1);
-  green->SetEffectTreeIndex(2);
-  green->SetScrollTreeIndex(1);
-  green->SetTransformTreeIndex(1);
-
-  root_layer->AddChild(green);
-
-  gfx::Size mask_bounds(50, 50);
-  MaskContentLayerClient client(mask_bounds);
-
-  scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
-  mask->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
-  mask->set_property_tree_sequence_number(property_trees.sequence_number);
-  mask->SetBounds(mask_bounds);
-  mask->SetIsDrawable(true);
-  mask->SetClipTreeIndex(1);
-  mask->SetEffectTreeIndex(3);
-  mask->SetScrollTreeIndex(1);
-  mask->SetTransformTreeIndex(1);
-  root_layer->AddChild(mask);
-
-  RunPixelResourceTestWithLayerList(
-      root_layer, base::FilePath(FILE_PATH_LITERAL("mask_with_effect.png")),
-      &property_trees);
-}
-
-TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffectDifferentSize) {
-  PropertyTrees property_trees;
-  scoped_refptr<Layer> root_layer;
-  InitializeForLayerListMode(&root_layer, &property_trees);
-
-  EffectNode isolation_effect;
-  isolation_effect.clip_id = 1;
-  isolation_effect.stable_id = 2;
-  isolation_effect.has_render_surface = true;
-  isolation_effect.transform_id = 1;
-  property_trees.effect_tree.Insert(isolation_effect, 1);
-
-  EffectNode mask_effect;
-  mask_effect.clip_id = 1;
-  mask_effect.stable_id = 2;
-  mask_effect.transform_id = 1;
-  mask_effect.blend_mode = SkBlendMode::kDstIn;
-  property_trees.effect_tree.Insert(mask_effect, 2);
-
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
-  background->set_property_tree_sequence_number(property_trees.sequence_number);
-  background->SetClipTreeIndex(1);
-  background->SetEffectTreeIndex(1);
-  background->SetScrollTreeIndex(1);
-  background->SetTransformTreeIndex(1);
-  root_layer->AddChild(background);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(25, 25, 50, 50), kCSSGreen);
-  green->set_property_tree_sequence_number(property_trees.sequence_number);
-  green->SetClipTreeIndex(1);
-  green->SetEffectTreeIndex(2);
-  green->SetScrollTreeIndex(1);
-  green->SetTransformTreeIndex(1);
-
-  root_layer->AddChild(green);
-
-  gfx::Size mask_bounds(25, 25);
-  MaskContentLayerClient client(mask_bounds);
-
-  scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
-  mask->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
-  mask->set_property_tree_sequence_number(property_trees.sequence_number);
-  mask->SetBounds(mask_bounds);
-  mask->SetIsDrawable(true);
-  mask->SetClipTreeIndex(1);
-  mask->SetEffectTreeIndex(3);
-  mask->SetScrollTreeIndex(1);
-  mask->SetTransformTreeIndex(1);
-  root_layer->AddChild(mask);
-
-  // The mask is half the size of thing it's masking. In layer-list mode,
-  // the mask is not automatically scaled to match the other layer.
-  RunPixelResourceTestWithLayerList(
-      root_layer,
-      base::FilePath(FILE_PATH_LITERAL("mask_with_effect_different_size.png")),
-      &property_trees);
-}
-
-TEST_P(LayerTreeHostLayerListPixelTest, ImageMaskWithEffect) {
-  PropertyTrees property_trees;
-  scoped_refptr<Layer> root_layer;
-  InitializeForLayerListMode(&root_layer, &property_trees);
-
-  EffectNode isolation_effect;
-  isolation_effect.clip_id = 1;
-  isolation_effect.stable_id = 2;
-  isolation_effect.has_render_surface = true;
-  isolation_effect.transform_id = 1;
-  property_trees.effect_tree.Insert(isolation_effect, 1);
-
-  EffectNode mask_effect;
-  mask_effect.clip_id = 1;
-  mask_effect.stable_id = 2;
-  mask_effect.transform_id = 1;
-  mask_effect.blend_mode = SkBlendMode::kDstIn;
-  property_trees.effect_tree.Insert(mask_effect, 2);
-
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
-  background->set_property_tree_sequence_number(property_trees.sequence_number);
-  background->SetClipTreeIndex(1);
-  background->SetEffectTreeIndex(1);
-  background->SetScrollTreeIndex(1);
-  background->SetTransformTreeIndex(1);
-  root_layer->AddChild(background);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(25, 25, 50, 50), kCSSGreen);
-  green->set_property_tree_sequence_number(property_trees.sequence_number);
-  green->SetClipTreeIndex(1);
-  green->SetEffectTreeIndex(2);
-  green->SetScrollTreeIndex(1);
-  green->SetTransformTreeIndex(1);
-
-  root_layer->AddChild(green);
-
-  gfx::Size mask_bounds(50, 50);
-  MaskContentLayerClient client(mask_bounds);
-
-  scoped_refptr<PictureImageLayer> mask = PictureImageLayer::Create();
-  mask->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
-  mask->set_property_tree_sequence_number(property_trees.sequence_number);
-  mask->SetBounds(mask_bounds);
-  mask->SetIsDrawable(true);
-  mask->SetClipTreeIndex(1);
-  mask->SetEffectTreeIndex(3);
-  mask->SetScrollTreeIndex(1);
-  mask->SetTransformTreeIndex(1);
-
-  sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(200, 200);
-  SkCanvas* canvas = surface->getCanvas();
-  canvas->scale(SkIntToScalar(4), SkIntToScalar(4));
-  scoped_refptr<DisplayItemList> mask_display_list =
-      client.PaintContentsToDisplayList(
-          ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
-  mask_display_list->Raster(canvas);
-  mask->SetImage(PaintImageBuilder::WithDefault()
-                     .set_id(PaintImage::GetNextId())
-                     .set_image(surface->makeImageSnapshot(),
-                                PaintImage::GetNextContentId())
-                     .TakePaintImage(),
-                 SkMatrix::I(), false);
-  root_layer->AddChild(mask);
-
-  // The mask is half the size of thing it's masking. In layer-list mode,
-  // the mask is not automatically scaled to match the other layer.
-  RunPixelResourceTestWithLayerList(
-      root_layer,
-      base::FilePath(FILE_PATH_LITERAL("image_mask_with_effect.png")),
-      &property_trees);
-}
-
 TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
diff --git a/chrome/VERSION b/chrome/VERSION
index b1489d7..9391ebe 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=74
 MINOR=0
-BUILD=3707
+BUILD=3711
 PATCH=0
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml
index 28e7a4f..54b3ff3 100644
--- a/chrome/android/java/res/xml/sync_and_services_preferences.xml
+++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -38,11 +38,6 @@
             android:summary="@string/autocomplete_searches_and_urls_summary"
             android:persistent="false"/>
         <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
-            android:key="network_predictions"
-            android:title="@string/preload_pages_title"
-            android:summary="@string/preload_pages_summary"
-            android:persistent="false"/>
-        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="navigation_error"
             android:title="@string/navigation_error_suggestions_title"
             android:summary="@string/navigation_error_suggestions_summary"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 5e9390f..1dca133 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1928,8 +1928,6 @@
     @Override
     public void onOrientationChange(int orientation) {
         if (mToolbarManager != null) mToolbarManager.onOrientationChange();
-        Tab tab = getActivityTab();
-        if (tab != null) tab.onOrientationChange();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index cc7eff3..86564c71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -235,6 +235,7 @@
     public static final String HORIZONTAL_TAB_SWITCHER_ANDROID = "HorizontalTabSwitcherAndroid";
     public static final String INCOGNITO_STRINGS = "IncognitoStrings";
     public static final String INFLATE_TOOLBAR_ON_BACKGROUND_THREAD = "BackgroundToolbarInflation";
+    public static final String INLINE_UPDATE_FLOW = "InlineUpdateFlow";
     public static final String INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE =
             "IntentBlockExternalFormRedirectsNoGesture";
     public static final String INTEREST_FEED_CONTENT_SUGGESTIONS = "InterestFeedContentSuggestions";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index a0c4f94..c0443815 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2204,7 +2204,8 @@
 
     @Override
     public boolean isInOverviewMode() {
-        return mLayoutManager != null && mLayoutManager.overviewVisible();
+        return (mLayoutManager != null && mLayoutManager.overviewVisible())
+                || (mTabModelSelectorImpl != null && mTabModelSelectorImpl.isInOverviewMode());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
index a03b079..4d09f6e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -94,13 +94,18 @@
 
     public static boolean isEnabled(@ExploreSitesVariation int variation) {
         return variation == ExploreSitesVariation.ENABLED
-                || variation == ExploreSitesVariation.PERSONALIZED;
+                || variation == ExploreSitesVariation.PERSONALIZED
+                || variation == ExploreSitesVariation.CONDENSED;
     }
 
     public static boolean isExperimental(@ExploreSitesVariation int variation) {
         return variation == ExploreSitesVariation.EXPERIMENT;
     }
 
+    public static boolean isCondensed(@ExploreSitesVariation int variation) {
+        return variation == ExploreSitesVariation.CONDENSED;
+    }
+
     /**
      * Increments the ntp_shown_count for a particular category.
      * @param categoryId the row id of the category to increment show count for.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationLayout.java
index 35e9e5a..baaf317 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationLayout.java
@@ -111,6 +111,9 @@
 
         @Override
         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            // onScroll needs handling only after the state moves away from none state.
+            if (mState == GestureState.NONE) return true;
+
             if (wasLastSideSwipeGestureConsumed()) {
                 reset();
                 mState = GestureState.NONE;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
index bdc718c..fbf5baf0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -75,7 +75,9 @@
      * metric semantics the same over time.
      */
     @IntDef({ActionType.UNKNOWN, ActionType.DOWNLOAD_PAUSE, ActionType.DOWNLOAD_RESUME,
-            ActionType.DOWNLOAD_CANCEL})
+            ActionType.DOWNLOAD_CANCEL, ActionType.DOWNLOAD_PAGE_PAUSE,
+            ActionType.DOWNLOAD_PAGE_RESUME, ActionType.DOWNLOAD_PAGE_CANCEL,
+            ActionType.CONTENT_SUGGESTION_SETTINGS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActionType {
         int UNKNOWN = -1;
@@ -91,8 +93,10 @@
         int DOWNLOAD_PAGE_RESUME = 4;
         // Cancel button on page download notification.
         int DOWNLOAD_PAGE_CANCEL = 5;
+        // Setting button on content suggestion notification.
+        int CONTENT_SUGGESTION_SETTINGS = 6;
 
-        int NUM_ENTRIES = 6;
+        int NUM_ENTRIES = 7;
     }
 
     private static final String LAST_SHOWN_NOTIFICATION_TYPE_KEY =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotifier.java
index 3c47bd3..109b7e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotifier.java
@@ -24,11 +24,14 @@
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.chrome.browser.notifications.ChromeNotification;
 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
 import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
 import org.chromium.chrome.browser.notifications.NotificationManagerProxy;
 import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl;
+import org.chromium.chrome.browser.notifications.NotificationMetadata;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
+import org.chromium.chrome.browser.notifications.PendingIntentProvider;
 import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
 import org.chromium.chrome.browser.notifications.channels.ChannelsInitializer;
 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAction;
@@ -156,18 +159,17 @@
 
         // Post notification.
         Context context = ContextUtils.getApplicationContext();
-        NotificationManager manager =
-                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        NotificationManagerProxy manager = new NotificationManagerProxyImpl(context);
 
         int nextId = nextNotificationId();
         Uri uri = Uri.parse(url);
-        PendingIntent contentIntent = PendingIntent.getBroadcast(context, 0,
+        PendingIntentProvider contentIntent = PendingIntentProvider.getBroadcast(context, 0,
                 new Intent(context, OpenUrlReceiver.class)
                         .setData(uri)
                         .putExtra(NOTIFICATION_CATEGORY_EXTRA, category)
                         .putExtra(NOTIFICATION_ID_WITHIN_CATEGORY_EXTRA, idWithinCategory),
                 0);
-        PendingIntent deleteIntent = PendingIntent.getBroadcast(context, 0,
+        PendingIntentProvider deleteIntent = PendingIntentProvider.getBroadcast(context, 0,
                 new Intent(context, DeleteReceiver.class)
                         .setData(uri)
                         .putExtra(NOTIFICATION_CATEGORY_EXTRA, category)
@@ -176,7 +178,12 @@
         ChromeNotificationBuilder builder =
                 NotificationBuilderFactory
                         .createChromeNotificationBuilder(true /* preferCompat */,
-                                ChannelDefinitions.ChannelId.CONTENT_SUGGESTIONS)
+                                ChannelDefinitions.ChannelId.CONTENT_SUGGESTIONS,
+                                null /* remoteAppPackageName */,
+                                new NotificationMetadata(
+                                        NotificationUmaTracker.SystemNotificationType
+                                                .CONTENT_SUGGESTION,
+                                        NOTIFICATION_TAG, nextId))
                         .setContentIntent(contentIntent)
                         .setDeleteIntent(deleteIntent)
                         .setContentTitle(title)
@@ -186,19 +193,20 @@
                         .setLargeIcon(image)
                         .setSmallIcon(R.drawable.ic_chrome);
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            PendingIntent settingsIntent = PendingIntent.getActivity(context, 0,
+            PendingIntentProvider settingsIntent = PendingIntentProvider.getActivity(context, 0,
                     PreferencesLauncher.createIntentForSettingsPage(
                             context, NotificationsPreferences.class.getName()),
                     0);
             builder.addAction(R.drawable.settings_cog, context.getString(R.string.preferences),
-                    settingsIntent);
+                    settingsIntent, NotificationUmaTracker.ActionType.CONTENT_SUGGESTION_SETTINGS);
         }
         if (priority >= 0) builder.setDefaults(Notification.DEFAULT_ALL);
-        Notification notification = builder.build();
+        ChromeNotification notification = builder.buildChromeNotification();
 
-        manager.notify(NOTIFICATION_TAG, nextId, notification);
+        manager.notify(notification);
         NotificationUmaTracker.getInstance().onNotificationShown(
-                NotificationUmaTracker.SystemNotificationType.CONTENT_SUGGESTION, notification);
+                NotificationUmaTracker.SystemNotificationType.CONTENT_SUGGESTION,
+                notification.getNotification());
 
         addActiveNotification(new ActiveNotification(nextId, category, idWithinCategory, uri));
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java
index e79cef8..4c10d75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java
@@ -10,6 +10,7 @@
 import org.chromium.base.CommandLine;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState;
+import org.chromium.chrome.browser.omaha.inline.FakeAppUpdateManagerWrapper;
 import org.chromium.components.variations.VariationsAssociatedData;
 
 /**
@@ -19,7 +20,7 @@
  * - {@link ChromeSwitches#FORCE_SHOW_UPDATE_MENU_BADGE} (optional)
  * - {@link ChromeSwitches#MARKET_URL_FOR_TESTING} (optional)
  */
-class UpdateConfigs {
+public class UpdateConfigs {
     // VariationsAssociatedData configs
     private static final String FIELD_TRIAL_NAME = "UpdateMenuItem";
     private static final String ENABLED_VALUE = "true";
@@ -30,11 +31,17 @@
     private static final String NONE_SWITCH_VALUE = "none";
     private static final String UPDATE_AVAILABLE_SWITCH_VALUE = "update_available";
     private static final String UNSUPPORTED_OS_VERSION_SWITCH_VALUE = "unsupported_os_version";
-    private static final String INLINE_UPDATE_AVAILABLE_SWITCH_VALUE = "inline_update_available";
-    private static final String INLINE_UPDATE_DOWNLOADING_SWITCH_VALUE =
-            "inline_update_downloading";
-    private static final String INLINE_UPDATE_READY_SWITCH_VALUE = "inline_update_ready";
-    private static final String INLINE_UPDATE_FAILED_SWITCH_VALUE = "inline_update_failed";
+    private static final String INLINE_UPDATE_SUCCESS_SWITCH_VALUE = "inline_update_success";
+    private static final String INLINE_UPDATE_DIALOG_CANCELED_SWITCH_VALUE =
+            "inline_update_dialog_canceled";
+    private static final String INLINE_UPDATE_DIALOG_FAILED_SWITCH_VALUE =
+            "inline_update_dialog_failed";
+    private static final String INLINE_UPDATE_DOWNLOAD_FAILED_SWITCH_VALUE =
+            "inline_update_download_failed";
+    private static final String INLINE_UPDATE_DOWNLOAD_CANCELED_SWITCH_VALUE =
+            "inline_update_download_canceled";
+    private static final String INLINE_UPDATE_INSTALL_FAILED_SWITCH_VALUE =
+            "inline_update_install_failed";
 
     /**
      * @return The minimum required storage to show the update prompt or {@code -1} if there is no
@@ -87,20 +94,56 @@
                 return UpdateState.UPDATE_AVAILABLE;
             case UNSUPPORTED_OS_VERSION_SWITCH_VALUE:
                 return UpdateState.UNSUPPORTED_OS_VERSION;
-            case INLINE_UPDATE_AVAILABLE_SWITCH_VALUE:
+            case INLINE_UPDATE_SUCCESS_SWITCH_VALUE: // Intentional fallthrough.
+            case INLINE_UPDATE_DIALOG_CANCELED_SWITCH_VALUE: // Intentional fallthrough.
+            case INLINE_UPDATE_DIALOG_FAILED_SWITCH_VALUE: // Intentional fallthrough.
+            case INLINE_UPDATE_DOWNLOAD_FAILED_SWITCH_VALUE: // Intentional fallthrough.
+            case INLINE_UPDATE_DOWNLOAD_CANCELED_SWITCH_VALUE: // Intentional fallthrough.
+            case INLINE_UPDATE_INSTALL_FAILED_SWITCH_VALUE:
+                // The chrome://flags configuration refers to how the inline update flow should end,
+                // but we will always start at the beginning of the flow.
                 return UpdateState.INLINE_UPDATE_AVAILABLE;
-            case INLINE_UPDATE_DOWNLOADING_SWITCH_VALUE:
-                return UpdateState.INLINE_UPDATE_DOWNLOADING;
-            case INLINE_UPDATE_FAILED_SWITCH_VALUE:
-                return UpdateState.INLINE_UPDATE_FAILED;
-            case INLINE_UPDATE_READY_SWITCH_VALUE:
-                return UpdateState.INLINE_UPDATE_READY;
             default:
                 return null;
         }
     }
 
     /**
+     * For when there is a test scenario for inline updates, it returns the end state. If there is
+     * no test scenario, it returns
+     * {@link FakeAppUpdateManagerWrapper.Type.NO_SIMULATION}.
+     * @return the end state for what the fake inline scenario should be.
+     */
+    public static @FakeAppUpdateManagerWrapper.Type int getMockInlineScenarioEndState() {
+        String forcedUpdateType =
+                UpdateConfigs.getStringParamValue(ChromeSwitches.FORCE_UPDATE_MENU_UPDATE_TYPE);
+        if (TextUtils.isEmpty(forcedUpdateType)) {
+            return FakeAppUpdateManagerWrapper.Type.NO_SIMULATION;
+        }
+
+        switch (forcedUpdateType) {
+            case UpdateConfigs.INLINE_UPDATE_SUCCESS_SWITCH_VALUE:
+                return FakeAppUpdateManagerWrapper.Type.SUCCESS;
+            case UpdateConfigs.INLINE_UPDATE_DIALOG_CANCELED_SWITCH_VALUE:
+                return FakeAppUpdateManagerWrapper.Type.FAIL_DIALOG_CANCEL;
+            case UpdateConfigs.INLINE_UPDATE_DIALOG_FAILED_SWITCH_VALUE:
+                return FakeAppUpdateManagerWrapper.Type.FAIL_DIALOG_UPDATE_FAILED;
+            case UpdateConfigs.INLINE_UPDATE_DOWNLOAD_FAILED_SWITCH_VALUE:
+                return FakeAppUpdateManagerWrapper.Type.FAIL_DOWNLOAD;
+            case UpdateConfigs.INLINE_UPDATE_DOWNLOAD_CANCELED_SWITCH_VALUE:
+                return FakeAppUpdateManagerWrapper.Type.FAIL_DOWNLOAD_CANCEL;
+            case UpdateConfigs.INLINE_UPDATE_INSTALL_FAILED_SWITCH_VALUE:
+                return FakeAppUpdateManagerWrapper.Type.FAIL_INSTALL;
+            case UpdateConfigs.NONE_SWITCH_VALUE: // Intentional fallthrough.
+            case UpdateConfigs.UPDATE_AVAILABLE_SWITCH_VALUE: // Intentional fallthrough.
+            case UpdateConfigs.UNSUPPORTED_OS_VERSION_SWITCH_VALUE: // Intentional fallthrough.
+            default:
+                // The config requires to run through a test scenario without inline updates.
+                return FakeAppUpdateManagerWrapper.Type.NONE;
+        }
+    }
+
+    /**
      * @return A URL to use when an update is available if mocking out the update available menu
      * item.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java
index af329ea..7a82bc0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java
@@ -33,6 +33,7 @@
 import org.chromium.base.task.AsyncTask.Status;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.omaha.inline.InlineUpdateController;
+import org.chromium.chrome.browser.omaha.inline.InlineUpdateControllerFactory;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.util.ConversionUtils;
 
@@ -107,6 +108,7 @@
             latestVersion = other.latestVersion;
             latestUnsupportedVersion = other.latestUnsupportedVersion;
             mIsSimulated = other.mIsSimulated;
+            mIsInlineSimulated = other.mIsInlineSimulated;
         }
     }
 
@@ -209,7 +211,7 @@
     }
 
     private UpdateStatusProvider() {
-        mInlineController = new InlineUpdateController(this::resolveStatus);
+        mInlineController = InlineUpdateControllerFactory.create(this::resolveStatus);
         mOmahaQuery = new UpdateQuery(this::resolveStatus);
 
         // Note that as a singleton this class never unregisters.
@@ -228,15 +230,22 @@
         // We pull the Omaha result once as it will never change.
         if (mStatus == null) mStatus = new UpdateStatus(mOmahaQuery.getResult());
 
-        if (!mStatus.mIsSimulated || mStatus.mIsInlineSimulated) {
+        if (mStatus.mIsSimulated) {
+            if (mStatus.mIsInlineSimulated) {
+                @UpdateState
+                int inlineState = mInlineController.getStatus();
+
+                if (inlineState == UpdateState.NONE) {
+                    mStatus.updateState = mOmahaQuery.getResult().updateState;
+                } else {
+                    mStatus.updateState = inlineState;
+                }
+            }
+        } else {
             @UpdateState
             int inlineState = mInlineController.getStatus();
-
-            if (mStatus.updateState == UpdateState.UPDATE_AVAILABLE
-                    && inlineState != UpdateState.NONE) {
+            if (inlineState != UpdateState.NONE) {
                 mStatus.updateState = inlineState;
-            } else {
-                mStatus.updateState = mOmahaQuery.getResult().updateState;
             }
         }
 
@@ -287,9 +296,7 @@
             status.mIsSimulated = true;
             status.updateState = forcedUpdateState;
 
-            // TODO(dtrainor/nyquist): If a fake inline flow is set, set the state to
-            // UPDATE_AVAILABLE here to properly get the flow kicked off and set this to true.
-            status.mIsInlineSimulated = false;
+            status.mIsInlineSimulated = forcedUpdateState == UpdateState.INLINE_UPDATE_AVAILABLE;
 
             // Push custom configurations for certain update states.
             switch (forcedUpdateState) {
@@ -377,4 +384,4 @@
             return ConversionUtils.bytesToMegabytes(blockSize * availableBlocks);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/FakeAppUpdateManagerWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/FakeAppUpdateManagerWrapper.java
index 02d6953f..8b384b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/FakeAppUpdateManagerWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/FakeAppUpdateManagerWrapper.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.support.annotation.IntDef;
 
 import com.google.android.play.core.appupdate.AppUpdateInfo;
@@ -16,24 +17,31 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.ui.widget.Toast;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 
 /**
  * A wrapper of FakeAppUpdateManager meant to help automatically trigger more update scenarios.  The
  * wrapper isn't meant to be used for a full integration test, but simulating all of the possible
  * error cases is a bit easier to do here.
  */
-class FakeAppUpdateManagerWrapper extends FakeAppUpdateManager {
+public class FakeAppUpdateManagerWrapper extends FakeAppUpdateManager {
     private static final int RESULT_IN_APP_UPDATE_FAILED = 1;
     private static final int STEP_DELAY_MS = 5000;
+    private static final int TOAST_DURATION_MS = 2000;
 
     /** A list of inline update end states that this class can simulate. */
-    @IntDef({Type.NONE, Type.SUCCESS, Type.FAIL_DIALOG_CANCEL, Type.FAIL_DIALOG_UPDATE_FAILED,
-            Type.FAIL_DOWNLOAD, Type.FAIL_DOWNLOAD_CANCEL, Type.FAIL_INSTALL})
+    @IntDef({Type.NO_SIMULATION, Type.NONE, Type.SUCCESS, Type.FAIL_DIALOG_CANCEL,
+            Type.FAIL_DIALOG_UPDATE_FAILED, Type.FAIL_DOWNLOAD, Type.FAIL_DOWNLOAD_CANCEL,
+            Type.FAIL_INSTALL})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Type {
+        /** No simulation. */
+        int NO_SIMULATION = 0;
+
         /** No update available. */
         int NONE = 1;
 
@@ -53,27 +61,114 @@
         int FAIL_DOWNLOAD_CANCEL = 6;
 
         /** The update will fail because it failed to install. */
-        int FAIL_INSTALL = 6;
+        int FAIL_INSTALL = 7;
+    }
+
+    @IntDef({Event.UPDATE_AVAILABLE, Event.USER_ACCEPTS_UPDATE, Event.USER_REJECTS_UPDATE,
+            Event.TRIGGER_DOWNLOAD, Event.DOWNLOAD_STARTS, Event.DOWNLOAD_FAILS,
+            Event.USER_CANCELS_DOWNLOAD, Event.DOWNLOAD_COMPLETES, Event.INSTALL_FAILS,
+            Event.INSTALL_COMPLETES})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Event {
+        int UPDATE_AVAILABLE = 1;
+        int USER_ACCEPTS_UPDATE = 2;
+        int USER_REJECTS_UPDATE = 3;
+        int TRIGGER_DOWNLOAD = 4;
+        int DOWNLOAD_STARTS = 5;
+        int DOWNLOAD_FAILS = 6;
+        int USER_CANCELS_DOWNLOAD = 7;
+        int DOWNLOAD_COMPLETES = 8;
+        int INSTALL_FAILS = 9;
+        int INSTALL_COMPLETES = 10;
+    }
+
+    /**
+     * A helper class to wrap invocations to the Google Play API.
+     */
+    private static class EventHandler extends Handler {
+        // Need to use a weak reference to ensure the handler does not leak the outer object.
+        private final WeakReference<FakeAppUpdateManagerWrapper> mWeakWrapper;
+
+        EventHandler(FakeAppUpdateManagerWrapper wrapper) {
+            super(Looper.getMainLooper());
+            mWeakWrapper = new WeakReference<>(wrapper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            execute(msg.what);
+        }
+
+        public void execute(@Event int event) {
+            FakeAppUpdateManagerWrapper w = mWeakWrapper.get();
+            if (w == null) return;
+            switch (event) {
+                case Event.UPDATE_AVAILABLE:
+                    w.toast("Making app update available.");
+                    w.setUpdateAvailable(10000 /* Figure out a better version? */);
+                    return;
+                case Event.USER_ACCEPTS_UPDATE:
+                    w.toast("User accepts update.");
+                    w.userAcceptsUpdate();
+                    return;
+                case Event.USER_REJECTS_UPDATE:
+                    w.toast("User rejects update.");
+                    w.userRejectsUpdate();
+                    return;
+                case Event.TRIGGER_DOWNLOAD:
+                    w.toast("Triggering download.");
+                    w.triggerDownload();
+                    return;
+                case Event.DOWNLOAD_STARTS:
+                    w.toast("Download has started.");
+                    w.downloadStarts();
+                    return;
+                case Event.DOWNLOAD_FAILS:
+                    w.toast("Triggering download failure.");
+                    w.downloadFails();
+                    return;
+                case Event.USER_CANCELS_DOWNLOAD:
+                    w.toast("Triggering cancellation of download.");
+                    w.userCancelsDownload();
+                    return;
+                case Event.DOWNLOAD_COMPLETES:
+                    w.toast("Download completes.");
+                    w.downloadCompletes();
+                    return;
+                case Event.INSTALL_FAILS:
+                    w.toast("Triggering install failure.");
+                    w.installFails();
+                    return;
+                case Event.INSTALL_COMPLETES:
+                    w.toast("Triggering install completion.");
+                    w.installCompletes();
+                    return;
+                default:
+                    w.toast("Unknown event.");
+            }
+        }
     }
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final @Type int mType;
+    private final EventHandler mEventHandler;
 
     /**
-     *
-     * @param type
+     * @param endState at which point should the inline update flow end.
      */
-    public FakeAppUpdateManagerWrapper(@Type int type) {
+    FakeAppUpdateManagerWrapper(@Type int endState) {
         super(ContextUtils.getApplicationContext());
-        mType = type;
+        mType = endState;
+        mEventHandler = new EventHandler(this);
 
-        if (mType != Type.NONE) setUpdateAvailable(10000 /* Figure out a better version? */);
+        if (mType != Type.NONE) execute(Event.UPDATE_AVAILABLE);
     }
 
     // FakeAppUpdateManager implementation.
     @Override
     public boolean startUpdateFlowForResult(AppUpdateInfo appUpdateInfo,
             @AppUpdateType int appUpdateType, Activity activity, int requestCode) {
+        toast("Starting update flow.");
         // TODO(dtrainor): Simulate exceptions being thrown or returning false from the super call.
         boolean success =
                 super.startUpdateFlowForResult(appUpdateInfo, appUpdateType, activity, requestCode);
@@ -99,13 +194,14 @@
 
     @Override
     public Task<Void> completeUpdate() {
+        toast("Completing update.");
         Task<Void> result = super.completeUpdate();
 
         if (mType == Type.FAIL_INSTALL) {
-            mHandler.postDelayed(this::installCompletes, STEP_DELAY_MS);
-            // This doesn't actually restart Chrome in this case.
+            postDelayedEvent(Event.INSTALL_FAILS);
         } else {
-            mHandler.postDelayed(this::installFails, STEP_DELAY_MS);
+            postDelayedEvent(Event.INSTALL_COMPLETES);
+            // This doesn't actually restart Chrome in this case.
         }
 
         return result;
@@ -113,30 +209,40 @@
 
     private void triggerDialogResponse(ChromeActivity activity, int requestCode, int resultCode) {
         if (resultCode == Activity.RESULT_OK) {
-            userAcceptsUpdate();
+            execute(Event.USER_ACCEPTS_UPDATE);
         } else if (resultCode == Activity.RESULT_CANCELED) {
-            userRejectsUpdate();
+            execute(Event.USER_REJECTS_UPDATE);
         }
 
         activity.onActivityResult(requestCode, resultCode, null);
         if (resultCode == Activity.RESULT_OK) {
-            mHandler.postDelayed(this::triggerDownload, STEP_DELAY_MS);
+            postDelayedEvent(Event.TRIGGER_DOWNLOAD);
         }
     }
 
     private void triggerDownload() {
-        downloadStarts();
+        execute(Event.DOWNLOAD_STARTS);
 
         if (mType == Type.FAIL_DOWNLOAD) {
-            mHandler.postDelayed(this::downloadFails, STEP_DELAY_MS);
+            postDelayedEvent(Event.DOWNLOAD_FAILS);
         } else if (mType == Type.FAIL_DOWNLOAD_CANCEL) {
-            mHandler.postDelayed(this::userCancelsDownload, STEP_DELAY_MS);
+            postDelayedEvent(Event.USER_CANCELS_DOWNLOAD);
         } else {
-            mHandler.postDelayed(this::triggerInstall, STEP_DELAY_MS);
+            postDelayedEvent(Event.DOWNLOAD_COMPLETES);
         }
     }
 
-    private void triggerInstall() {
-        downloadCompletes();
+    private void execute(@Event int event) {
+        mEventHandler.execute(event);
     }
-}
\ No newline at end of file
+
+    private void postDelayedEvent(@Event int event) {
+        mEventHandler.sendEmptyMessageDelayed(event, STEP_DELAY_MS);
+    }
+
+    private void toast(CharSequence text) {
+        Toast.makeText(ContextUtils.getApplicationContext(), "Play Store Flow: " + text,
+                     TOAST_DURATION_MS)
+                .show();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineAppUpdateManagerFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineAppUpdateManagerFactory.java
deleted file mode 100644
index 387e4e7e..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineAppUpdateManagerFactory.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.omaha.inline;
-
-import com.google.android.play.core.appupdate.AppUpdateManager;
-import com.google.android.play.core.appupdate.AppUpdateManagerFactory;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.chrome.browser.omaha.inline.FakeAppUpdateManagerWrapper.Type;
-
-/** A factory that creates an {@link AppUpdateManager} instance. */
-public class InlineAppUpdateManagerFactory {
-    private static final boolean sTest = true;
-
-    /** @return A new {@link AppUpdateManager} to use to interact with Play for inline updates. */
-    public static AppUpdateManager create() {
-        // TODO(me): Check finch configuration to figure out what kind of test scenario to run.
-        if (sTest) {
-            return new FakeAppUpdateManagerWrapper(Type.NONE);
-        } else {
-            return AppUpdateManagerFactory.create(ContextUtils.getApplicationContext());
-        }
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateController.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateController.java
index 1f0c12f..2d2c5b0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateController.java
@@ -5,164 +5,40 @@
 package org.chromium.chrome.browser.omaha.inline;
 
 import android.app.Activity;
-import android.content.IntentSender.SendIntentException;
-import android.os.Handler;
-import android.os.Looper;
+import android.content.Intent;
 import android.support.annotation.Nullable;
 
-import com.google.android.play.core.appupdate.AppUpdateInfo;
-import com.google.android.play.core.appupdate.AppUpdateManager;
-import com.google.android.play.core.install.InstallState;
-import com.google.android.play.core.install.InstallStateUpdatedListener;
-import com.google.android.play.core.install.model.AppUpdateType;
-import com.google.android.play.core.install.model.InstallStatus;
-import com.google.android.play.core.install.model.UpdateAvailability;
-
-import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState;
+import org.chromium.chrome.browser.omaha.UpdateStatusProvider;
 
 /**
- * Helper class for gluing interactions with the Play store's AppUpdateManager with Chrome.  This
+ * Helper for gluing interactions with the Play store's AppUpdateManager with Chrome.  This
  * involves hooking up to Play as a listener for install state changes, should only happen if we are
  * in the foreground.
  */
-public class InlineUpdateController implements InstallStateUpdatedListener {
-    private static final int RESULT_IN_APP_UPDATE_FAILED = 1;
-    private static final int REQUEST_CODE = 8123;
-
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
-    private final Runnable mCallback;
-    private final AppUpdateManager mAppUpdateManager;
-
-    private boolean mEnabled;
-    private @Nullable @UpdateState Integer mUpdateState;
-
-    private AppUpdateInfo mAppUpdateInfo;
-    private @Nullable @UpdateAvailability Integer mUpdateAvailability;
-    private @Nullable @InstallStatus Integer mInstallStatus;
-
+public interface InlineUpdateController {
     /**
-     * Builds an instance of {@link InlineUpdateController}.
-     * @param callback The {@link Runnable} to notify when an inline update state change occurs.
+     * Enables or disables the controller.
+     * @param enabled true iff the controller should be enabled.
      */
-    public InlineUpdateController(Runnable callback) {
-        mCallback = callback;
-        mAppUpdateManager = InlineAppUpdateManagerFactory.create();
-
-        setEnabled(true);
-    }
-
-    public void setEnabled(boolean enabled) {
-        if (mEnabled == enabled) return;
-        mEnabled = enabled;
-
-        if (mEnabled) {
-            mUpdateState = UpdateState.NONE;
-            mAppUpdateManager.registerListener(this);
-            pullCurrentState();
-        } else {
-            mAppUpdateManager.unregisterListener(this);
-        }
-    }
+    void setEnabled(boolean enabled);
 
     /**
      * @return The current state of the inline update process.  May be {@code null} if the state
      * hasn't been determined yet.
      */
-    public @Nullable @UpdateState Integer getStatus() {
-        return mUpdateState;
-    }
+    @Nullable
+    @UpdateStatusProvider.UpdateState
+    Integer getStatus();
 
     /**
      * Starts the update, if possible.  This will send an {@link Intent} out to play, which may
      * cause Chrome to move to the background.
      * @param activity The {@link Activity} to use to interact with Play.
      */
-    public void startUpdate(Activity activity) {
-        try {
-            boolean success = mAppUpdateManager.startUpdateFlowForResult(
-                    mAppUpdateInfo, AppUpdateType.FLEXIBLE, activity, REQUEST_CODE);
-        } catch (SendIntentException exception) {
-            mInstallStatus = InstallStatus.FAILED;
-        }
-        // TODO(dtrainor): Use success.
-    }
+    void startUpdate(Activity activity);
 
     /**
      * Completes the Play installation process, if possible.  This may cause Chrome to restart.
      */
-    public void completeUpdate() {
-        mAppUpdateManager.completeUpdate()
-                .addOnSuccessListener(unused -> { pushStatus(); })
-                .addOnFailureListener(exception -> {
-                    mInstallStatus = InstallStatus.FAILED;
-                    pushStatus();
-                });
-    }
-
-    // InstallStateUpdatedListener implementation.
-    @Override
-    public void onStateUpdate(InstallState state) {
-        mInstallStatus = state.installStatus();
-        pushStatus();
-    }
-
-    private void pullCurrentState() {
-        mAppUpdateManager.getAppUpdateInfo()
-                .addOnSuccessListener(info -> {
-                    mAppUpdateInfo = info;
-                    mUpdateAvailability = info.updateAvailability();
-                    mInstallStatus = info.installStatus();
-                    pushStatus();
-                })
-                .addOnFailureListener(exception -> {
-                    mAppUpdateInfo = null;
-                    mUpdateAvailability = UpdateAvailability.UNKNOWN;
-                    mInstallStatus = InstallStatus.UNKNOWN;
-                    pushStatus();
-                });
-    }
-
-    private void pushStatus() {
-        if (!mEnabled || mUpdateAvailability == null || mInstallStatus == null) return;
-
-        @UpdateState
-        int newState = toUpdateState(mUpdateAvailability, mInstallStatus);
-        if (mUpdateState != null && mUpdateState == newState) return;
-
-        mUpdateState = newState;
-        mCallback.run();
-    }
-
-    private static @UpdateState int toUpdateState(
-            @UpdateAvailability int updateAvailability, @InstallStatus int installStatus) {
-        @UpdateState
-        int newStatus = UpdateState.NONE;
-
-        // Note, use InstallStatus first then UpdateAvailability if InstallStatus doesn't indicate
-        // a currently active install.
-        switch (installStatus) {
-            case InstallStatus.PENDING:
-                // Intentional fall through.
-            case InstallStatus.DOWNLOADING:
-                newStatus = UpdateState.INLINE_UPDATE_DOWNLOADING;
-                break;
-            case InstallStatus.DOWNLOADED:
-                newStatus = UpdateState.INLINE_UPDATE_READY;
-                break;
-            case InstallStatus.FAILED:
-                newStatus = UpdateState.INLINE_UPDATE_FAILED;
-                break;
-        }
-
-        if (newStatus == UpdateState.NONE) {
-            switch (updateAvailability) {
-                case UpdateAvailability.UPDATE_AVAILABLE:
-                    newStatus = UpdateState.INLINE_UPDATE_AVAILABLE;
-                    break;
-            }
-        }
-
-        return newStatus;
-    }
-}
\ No newline at end of file
+    void completeUpdate();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java
new file mode 100644
index 0000000..f5d2f18
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java
@@ -0,0 +1,42 @@
+// 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.omaha.inline;
+
+import com.google.android.play.core.appupdate.AppUpdateManagerFactory;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.omaha.UpdateConfigs;
+
+/**
+ * A factory that creates an {@link InlineUpdateController} instance.
+ */
+public class InlineUpdateControllerFactory {
+    /**
+     * @return A new {@link InlineUpdateController} to use to interact with Play for inline updates.
+     */
+    public static InlineUpdateController create(Runnable callback) {
+        @FakeAppUpdateManagerWrapper.Type
+        int mockInlineEndState = UpdateConfigs.getMockInlineScenarioEndState();
+        if (mockInlineEndState != FakeAppUpdateManagerWrapper.Type.NO_SIMULATION) {
+            // The config requires to run through a test controller, using the
+            // PlayInlineUpdateController, but with a fake Google Play backend that automatically
+            // goes through a scenario flow.
+            return new PlayInlineUpdateController(
+                    callback, new FakeAppUpdateManagerWrapper(mockInlineEndState));
+        }
+
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.INLINE_UPDATE_FLOW)) {
+            // The application configuration requires to use the real Google Play backend for inline
+            // updates.
+            return new PlayInlineUpdateController(
+                    callback, AppUpdateManagerFactory.create(ContextUtils.getApplicationContext()));
+        }
+
+        // No test scenario was in place, and the inline flow has not been enabled, so use a
+        // controller with no functionality.
+        return new NoopInlineUpdateController(callback);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/NoopInlineUpdateController.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/NoopInlineUpdateController.java
new file mode 100644
index 0000000..47d4e4e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/NoopInlineUpdateController.java
@@ -0,0 +1,37 @@
+// 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.omaha.inline;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.Nullable;
+
+import org.chromium.chrome.browser.omaha.UpdateStatusProvider;
+
+/**
+ * An update controller that does nothing. This is used if the inline update experiment has
+ * not been enabled.
+ */
+class NoopInlineUpdateController implements InlineUpdateController {
+    NoopInlineUpdateController(Runnable callback) {
+        // Do a one-off post since the state will never change.
+        new Handler(Looper.getMainLooper()).post(callback);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {}
+
+    @Override
+    public @Nullable @UpdateStatusProvider.UpdateState Integer getStatus() {
+        return UpdateStatusProvider.UpdateState.NONE;
+    }
+
+    @Override
+    public void startUpdate(Activity activity) {}
+
+    @Override
+    public void completeUpdate() {}
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java
new file mode 100644
index 0000000..4dc37b1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java
@@ -0,0 +1,176 @@
+// 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.omaha.inline;
+
+import android.app.Activity;
+import android.content.IntentSender.SendIntentException;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.Nullable;
+
+import com.google.android.play.core.appupdate.AppUpdateInfo;
+import com.google.android.play.core.appupdate.AppUpdateManager;
+import com.google.android.play.core.install.InstallState;
+import com.google.android.play.core.install.InstallStateUpdatedListener;
+import com.google.android.play.core.install.model.AppUpdateType;
+import com.google.android.play.core.install.model.InstallStatus;
+import com.google.android.play.core.install.model.UpdateAvailability;
+
+import org.chromium.base.Log;
+import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState;
+
+/**
+ * Helper class for gluing interactions with the Play store's AppUpdateManager with Chrome.  This
+ * involves hooking up to Play as a listener for install state changes, should only happen if we are
+ * in the foreground.
+ */
+public class PlayInlineUpdateController
+        implements InlineUpdateController, InstallStateUpdatedListener {
+    private static final String TAG = "PlayInline";
+    private static final int RESULT_IN_APP_UPDATE_FAILED = 1;
+    private static final int REQUEST_CODE = 8123;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    private final Runnable mCallback;
+    private final AppUpdateManager mAppUpdateManager;
+
+    private boolean mEnabled;
+    private @Nullable @UpdateState Integer mUpdateState;
+
+    private AppUpdateInfo mAppUpdateInfo;
+    private @Nullable @UpdateAvailability Integer mUpdateAvailability;
+    private @Nullable @InstallStatus Integer mInstallStatus;
+
+    /**
+     * Builds an instance of {@link PlayInlineUpdateController}.
+     * @param callback The {@link Runnable} to notify when an inline update state change occurs.
+     */
+    PlayInlineUpdateController(Runnable callback, AppUpdateManager appUpdateManager) {
+        mCallback = callback;
+        mAppUpdateManager = appUpdateManager;
+        setEnabled(true);
+    }
+
+    // InlineUpdateController implementation.
+    @Override
+    public void setEnabled(boolean enabled) {
+        if (mEnabled == enabled) return;
+        mEnabled = enabled;
+
+        if (mEnabled) {
+            mUpdateState = UpdateState.NONE;
+            mAppUpdateManager.registerListener(this);
+            pullCurrentState();
+        } else {
+            mAppUpdateManager.unregisterListener(this);
+        }
+    }
+
+    @Override
+    public @Nullable @UpdateState Integer getStatus() {
+        return mUpdateState;
+    }
+
+    @Override
+    public void startUpdate(Activity activity) {
+        try {
+            boolean success = mAppUpdateManager.startUpdateFlowForResult(
+                    mAppUpdateInfo, AppUpdateType.FLEXIBLE, activity, REQUEST_CODE);
+            Log.i(TAG, "startUpdateFlowForResult() returned " + success);
+        } catch (SendIntentException exception) {
+            mInstallStatus = InstallStatus.FAILED;
+            Log.i(TAG, "startUpdateFlowForResult() threw an exception.");
+        }
+        // TODO(dtrainor): Use success.
+    }
+
+    @Override
+    public void completeUpdate() {
+        mAppUpdateManager.completeUpdate()
+                .addOnSuccessListener(unused -> {
+                    Log.i(TAG, "completeUpdate() success.");
+                    pushStatus();
+                })
+                .addOnFailureListener(exception -> {
+                    Log.i(TAG, "completeUpdate() failed.");
+                    mInstallStatus = InstallStatus.FAILED;
+                    pushStatus();
+                });
+    }
+
+    // InstallStateUpdatedListener implementation.
+    @Override
+    public void onStateUpdate(InstallState state) {
+        Log.i(TAG,
+                "onStateUpdate(" + state.installStatus() + ", " + state.installErrorCode() + ")");
+        mInstallStatus = state.installStatus();
+        pushStatus();
+    }
+
+    private void pullCurrentState() {
+        mAppUpdateManager.getAppUpdateInfo()
+                .addOnSuccessListener(info -> {
+                    mAppUpdateInfo = info;
+                    mUpdateAvailability = info.updateAvailability();
+                    mInstallStatus = info.installStatus();
+                    Log.i(TAG,
+                            "pullCurrentState(" + mUpdateAvailability + ", " + mInstallStatus
+                                    + ") success.");
+                    pushStatus();
+                })
+                .addOnFailureListener(exception -> {
+                    mAppUpdateInfo = null;
+                    mUpdateAvailability = UpdateAvailability.UNKNOWN;
+                    mInstallStatus = InstallStatus.UNKNOWN;
+                    Log.i(TAG, "pullCurrentState() failed.");
+                    pushStatus();
+                });
+    }
+
+    private void pushStatus() {
+        if (!mEnabled || mUpdateAvailability == null || mInstallStatus == null) return;
+
+        @UpdateState
+        int newState = toUpdateState(mUpdateAvailability, mInstallStatus);
+        if (mUpdateState != null && mUpdateState == newState) return;
+
+        Log.i(TAG, "Pushing inline update state to " + newState);
+        mUpdateState = newState;
+        mCallback.run();
+    }
+
+    private static @UpdateState int toUpdateState(
+            @UpdateAvailability int updateAvailability, @InstallStatus int installStatus) {
+        @UpdateState
+        int newStatus = UpdateState.NONE;
+
+        // Note, use InstallStatus first then UpdateAvailability if InstallStatus doesn't indicate
+        // a currently active install.
+        switch (installStatus) {
+            case InstallStatus.PENDING:
+                // Intentional fall through.
+            case InstallStatus.DOWNLOADING:
+                newStatus = UpdateState.INLINE_UPDATE_DOWNLOADING;
+                break;
+            case InstallStatus.DOWNLOADED:
+                newStatus = UpdateState.INLINE_UPDATE_READY;
+                break;
+            case InstallStatus.FAILED:
+                newStatus = UpdateState.INLINE_UPDATE_FAILED;
+                break;
+        }
+
+        if (newStatus == UpdateState.NONE) {
+            switch (updateAvailability) {
+                case UpdateAvailability.UPDATE_AVAILABLE:
+                    newStatus = UpdateState.INLINE_UPDATE_AVAILABLE;
+                    break;
+            }
+        }
+
+        return newStatus;
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
index 39445d9..e78db5d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
@@ -31,7 +31,6 @@
 import org.chromium.base.BuildInfo;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsEnabledStateUtils;
@@ -80,7 +79,6 @@
 
     private static final String PREF_SERVICES_CATEGORY = "services_category";
     private static final String PREF_SEARCH_SUGGESTIONS = "search_suggestions";
-    private static final String PREF_NETWORK_PREDICTIONS = "network_predictions";
     private static final String PREF_NAVIGATION_ERROR = "navigation_error";
     private static final String PREF_SAFE_BROWSING = "safe_browsing";
     private static final String PREF_SAFE_BROWSING_SCOUT_REPORTING =
@@ -118,7 +116,6 @@
     private ChromeSwitchPreference mSyncRequested;
 
     private ChromeSwitchPreference mSearchSuggestions;
-    private ChromeSwitchPreference mNetworkPredictions;
     private ChromeSwitchPreference mNavigationError;
     private ChromeSwitchPreference mSafeBrowsing;
     private ChromeSwitchPreference mSafeBrowsingReporting;
@@ -169,10 +166,6 @@
         mSearchSuggestions.setOnPreferenceChangeListener(this);
         mSearchSuggestions.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        mNetworkPredictions = (ChromeSwitchPreference) findPreference(PREF_NETWORK_PREDICTIONS);
-        mNetworkPredictions.setOnPreferenceChangeListener(this);
-        mNetworkPredictions.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
         mNavigationError = (ChromeSwitchPreference) findPreference(PREF_NAVIGATION_ERROR);
         mNavigationError.setOnPreferenceChangeListener(this);
         mNavigationError.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
@@ -315,9 +308,6 @@
             mPrefServiceBridge.setSafeBrowsingEnabled((boolean) newValue);
         } else if (PREF_SAFE_BROWSING_SCOUT_REPORTING.equals(key)) {
             mPrefServiceBridge.setSafeBrowsingExtendedReportingEnabled((boolean) newValue);
-        } else if (PREF_NETWORK_PREDICTIONS.equals(key)) {
-            mPrefServiceBridge.setNetworkPredictionEnabled((boolean) newValue);
-            recordNetworkPredictionEnablingUMA((boolean) newValue);
         } else if (PREF_NAVIGATION_ERROR.equals(key)) {
             mPrefServiceBridge.setResolveNavigationErrorEnabled((boolean) newValue);
         } else if (PREF_USAGE_AND_CRASH_REPORTING.equals(key)) {
@@ -483,11 +473,6 @@
         }
     }
 
-    private void recordNetworkPredictionEnablingUMA(boolean enabled) {
-        // Report user turning on and off NetworkPrediction.
-        RecordHistogram.recordBooleanHistogram("PrefService.NetworkPredictionEnabled", enabled);
-    }
-
     private static void removePreference(PreferenceGroup from, Preference preference) {
         boolean found = from.removePreference(preference);
         assert found : "Don't have such preference! Preference key: " + preference.getKey();
@@ -497,7 +482,6 @@
         updateSyncPreferences();
 
         mSearchSuggestions.setChecked(mPrefServiceBridge.isSearchSuggestEnabled());
-        mNetworkPredictions.setChecked(mPrefServiceBridge.getNetworkPredictionEnabled());
         mNavigationError.setChecked(mPrefServiceBridge.isResolveNavigationErrorEnabled());
         mSafeBrowsing.setChecked(mPrefServiceBridge.isSafeBrowsingEnabled());
         mSafeBrowsingReporting.setChecked(
@@ -560,9 +544,6 @@
             if (PREF_SAFE_BROWSING.equals(key)) {
                 return mPrefServiceBridge.isSafeBrowsingManaged();
             }
-            if (PREF_NETWORK_PREDICTIONS.equals(key)) {
-                return mPrefServiceBridge.isNetworkPredictionManaged();
-            }
             if (PREF_USAGE_AND_CRASH_REPORTING.equals(key)) {
                 return mPrefServiceBridge.isMetricsReportingManaged();
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
index 596f0ca..5740a2ae1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -72,16 +72,33 @@
                 (ChromeBaseCheckBoxPreference) findPreference(PREF_CAN_MAKE_PAYMENT);
         canMakePaymentPref.setOnPreferenceChangeListener(this);
 
+        ChromeBaseCheckBoxPreference networkPredictionPref =
+                (ChromeBaseCheckBoxPreference) findPreference(PREF_NETWORK_PREDICTIONS);
+        networkPredictionPref.setChecked(prefServiceBridge.getNetworkPredictionEnabled());
+        networkPredictionPref.setOnPreferenceChangeListener(this);
+        networkPredictionPref.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
+
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
             // Remove preferences that were migrated to SyncAndServicesPreferences.
             preferenceScreen.removePreference(findPreference(PREF_NAVIGATION_ERROR));
             preferenceScreen.removePreference(findPreference(PREF_SEARCH_SUGGESTIONS));
             preferenceScreen.removePreference(findPreference(PREF_SAFE_BROWSING_SCOUT_REPORTING));
             preferenceScreen.removePreference(findPreference(PREF_SAFE_BROWSING));
-            preferenceScreen.removePreference(findPreference(PREF_NETWORK_PREDICTIONS));
             preferenceScreen.removePreference(findPreference(PREF_CONTEXTUAL_SEARCH));
             preferenceScreen.removePreference(findPreference(PREF_USAGE_AND_CRASH_REPORTING));
 
+            // TODO(https://crbug.com/846376): Update strings in XML after UNIFIED_CONSENT launch.
+            networkPredictionPref.setTitle(R.string.preload_pages_title);
+            networkPredictionPref.setSummary(R.string.preload_pages_summary);
+
+            // Put networkPredictionPref after canMakePaymentPref by overriding order value.
+            // However, calling setOrder doesn't change existing order if Preference has already
+            // been added to PreferenceGroup. Remove and re-add it to work around this.
+            // TODO(https://crbug.com/846376): Reorder prefs in XML after UNIFIED_CONSENT launch.
+            preferenceScreen.removePreference(networkPredictionPref);
+            networkPredictionPref.setOrder(canMakePaymentPref.getOrder());
+            preferenceScreen.addPreference(networkPredictionPref);
+
             Preference syncAndServicesLink = findPreference(PREF_SYNC_AND_SERVICES_LINK);
             NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan(view -> {
                 PreferencesLauncher.launchSettingsPage(getActivity(),
@@ -98,12 +115,6 @@
         preferenceScreen.removePreference(findPreference(PREF_SYNC_AND_SERVICES_LINK_DIVIDER));
         preferenceScreen.removePreference(findPreference(PREF_SYNC_AND_SERVICES_LINK));
 
-        ChromeBaseCheckBoxPreference networkPredictionPref =
-                (ChromeBaseCheckBoxPreference) findPreference(PREF_NETWORK_PREDICTIONS);
-        networkPredictionPref.setChecked(prefServiceBridge.getNetworkPredictionEnabled());
-        networkPredictionPref.setOnPreferenceChangeListener(this);
-        networkPredictionPref.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
         ChromeBaseCheckBoxPreference navigationErrorPref =
                 (ChromeBaseCheckBoxPreference) findPreference(PREF_NAVIGATION_ERROR);
         navigationErrorPref.setOnPreferenceChangeListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java
index 3c00faeb..7d3d038 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java
@@ -223,11 +223,20 @@
         queue.next();
     }
 
-    private Website findOrCreateSite(WebsiteAddress origin, WebsiteAddress embedder) {
-        OriginAndEmbedder key = OriginAndEmbedder.create(origin, embedder);
+    private Website findOrCreateSite(String origin, String embedder) {
+        // Avoid showing multiple entries in "All sites" for the same origin.
+        if (embedder != null && (embedder.equals(origin) || "*".equals(embedder))) {
+            embedder = null;
+        }
+
+        WebsiteAddress permissionOrigin = WebsiteAddress.create(origin);
+        WebsiteAddress permissionEmbedder = WebsiteAddress.create(embedder);
+
+        OriginAndEmbedder key = OriginAndEmbedder.create(permissionOrigin, permissionEmbedder);
+
         Website site = mSites.get(key);
         if (site == null) {
-            site = new Website(origin, embedder);
+            site = new Website(permissionOrigin, permissionEmbedder);
             mSites.put(key, site);
         }
         return site;
@@ -251,7 +260,7 @@
                 WebsitePreferenceBridge.getContentSettingsExceptions(contentSettingsType)) {
             // The pattern "*" represents the default setting, not a specific website.
             if (exception.getPattern().equals("*")) continue;
-            WebsiteAddress address = WebsiteAddress.create(exception.getPattern());
+            String address = exception.getPattern();
             if (address == null) continue;
             Website site = findOrCreateSite(address, null);
             site.setContentSettingException(exceptionType, exception);
@@ -296,11 +305,9 @@
         @Override
         public void run() {
             for (PermissionInfo info : WebsitePreferenceBridge.getPermissionInfo(mType)) {
-                WebsiteAddress origin = WebsiteAddress.create(info.getOrigin());
+                String origin = info.getOrigin();
                 if (origin == null) continue;
-                WebsiteAddress embedder = mType == PermissionInfo.Type.SENSORS
-                        ? null
-                        : WebsiteAddress.create(info.getEmbedder());
+                String embedder = mType == PermissionInfo.Type.SENSORS ? null : info.getEmbedder();
                 findOrCreateSite(origin, embedder).setPermissionInfo(info);
             }
         }
@@ -311,10 +318,9 @@
         public void run() {
             for (ChosenObjectInfo info : WebsitePreferenceBridge.getChosenObjectInfo(
                          ContentSettingsType.CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA)) {
-                WebsiteAddress origin = WebsiteAddress.create(info.getOrigin());
+                String origin = info.getOrigin();
                 if (origin == null) continue;
-                WebsiteAddress embedder = WebsiteAddress.create(info.getEmbedder());
-                findOrCreateSite(origin, embedder).addChosenObjectInfo(info);
+                findOrCreateSite(origin, info.getEmbedder()).addChosenObjectInfo(info);
             }
         }
     }
@@ -342,7 +348,7 @@
                         @SuppressWarnings("unchecked")
                         Map.Entry<String, LocalStorageInfo> entry =
                                 (Map.Entry<String, LocalStorageInfo>) o;
-                        WebsiteAddress address = WebsiteAddress.create(entry.getKey());
+                        String address = entry.getKey();
                         if (address == null) continue;
                         findOrCreateSite(address, null).setLocalStorageInfo(entry.getValue());
                     }
@@ -362,7 +368,7 @@
                     ArrayList<StorageInfo> infoArray = result;
 
                     for (StorageInfo info : infoArray) {
-                        WebsiteAddress address = WebsiteAddress.create(info.getHost());
+                        String address = info.getHost();
                         if (address == null) continue;
                         findOrCreateSite(address, null).addStorageInfo(info);
                     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
new file mode 100644
index 0000000..3d4cf63
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -0,0 +1,13 @@
+noparent = True
+
+specific_include_rules = {
+  'Tab\.java': [
+    "-chrome",
+    "+chrome/android/java/src/org/chromium/chrome/browser/tab",
+    "+components/embedder_support/android/java/src/org/chromium/components/embedder_support/view",
+    "+components/navigation_interception/android/java/src/org/chromium/components/navigation_interception",
+    "+content/public/android/java/src/org/chromium/content_public",
+    "+ui/android/java/src/org/chromium/ui/base",
+    "+ui/android/java/src/org/chromium/ui/mojom",
+  ],
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 4ea727f0..49b95cc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -19,15 +19,10 @@
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 import android.view.ContextThemeWrapper;
-import android.view.Gravity;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.PopupWindow;
-import android.widget.PopupWindow.OnDismissListener;
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
@@ -38,7 +33,6 @@
 import org.chromium.base.UserDataHost;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.ChromeActionModeCallback;
@@ -59,7 +53,6 @@
 import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
-import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
@@ -84,13 +77,8 @@
 import org.chromium.chrome.browser.tabmodel.TabReparentingParams;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
-import org.chromium.chrome.browser.widget.PulseDrawable;
-import org.chromium.chrome.browser.widget.textbubble.TextBubble;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
 import org.chromium.components.embedder_support.view.ContentView;
-import org.chromium.components.feature_engagement.EventConstants;
-import org.chromium.components.feature_engagement.FeatureConstants;
-import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.ChildProcessImportance;
@@ -99,7 +87,6 @@
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.SelectionPopupController;
-import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsAccessibility;
 import org.chromium.content_public.common.BrowserControlsState;
@@ -109,7 +96,6 @@
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.mojom.WindowOpenDisposition;
-import org.chromium.ui.widget.AnchoredPopupWindow;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -341,16 +327,6 @@
      */
     private boolean mIsDetached;
 
-    /**
-     * The Text bubble used to display In Product help widget for download feature on videos.
-     */
-    private TextBubble mDownloadIPHBubble;
-
-    /**
-     * The popup used to display the pulse around the download button on videos.
-     */
-    private PopupWindow mPulsePopupWindow;
-
     /** Whether or not the tab closing the tab can send the user back to the app that opened it. */
     private boolean mIsAllowedToReturnToExternalApp;
 
@@ -1605,8 +1581,6 @@
         for (TabObserver observer : mObservers) observer.onDestroyed(this);
         mObservers.clear();
 
-        hideMediaDownloadInProductHelp();
-
         mUserDataHost.destroy();
 
         NativePage currentNativePage = mNativePage;
@@ -2752,13 +2726,6 @@
     }
 
     /**
-     * Called when the orientation of the activity has changed.
-     */
-    public void onOrientationChange() {
-        hideMediaDownloadInProductHelp();
-    }
-
-    /**
      * Handle browser controls when a tab modal dialog is shown.
      * @param isShowing Whether a tab modal dialog is showing.
      */
@@ -2773,83 +2740,6 @@
         return nativeAreRendererInputEventsIgnored(mNativeTabAndroid);
     }
 
-    @CalledByNative
-    private void showMediaDownloadInProductHelp(int x, int y, int width, int height) {
-        Rect rect = new Rect(x, y, x + width, y + height);
-
-        // If we are not currently showing the widget, ask the tracker if we can show it.
-        if (mDownloadIPHBubble == null) {
-            Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile());
-            tracker.notifyEvent(EventConstants.MEDIA_DOWNLOAD_BUTTON_DISPLAYED);
-            if (!tracker.shouldTriggerHelpUI(FeatureConstants.MEDIA_DOWNLOAD_FEATURE)) {
-                // Inform native that the button was dismissed to notify the renderer that the
-                // request was rejected.
-                nativeMediaDownloadInProductHelpDismissed(mNativeTabAndroid);
-                return;
-            }
-
-            mDownloadIPHBubble = new TextBubble(getApplicationContext(), mContentView,
-                    R.string.iph_media_download_text,
-                    R.string.iph_media_download_accessibility_text, rect);
-            mDownloadIPHBubble.setDismissOnTouchInteraction(true);
-            mDownloadIPHBubble.addOnDismissListener(new OnDismissListener() {
-                @Override
-                public void onDismiss() {
-                    PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
-                        @Override
-                        public void run() {
-                            hideMediaDownloadInProductHelp();
-                        }
-                    });
-                }
-            });
-        }
-
-        mDownloadIPHBubble.setPreferredVerticalOrientation(
-                AnchoredPopupWindow.VerticalOrientation.BELOW);
-        mDownloadIPHBubble.show();
-        createPulse(rect);
-    }
-
-    private void createPulse(Rect rect) {
-        if (mPulsePopupWindow == null) {
-            PulseDrawable pulseDrawable = PulseDrawable.createCircle(mThemedApplicationContext);
-            View view = new Button(getActivity());
-            view.setLayoutParams(new FrameLayout.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
-            view.setBackground(pulseDrawable);
-
-            mPulsePopupWindow = new PopupWindow(getActivity());
-            mPulsePopupWindow.setBackgroundDrawable(null);
-            mPulsePopupWindow.setContentView(view);
-            mPulsePopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
-            mPulsePopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
-            mPulsePopupWindow.getContentView().setOnClickListener(
-                    v -> hideMediaDownloadInProductHelp());
-            mPulsePopupWindow.showAtLocation(
-                    getView(), Gravity.TOP | Gravity.START, rect.left, rect.top);
-            pulseDrawable.start();
-        }
-
-        mPulsePopupWindow.update(rect.left, rect.top, rect.width(), rect.height());
-    }
-
-    @CalledByNative
-    private void hideMediaDownloadInProductHelp() {
-        if (mPulsePopupWindow != null && mPulsePopupWindow.isShowing()) {
-            mPulsePopupWindow.dismiss();
-            mPulsePopupWindow = null;
-        }
-
-        if (mDownloadIPHBubble == null) return;
-
-        mDownloadIPHBubble.dismiss();
-        mDownloadIPHBubble = null;
-        Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile());
-        tracker.dismissed(FeatureConstants.MEDIA_DOWNLOAD_FEATURE);
-        nativeMediaDownloadInProductHelpDismissed(mNativeTabAndroid);
-    }
-
     /**
      * @return The publisher URL if the current page is hosted on a trusted CDN, or null otherwise.
      */
@@ -2900,6 +2790,5 @@
     private native void nativeSetPictureInPictureEnabled(long nativeTabAndroid, boolean enabled);
     private native void nativeEnableEmbeddedMediaExperience(long nativeTabAndroid, boolean enabled);
     private native void nativeAttachDetachedTab(long nativeTabAndroid);
-    private native void nativeMediaDownloadInProductHelpDismissed(long nativeTabAndroid);
     private native boolean nativeAreRendererInputEventsIgnored(long nativeTabAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelector.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelector.java
index bf83bce..d77379b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelector.java
@@ -7,6 +7,7 @@
 import android.support.annotation.Nullable;
 
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.LoadUrlParams;
 
@@ -158,6 +159,13 @@
     void setCloseAllTabsDelegate(CloseAllTabsDelegate delegate);
 
     /**
+     * Sets the {@link OverviewModeBehavior} that should be used to determine
+     * when the app is in overview mode or not.
+     * @param overviewModeBehavior The {@link OverviewModeBehavior} to use.
+     */
+    void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior);
+
+    /**
      * @return Whether the tab state for this {@link TabModelSelector} has been initialized.
      */
     boolean isTabStateInitialized();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
index a39156c..7f68ce4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.tabmodel;
 
 import org.chromium.base.ObserverList;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.tab.Tab;
 
 import java.util.ArrayList;
@@ -217,6 +218,9 @@
     }
 
     @Override
+    public void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {}
+
+    @Override
     public void destroy() {
         for (int i = 0; i < getModels().size(); i++) getModelAt(i).destroy();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
index 9326962..70868eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -102,11 +102,7 @@
         if (tab != null) mTabSaver.addTabToSaveQueue(tab);
     }
 
-    /**
-     *
-     * @param overviewModeBehavior The {@link OverviewModeBehavior} that should be used to determine
-     *                             when the app is in overview mode or not.
-     */
+    @Override
     public void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
         assert overviewModeBehavior != null;
         mOverviewModeBehavior = overviewModeBehavior;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/GridTabSwitcherMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/GridTabSwitcherMediator.java
index 52e3b85b..62147bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/GridTabSwitcherMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/GridTabSwitcherMediator.java
@@ -64,6 +64,8 @@
         };
         mTabModelSelector.addObserver(mTabModelSelectorObserver);
 
+        mTabModelSelector.setOverviewModeBehavior(this);
+
         mTabModelObserver = new TabModelSelectorTabModelObserver(mTabModelSelector) {
 
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java
index eef5dd8..297ccfc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java
@@ -121,6 +121,7 @@
 
             @Override
             public void didCloseTab(int tabId, boolean incognito) {
+                if (mModel.indexFromId(tabId) == TabModel.INVALID_TAB_INDEX) return;
                 mModel.removeAt(mModel.indexFromId(tabId));
             }
         };
@@ -168,14 +169,14 @@
                         .build();
         mModel.add(tabInfo);
         mFaviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile().getOriginalProfile(),
-                tab.getUrl(), mFaviconSize,
-                (image, iconUrl)
-                        -> mModel.get(mModel.indexFromId(tab.getId()))
-                                   .set(TabProperties.FAVICON, image));
-        mTabContentManager.getTabThumbnailWithCallback(tab,
-                result
-                -> mModel.get(mModel.indexFromId(tab.getId()))
-                           .set(TabProperties.THUMBNAIL_KEY, result));
+                tab.getUrl(), mFaviconSize, (image, iconUrl) -> {
+                    if (mModel.indexFromId(tab.getId()) == Tab.INVALID_TAB_ID) return;
+                    mModel.get(mModel.indexFromId(tab.getId())).set(TabProperties.FAVICON, image);
+                });
+        mTabContentManager.getTabThumbnailWithCallback(tab, result -> {
+            if (mModel.indexFromId(tab.getId()) == Tab.INVALID_TAB_ID) return;
+            mModel.get(mModel.indexFromId(tab.getId())).set(TabProperties.THUMBNAIL_KEY, result);
+        });
         tab.addObserver(mTabObserver);
     }
 }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 30b8e30b..a29fea8 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3867,12 +3867,6 @@
       <message name="IDS_IPH_DATA_SAVER_DETAIL_ACCESSIBILITY_TEXT" desc="The in-product-help accessibility text to open data saver.">
         See how much data you've saved from the More Options button
       </message>
-      <message name="IDS_IPH_MEDIA_DOWNLOAD_TEXT" desc="The in-product-help message to download a video.">
-        Download videos to watch later
-      </message>
-      <message name="IDS_IPH_MEDIA_DOWNLOAD_ACCESSIBILITY_TEXT" desc="The in-product-help accessibility text to download a video.">
-        Download videos to watch later using the Download button
-      </message>
       <message name="IDS_IPH_PREVIEWS_OMNIBOX_UI_TEXT" desc="The in-product-help text informing the user that the displayed page was modified to make it load faster or use less data. Prompts the user to tap the message and load the original, unaltered, page if they would like. The 'Lite page provided by Google.' sentence should match TC ID 373879247902731825">
         Lite page provided by Google. Tap to load the original.
       </message>
@@ -3886,7 +3880,6 @@
         Translate this page to any language from the More options button
       </message>
 
-
       <!-- Search Widget strings -->
       <message name="IDS_SEARCH_WIDGET_DEFAULT" desc="Default text for the search widget">
         Search
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 8e9cad9..0e0f07d6 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1108,8 +1108,10 @@
   "java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchPrefs.java",
   "java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchedPagesNotifier.java",
   "java/src/org/chromium/chrome/browser/omaha/inline/FakeAppUpdateManagerWrapper.java",
-  "java/src/org/chromium/chrome/browser/omaha/inline/InlineAppUpdateManagerFactory.java",
   "java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateController.java",
+  "java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java",
+  "java/src/org/chromium/chrome/browser/omaha/inline/NoopInlineUpdateController.java",
+  "java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java",
   "java/src/org/chromium/chrome/browser/omaha/ExponentialBackoffScheduler.java",
   "java/src/org/chromium/chrome/browser/omaha/MarketURLGetter.java",
   "java/src/org/chromium/chrome/browser/omaha/OmahaBase.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java
index 10e80fb..660918c8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java
@@ -384,4 +384,29 @@
         RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI,
                 "file_url_emphasis_browser_ui", mRenderTestRule);
     }
+
+    /**
+     * Tests that the reposition bar does not appear if the keyboard is open.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Browser", "RenderTest"})
+    public void testRepositionBarDoesNotAppearWithKeyboardOpen()
+            throws InterruptedException, TimeoutException, IOException {
+        // Use the mock keyboard so it doesn't show, reducing the chance of flakes due to AA.
+        NativeUiUtils.enableMockedKeyboard();
+        mVrTestRule.loadUrl(
+                VrBrowserTestFramework.getFileUrlForHtmlTestFile("generic_text_entry_page"),
+                PAGE_LOAD_TIMEOUT_S);
+        NativeUiUtils.clickContentNode(
+                "textfield", new PointF(), 1 /* numClicks */, mVrBrowserTestFramework);
+        NativeUiUtils.waitForUiQuiescence();
+        NativeUiUtils.hoverElement(UserFriendlyElementName.CONTENT_QUAD, new PointF(0.0f, 0.55f));
+        NativeUiUtils.waitForUiQuiescence();
+        // Due to the way the repositioner works, the reposition bar is technically always visible
+        // in the element hierarchy, so we can't just assert that it's invisible. Instead, we have
+        // to resort to pixel diffing.
+        RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI,
+                "reposition_bar_keyboard_open", mRenderTestRule);
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java
index d796930c..4a21ed59 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java
@@ -10,6 +10,8 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.os.SystemClock;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -18,7 +20,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowSystemClock;
 
 import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -371,13 +372,13 @@
         mTimer = createPageViewTimer();
         switchTabs(null, mTab);
         showContentRunnable.run();
-        ShadowSystemClock.sleep(SAMPLE_PAGE_VIEW_TIME);
+        SystemClock.sleep(SAMPLE_PAGE_VIEW_TIME);
         if (pauseRunnable != null && resumeRunnable != null) {
             expectedTime += SAMPLE_PAGE_VIEW_TIME;
             pauseRunnable.run();
-            ShadowSystemClock.sleep(SAMPLE_PAGE_VIEW_TIME);
+            SystemClock.sleep(SAMPLE_PAGE_VIEW_TIME);
             resumeRunnable.run();
-            ShadowSystemClock.sleep(SAMPLE_PAGE_VIEW_TIME);
+            SystemClock.sleep(SAMPLE_PAGE_VIEW_TIME);
         }
         stopTimerRunnable.run();
         assertEquals(expectedSamples,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedbackCollectorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedbackCollectorTest.java
index eaecdf9..2a8d3b9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedbackCollectorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedbackCollectorTest.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 import android.util.Pair;
@@ -166,7 +167,7 @@
 
             mDone = true;
             mBitmap = bitmap;
-            new Handler(ShadowLooper.getMainLooper()).post(mCallback);
+            new Handler(Looper.getMainLooper()).post(mCallback);
         }
     }
 
@@ -226,7 +227,7 @@
             assertNotEquals(null, mCallback);
 
             mDone = true;
-            new Handler(ShadowLooper.getMainLooper()).post(mCallback);
+            new Handler(Looper.getMainLooper()).post(mCallback);
         }
     }
 
@@ -266,7 +267,7 @@
 
     @Before
     public void setUp() {
-        ThreadUtils.setUiThread(ShadowLooper.getMainLooper());
+        ThreadUtils.setUiThread(Looper.getMainLooper());
     }
 
     @After
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java
index 19295572..c95788f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java
@@ -11,6 +11,8 @@
 
 import static org.chromium.chrome.browser.fullscreen.BrowserStateBrowserControlsVisibilityDelegate.MINIMUM_SHOW_DURATION_MS;
 
+import android.os.SystemClock;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -18,7 +20,6 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowLooper;
-import org.robolectric.shadows.ShadowSystemClock;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
@@ -41,7 +42,7 @@
     }
 
     private void advanceTime(long amount) {
-        ShadowSystemClock.setCurrentTimeMillis(ShadowSystemClock.elapsedRealtime() + amount);
+        SystemClock.setCurrentTimeMillis(SystemClock.elapsedRealtime() + amount);
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderTest.java
index 46c8198..88ff7b3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderTest.java
@@ -137,7 +137,7 @@
         ShadowPackageManager packageManager =
                 Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager());
         packageManager.addPackage(packageInfo);
-        packageManager.resources.put(packageInfo.packageName, resources);
+        ShadowPackageManager.resources.put(packageInfo.packageName, resources);
     }
 
     /**
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTrackerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTrackerTest.java
index 228fed86..b22816c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTrackerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTrackerTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
+import android.os.SystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -83,7 +84,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        ShadowSystemClock.setCurrentTimeMillis(CURRENT_TIME_MS);
+        SystemClock.setCurrentTimeMillis(CURRENT_TIME_MS);
         ShadowPlatformNetworksManager.sAllVisibleNetworks = new LinkedList<>(
                 Arrays.asList(FIRST_ALL_VISIBLE_NETWORKS, SECOND_ALL_VISIBLE_NETWORKS));
         ShadowPlatformNetworksManager.sOnlyConnectedNetworks = new LinkedList<>(
@@ -122,7 +123,7 @@
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
 
         // Time to consider the first cached networks still as valid.
-        ShadowSystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_UNDER_THRESHOLD_TIME_MS);
+        SystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_UNDER_THRESHOLD_TIME_MS);
         visibleNetworks = VisibleNetworksTracker.getLastKnownVisibleNetworks(sContext);
 
         assertEquals(FIRST_ALL_VISIBLE_NETWORKS, visibleNetworks);
@@ -140,7 +141,7 @@
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
 
         // Time to consider the first cached networks as invalid. Should fetch the second ones.
-        ShadowSystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_OVER_THRESHOLD_TIME_MS);
+        SystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_OVER_THRESHOLD_TIME_MS);
         visibleNetworks = VisibleNetworksTracker.getLastKnownVisibleNetworks(sContext);
 
         assertEquals(SECOND_ONLY_CONNECTED_NETWORKS, visibleNetworks);
@@ -172,7 +173,7 @@
         assertEquals(CURRENT_TIME_MS, VisibleNetworksTracker.getCachedVisibleNetworksTime());
 
         // Time to consider the first cached networks still as valid, refresh should be a noop.
-        ShadowSystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_UNDER_THRESHOLD_TIME_MS);
+        SystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_UNDER_THRESHOLD_TIME_MS);
         VisibleNetworksTracker.refreshVisibleNetworks(sContext);
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
 
@@ -188,7 +189,7 @@
         assertEquals(CURRENT_TIME_MS, VisibleNetworksTracker.getCachedVisibleNetworksTime());
 
         // Time to consider the first cached networks as invalid. Should fetch the second ones.
-        ShadowSystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_OVER_THRESHOLD_TIME_MS);
+        SystemClock.setCurrentTimeMillis(CURRENT_TIME_MS + ELAPSED_OVER_THRESHOLD_TIME_MS);
         VisibleNetworksTracker.refreshVisibleNetworks(sContext);
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/page_info/PermissionParamsListBuilderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/page_info/PermissionParamsListBuilderUnitTest.java
index 1b1a4f60..3936edfc 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/page_info/PermissionParamsListBuilderUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/page_info/PermissionParamsListBuilderUnitTest.java
@@ -72,9 +72,6 @@
         assertEquals(1, params.size());
         PageInfoView.PermissionParams permissionParams = params.get(0);
 
-        assertEquals(context.getDrawable(R.drawable.permission_cookie),
-                context.getDrawable(permissionParams.iconResource));
-
         String expectedStatus = "Foo – " + context.getString(R.string.page_info_permission_allowed);
         assertEquals(expectedStatus, permissionParams.status.toString());
 
@@ -211,4 +208,4 @@
             return mIntentOverride;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
index fa5c2f0..e37a9e1 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -24,7 +24,6 @@
 import org.mockito.Mockito;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
-import org.robolectric.shadows.ShadowBitmap;
 import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -301,7 +300,7 @@
      */
     private static Bitmap createBitmap(int color) {
         int colors[] = {color};
-        return ShadowBitmap.createBitmap(colors, 1, 1, Bitmap.Config.ALPHA_8);
+        return Bitmap.createBitmap(colors, 1, 1, Bitmap.Config.ALPHA_8);
     }
 
     private static void updateIfNeeded(WebApkUpdateManager updateManager) {
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 0c43c470..041f9b51 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-74.0.3706.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-74.0.3709.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
diff --git a/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/MainActivityTest.java b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/MainActivityTest.java
index 89de8bd..ff79fe2 100644
--- a/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/MainActivityTest.java
+++ b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/MainActivityTest.java
@@ -8,6 +8,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Bundle;
@@ -21,7 +22,6 @@
 import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
-import org.robolectric.shadows.ShadowPackageManager;
 
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.chromium.webapk.lib.common.WebApkConstants;
@@ -37,12 +37,12 @@
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, packageName = WebApkUtilsTest.WEBAPK_PACKAGE_NAME)
 public final class MainActivityTest {
-    private ShadowPackageManager mPackageManager;
+    private PackageManager mPackageManager;
     private static final String BROWSER_PACKAGE_NAME = "com.android.chrome";
 
     @Before
     public void setUp() {
-        mPackageManager = Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager());
+        mPackageManager = RuntimeEnvironment.application.getPackageManager();
         installBrowser(BROWSER_PACKAGE_NAME);
     }
 
diff --git a/chrome/android/webapk/test/src/org/chromium/webapk/test/WebApkTestHelper.java b/chrome/android/webapk/test/src/org/chromium/webapk/test/WebApkTestHelper.java
index 832fefd..21c697f 100644
--- a/chrome/android/webapk/test/src/org/chromium/webapk/test/WebApkTestHelper.java
+++ b/chrome/android/webapk/test/src/org/chromium/webapk/test/WebApkTestHelper.java
@@ -37,7 +37,7 @@
         ShadowPackageManager packageManager =
                 Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager());
         Resources res = Mockito.mock(Resources.class);
-        packageManager.resources.put(packageName, res);
+        ShadowPackageManager.resources.put(packageName, res);
 
         Intent shareIntent = new Intent();
         shareIntent.setAction(Intent.ACTION_SEND);
@@ -84,7 +84,7 @@
     public static void setResource(String packageName, Resources res) {
         ShadowPackageManager packageManager =
                 Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager());
-        packageManager.resources.put(packageName, res);
+        ShadowPackageManager.resources.put(packageName, res);
     }
 
     private static PackageInfo newPackageInfo(String packageName, Bundle metaData,
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index e32ae57..4eb0aa1 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -43,7 +43,6 @@
 #include "services/preferences/public/cpp/manifest.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
 #include "third_party/blink/public/platform/input_host.mojom.h"
-#include "third_party/blink/public/platform/media_download_in_product_help.mojom.h"
 #include "third_party/blink/public/platform/modules/badging/badging.mojom.h"
 #include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.h"
 #include "third_party/blink/public/platform/modules/installedapp/installed_app_provider.mojom.h"
@@ -200,7 +199,6 @@
                     autofill::mojom::PasswordManagerDriver,
                     blink::mojom::BadgeService, blink::mojom::CredentialManager,
                     blink::mojom::InstalledAppProvider,
-                    blink::mojom::MediaDownloadInProductHelp,
                     blink::mojom::ShareService,
                     blink::mojom::TextSuggestionHost,
                     chrome::mojom::OfflinePageAutoFetcher,
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 97771c1..5f64ab7e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -3543,6 +3543,9 @@
   </message>
 
   <!-- Crostini export and import -->
+  <message name="IDS_CROSTINI_NOTIFICATION_OPERATION_STARTING" desc="Message to display in a notification when the operation is starting and we don't yet have an estimate for how long it will take">
+    Starting...
+  </message>
   <message name="IDS_CROSTINI_EXPORT_TITLE" desc="Title for exporting (backing up) the crostini container.">
     Backup
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 36a0ef1..5fc7de7 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1296,6 +1296,8 @@
     "prerender/prerender_tab_helper.h",
     "prerender/prerender_util.cc",
     "prerender/prerender_util.h",
+    "previews/previews_content_util.cc",
+    "previews/previews_content_util.h",
     "previews/previews_infobar_delegate.cc",
     "previews/previews_infobar_delegate.h",
     "previews/previews_lite_page_decider.cc",
@@ -1820,6 +1822,7 @@
     "//chrome/browser/ssl:proto",
     "//chrome/browser/ui",
     "//chrome/browser/ui/webui/bluetooth_internals",
+    "//chrome/common:channel_info",
     "//chrome/common/net",
     "//chrome/installer/util:with_no_strings",
     "//chrome/services/noop/public/cpp",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 3b916814..6bac037a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -365,14 +365,18 @@
      switches::kForceUpdateMenuType, "update_available"},
     {flag_descriptions::kUpdateMenuTypeUnsupportedOSVersion,
      switches::kForceUpdateMenuType, "unsupported_os_version"},
-    {flag_descriptions::kUpdateMenuTypeInlineUpdateAvailable,
-     switches::kForceUpdateMenuType, "inline_update_available"},
-    {flag_descriptions::kUpdateMenuTypeInlineUpdateDownloading,
-     switches::kForceUpdateMenuType, "inline_update_downloading"},
-    {flag_descriptions::kUpdateMenuTypeInlineUpdateReady,
-     switches::kForceUpdateMenuType, "inline_update_ready"},
-    {flag_descriptions::kUpdateMenuTypeInlineUpdateFailed,
-     switches::kForceUpdateMenuType, "inline_update_failed"},
+    {flag_descriptions::kUpdateMenuTypeInlineUpdateSuccess,
+     switches::kForceUpdateMenuType, "inline_update_success"},
+    {flag_descriptions::kUpdateMenuTypeInlineUpdateDialogCanceled,
+     switches::kForceUpdateMenuType, "inline_update_dialog_canceled"},
+    {flag_descriptions::kUpdateMenuTypeInlineUpdateDialogFailed,
+     switches::kForceUpdateMenuType, "inline_update_dialog_failed"},
+    {flag_descriptions::kUpdateMenuTypeInlineUpdateDownloadFailed,
+     switches::kForceUpdateMenuType, "inline_update_download_failed"},
+    {flag_descriptions::kUpdateMenuTypeInlineUpdateDownloadCanceled,
+     switches::kForceUpdateMenuType, "inline_update_download_canceled"},
+    {flag_descriptions::kUpdateMenuTypeInlineUpdateInstallFailed,
+     switches::kForceUpdateMenuType, "inline_update_install_failed"},
 };
 
 const FeatureEntry::FeatureParam kCCTModuleCache_ZeroMinutes[] = {
@@ -1376,14 +1380,6 @@
     {"harmony-await-optimization", flag_descriptions::kAwaitOptimizationName,
      flag_descriptions::kAwaitOptimizationDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kAwaitOptimization)},
-    {"disable-software-rasterizer", flag_descriptions::kSoftwareRasterizerName,
-     flag_descriptions::kSoftwareRasterizerDescription,
-#if BUILDFLAG(ENABLE_SWIFTSHADER)
-     kOsAll,
-#else   // BUILDFLAG(ENABLE_SWIFTSHADER)
-     0,
-#endif  // BUILDFLAG(ENABLE_SWIFTSHADER)
-     SINGLE_DISABLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)},
     {"enable-gpu-rasterization", flag_descriptions::kGpuRasterizationName,
      flag_descriptions::kGpuRasterizationDescription, kOsAll,
      MULTI_VALUE_TYPE(kEnableGpuRasterizationChoices)},
@@ -1653,10 +1649,6 @@
     {"trace-upload-url", flag_descriptions::kTraceUploadUrlName,
      flag_descriptions::kTraceUploadUrlDescription, kOsAll,
      MULTI_VALUE_TYPE(kTraceUploadURL)},
-    {"enable-service-worker-servicification",
-     flag_descriptions::kServiceWorkerServicificationName,
-     flag_descriptions::kServiceWorkerServicificationDescription, kOsAll,
-     FEATURE_VALUE_TYPE(blink::features::kServiceWorkerServicification)},
     {"enable-suggestions-with-substring-match",
      flag_descriptions::kSuggestionsWithSubStringMatchName,
      flag_descriptions::kSuggestionsWithSubStringMatchDescription, kOsAll,
@@ -1905,9 +1897,6 @@
     {"crostini-backup", flag_descriptions::kCrostiniBackupName,
      flag_descriptions::kCrostiniBackupDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kCrostiniBackup)},
-    {"crostini-files", flag_descriptions::kCrostiniFilesName,
-     flag_descriptions::kCrostiniFilesDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(chromeos::features::kCrostiniFiles)},
 #endif  // OS_CHROMEOS
 #if defined(OS_ANDROID)
     {"enable-credit-card-assist", flag_descriptions::kCreditCardAssistName,
@@ -3854,13 +3843,6 @@
      flag_descriptions::kSyncStandaloneTransportDescription, kOsAll,
      FEATURE_VALUE_TYPE(switches::kSyncStandaloneTransport)},
 
-#if defined(OS_CHROMEOS)
-    {"enable-chromevox-developer-option",
-     flag_descriptions::kEnableChromevoxDeveloperOptionName,
-     flag_descriptions::kEnableChromevoxDeveloperOptionDescription, kOsCrOS,
-     SINGLE_VALUE_TYPE(chromeos::switches::kEnableChromevoxDeveloperOption)},
-#endif
-
     {"sync-USS-autofill-profile",
      flag_descriptions::kSyncUSSAutofillProfileName,
      flag_descriptions::kSyncUSSAutofillProfileDescription, kOsAll,
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS
index 3820fc1..da3492b9 100644
--- a/chrome/browser/android/DEPS
+++ b/chrome/browser/android/DEPS
@@ -9,7 +9,6 @@
   "+sandbox/linux/seccomp-bpf-helpers",
   "+sandbox/sandbox_buildflags.h",
   "+third_party/gvr-android-sdk",
-  "+third_party/blink/public/platform/media_download_in_product_help.mojom.h",
   "+third_party/blink/public/platform/unhandled_tap_notifier.mojom.h",
 ]
 
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index bf300117..fdf0c29e 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -131,6 +131,7 @@
     &kHorizontalTabSwitcherAndroid,
     &kImprovedA2HS,
     &kInflateToolbarOnBackgroundThread,
+    &kInlineUpdateFlow,
     &kIntentBlockExternalFormRedirectsNoGesture,
     &kJellyBeanSupported,
     &kLanguagesPreference,
@@ -364,6 +365,9 @@
 const base::Feature kInflateToolbarOnBackgroundThread{
     "BackgroundToolbarInflation", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kInlineUpdateFlow{"InlineUpdateFlow",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kIntentBlockExternalFormRedirectsNoGesture{
     "IntentBlockExternalFormRedirectsNoGesture",
     base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index ae57167..91526e0 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -61,6 +61,7 @@
 extern const base::Feature kHorizontalTabSwitcherAndroid;
 extern const base::Feature kImprovedA2HS;
 extern const base::Feature kInflateToolbarOnBackgroundThread;
+extern const base::Feature kInlineUpdateFlow;
 extern const base::Feature kIntentBlockExternalFormRedirectsNoGesture;
 extern const base::Feature kJellyBeanSupported;
 extern const base::Feature kLanguagesPreference;
diff --git a/chrome/browser/android/explore_sites/explore_sites_feature.cc b/chrome/browser/android/explore_sites/explore_sites_feature.cc
index d477cef..42e55ecc 100644
--- a/chrome/browser/android/explore_sites/explore_sites_feature.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_feature.cc
@@ -16,6 +16,7 @@
 
 const char kExploreSitesVariationExperimental[] = "experiment";
 const char kExploreSitesVariationPersonalized[] = "personalized";
+const char kExploreSitesVariationCondensed[] = "condensed";
 
 ExploreSitesVariation GetExploreSitesVariation() {
   if (base::FeatureList::IsEnabled(kExploreSites)) {
@@ -29,6 +30,11 @@
         kExploreSitesVariationPersonalized) {
       return ExploreSitesVariation::PERSONALIZED;
     }
+    if (base::GetFieldTrialParamValueByFeature(
+            kExploreSites, kExploreSitesVariationParameterName) ==
+        kExploreSitesVariationCondensed) {
+      return ExploreSitesVariation::CONDENSED;
+    }
     return ExploreSitesVariation::ENABLED;
   }
   return ExploreSitesVariation::DISABLED;
diff --git a/chrome/browser/android/explore_sites/explore_sites_feature.h b/chrome/browser/android/explore_sites/explore_sites_feature.h
index c85f2fb..1080208 100644
--- a/chrome/browser/android/explore_sites/explore_sites_feature.h
+++ b/chrome/browser/android/explore_sites/explore_sites_feature.h
@@ -20,6 +20,7 @@
   ENABLED,
   EXPERIMENT,
   PERSONALIZED,
+  CONDENSED,
   DISABLED
 };
 
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 43cb179..a521688 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -51,8 +51,6 @@
 #include "components/bookmarks/managed/managed_bookmark_service.h"
 #include "components/dom_distiller/core/url_utils.h"
 #include "components/favicon/content/content_favicon_driver.h"
-#include "components/feature_engagement/public/feature_constants.h"
-#include "components/feature_engagement/public/feature_list.h"
 #include "components/navigation_interception/intercept_navigation_delegate.h"
 #include "components/navigation_interception/navigation_params.h"
 #include "components/sessions/content/content_live_tab.h"
@@ -71,15 +69,12 @@
 #include "content/public/browser/web_contents_user_data.h"
 #include "content/public/common/resource_request_body_android.h"
 #include "jni/Tab_jni.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/escape.h"
-#include "services/service_manager/public/cpp/bind_source_info.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
-#include "ui/base/layout.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/display/display.h"
@@ -161,42 +156,6 @@
 
 }  // namespace
 
-// This class is created and owned by the MediaDownloadInProductHelpManager.
-class TabAndroid::MediaDownloadInProductHelp
-    : public blink::mojom::MediaDownloadInProductHelp {
- public:
-  MediaDownloadInProductHelp(
-      content::RenderFrameHost* render_frame_host,
-      TabAndroid* tab,
-      blink::mojom::MediaDownloadInProductHelpRequest request)
-      : render_frame_host_(render_frame_host),
-        tab_(tab),
-        binding_(this, std::move(request)) {
-    DCHECK(render_frame_host_);
-    DCHECK(tab_);
-
-    binding_.set_connection_error_handler(
-        base::BindOnce(&TabAndroid::OnMediaDownloadInProductHelpConnectionError,
-                       base::Unretained(tab_)));
-  }
-  ~MediaDownloadInProductHelp() override = default;
-
-  // blink::mojom::MediaPromoUI implementation.
-  void ShowInProductHelpWidget(const gfx::Rect& rect) override {
-    tab_->ShowMediaDownloadInProductHelp(rect);
-  }
-
-  content::RenderFrameHost* render_frame_host() const {
-    return render_frame_host_;
-  }
-
- private:
-  // The |manager_| and |render_frame_host_| outlive this class.
-  content::RenderFrameHost* const render_frame_host_;
-  TabAndroid* const tab_;
-  mojo::Binding<blink::mojom::MediaDownloadInProductHelp> binding_;
-};
-
 TabAndroid* TabAndroid::FromWebContents(
     const content::WebContents* web_contents) {
   return TabAndroidHelper::FromWebContents(web_contents);
@@ -219,12 +178,8 @@
       tab_content_manager_(nullptr),
       synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)),
       picture_in_picture_enabled_(false),
-      embedded_media_experience_enabled_(false),
-      weak_factory_(this) {
+      embedded_media_experience_enabled_(false) {
   Java_Tab_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
-
-  frame_interfaces_.AddInterface(base::Bind(
-      &TabAndroid::CreateInProductHelpService, weak_factory_.GetWeakPtr()));
 }
 
 TabAndroid::~TabAndroid() {
@@ -871,22 +826,6 @@
     tab_content_manager_->NativeRemoveTabThumbnail(GetAndroidId());
 }
 
-void TabAndroid::OnInterfaceRequestFromFrame(
-    content::RenderFrameHost* render_frame_host,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle* interface_pipe) {
-  frame_interfaces_.TryBindInterface(interface_name, interface_pipe,
-                                     render_frame_host);
-}
-
-void TabAndroid::RenderFrameDeleted(
-    content::RenderFrameHost* render_frame_host) {
-  if (media_in_product_help_ &&
-      media_in_product_help_->render_frame_host() == render_frame_host) {
-    DismissMediaDownloadInProductHelp();
-  }
-}
-
 void TabAndroid::NavigationEntryChanged(
     const content::EntryChangedDetails& change_details) {
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -921,59 +860,6 @@
   return render_process_host->IsBlocked();
 }
 
-void TabAndroid::ShowMediaDownloadInProductHelp(
-    const gfx::Rect& rect_in_frame) {
-  DCHECK(web_contents_);
-
-  // We need to account for the browser controls offset to get the location for
-  // the widget in the view.
-  gfx::NativeView view = web_contents_->GetNativeView();
-  gfx::Rect rect_in_view(rect_in_frame.x(),
-                         rect_in_frame.y() + view->content_offset(),
-                         rect_in_frame.width(), rect_in_frame.height());
-  gfx::Rect scaled_rect_on_screen = gfx::ScaleToEnclosingRectSafe(
-      rect_in_view, ui::GetScaleFactorForNativeView(view));
-
-  // We also need to account for the offset of the viewport location on screen.
-  scaled_rect_on_screen.set_origin(
-      scaled_rect_on_screen.origin() +
-      view->GetLocationOfContainerViewInWindow().OffsetFromOrigin());
-
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_Tab_showMediaDownloadInProductHelp(
-      env, weak_java_tab_.get(env), scaled_rect_on_screen.x(),
-      scaled_rect_on_screen.y(), scaled_rect_on_screen.width(),
-      scaled_rect_on_screen.height());
-}
-
-void TabAndroid::DismissMediaDownloadInProductHelp() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_Tab_hideMediaDownloadInProductHelp(env, weak_java_tab_.get(env));
-}
-
-void TabAndroid::MediaDownloadInProductHelpDismissed(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj) {
-  DCHECK(media_in_product_help_);
-  media_in_product_help_.reset();
-}
-
-void TabAndroid::CreateInProductHelpService(
-    blink::mojom::MediaDownloadInProductHelpRequest request,
-    content::RenderFrameHost* render_frame_host) {
-  // If we are showing the UI already, ignore the request.
-  if (media_in_product_help_)
-    return;
-
-  media_in_product_help_ = std::make_unique<MediaDownloadInProductHelp>(
-      render_frame_host, this, std::move(request));
-}
-
-void TabAndroid::OnMediaDownloadInProductHelpConnectionError() {
-  DCHECK(media_in_product_help_);
-  DismissMediaDownloadInProductHelp();
-}
-
 scoped_refptr<content::DevToolsAgentHost> TabAndroid::GetDevToolsAgentHost() {
   return devtools_host_;
 }
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 80a1805..1d8b429 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -14,7 +14,6 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/android/tab_state.h"
 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
@@ -23,8 +22,6 @@
 #include "components/omnibox/browser/location_bar_model.h"
 #include "components/sessions/core/session_id.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "third_party/blink/public/platform/media_download_in_product_help.mojom.h"
 
 class GURL;
 class Profile;
@@ -245,10 +242,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       jboolean enabled);
 
-  void MediaDownloadInProductHelpDismissed(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-
   bool ShouldEnableEmbeddedMediaExperience() const;
 
   scoped_refptr<content::DevToolsAgentHost> GetDevToolsAgentHost();
@@ -258,15 +251,6 @@
   void AttachDetachedTab(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
 
-  // Register the Tab's native methods through JNI.
-  static bool RegisterTabAndroid(JNIEnv* env);
-
-  // content::WebContentsObserver implementation.
-  void OnInterfaceRequestFromFrame(
-      content::RenderFrameHost* render_frame_host,
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle* interface_pipe) override;
-  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void NavigationEntryChanged(
       const content::EntryChangedDetails& change_details) override;
   void DidFinishNavigation(
@@ -277,18 +261,8 @@
       const base::android::JavaParamRef<jobject>& obj);
 
  private:
-  class MediaDownloadInProductHelp;
-
   prerender::PrerenderManager* GetPrerenderManager() const;
 
-  // methods used by MediaDownloadInProductHelp.
-  void CreateInProductHelpService(
-      blink::mojom::MediaDownloadInProductHelpRequest request,
-      content::RenderFrameHost* render_frame_host);
-  void ShowMediaDownloadInProductHelp(const gfx::Rect& rect_in_frame);
-  void DismissMediaDownloadInProductHelp();
-  void OnMediaDownloadInProductHelpConnectionError();
-
   JavaObjectWeakGlobalRef weak_java_tab_;
 
   // Identifier of the window the tab is in.
@@ -307,13 +281,6 @@
   bool picture_in_picture_enabled_;
   bool embedded_media_experience_enabled_;
 
-  std::unique_ptr<MediaDownloadInProductHelp> media_in_product_help_;
-
-  service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>
-      frame_interfaces_;
-
-  base::WeakPtrFactory<TabAndroid> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(TabAndroid);
 };
 
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc
index 281a762..8533ded 100644
--- a/chrome/browser/autofill/captured_sites_test_utils.cc
+++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -474,8 +474,8 @@
   }
 
   // Convert the file text into a json object.
-  std::unique_ptr<base::DictionaryValue> recipe =
-      base::DictionaryValue::From(base::JSONReader().ReadToValue(json_text));
+  std::unique_ptr<base::DictionaryValue> recipe = base::DictionaryValue::From(
+      base::JSONReader().ReadToValueDeprecated(json_text));
   if (!recipe) {
     ADD_FAILURE() << "Failed to deserialize json text!";
     return false;
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 862f081..bd528a5 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -1018,7 +1018,7 @@
     // a specified set of sites.
     if (filter_builder.GetMode() != BrowsingDataFilterBuilder::WHITELIST) {
       // Will be completed in OnDeauthorizeFlashContentLicensesCompleted()
-      num_pending_tasks_ += 1;
+      OnTaskStarted(TracingDataType::kFlashDeauthorization);
       if (!pepper_flash_settings_manager_.get()) {
         pepper_flash_settings_manager_.reset(
             new PepperFlashSettingsManager(this, profile_));
@@ -1116,6 +1116,15 @@
     ExternalProtocolHandler::ClearData(profile_);
 }
 
+void ChromeBrowsingDataRemoverDelegate::OnTaskStarted(
+    TracingDataType data_type) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  num_pending_tasks_++;
+  TRACE_EVENT_ASYNC_BEGIN1("browsing_data", "ChromeBrowsingDataRemoverDelegate",
+                           static_cast<int>(data_type), "data_type",
+                           static_cast<int>(data_type));
+}
+
 void ChromeBrowsingDataRemoverDelegate::OnTaskComplete(
     TracingDataType data_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -1134,11 +1143,7 @@
 base::OnceClosure
 ChromeBrowsingDataRemoverDelegate::CreateTaskCompletionClosure(
     TracingDataType data_type) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  num_pending_tasks_++;
-  TRACE_EVENT_ASYNC_BEGIN1("browsing_data", "ChromeBrowsingDataRemoverDelegate",
-                           static_cast<int>(data_type), "data_type",
-                           static_cast<int>(data_type));
+  OnTaskStarted(data_type);
   return base::BindOnce(&ChromeBrowsingDataRemoverDelegate::OnTaskComplete,
                         weak_ptr_factory_.GetWeakPtr(), data_type);
 }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
index 341bad0..f854b60 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -225,6 +225,9 @@
     kTpmAttestationKeys = 30,
   };
 
+  // Called by CreateTaskCompletionClosure().
+  void OnTaskStarted(TracingDataType data_type);
+
   // Called by the closures returned by CreateTaskCompletionClosure().
   // Checks if all tasks have completed, and if so, calls callback_.
   void OnTaskComplete(TracingDataType data_type);
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index bd5355d..34a4dcc 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -296,34 +296,19 @@
   kNSTemporaryDirectory,
   kTMPDIRDirectory,
   kTmpDirectory,
-  kMaxValue = kTmpDirectory,
+  kTmpDirectoryDifferentVolume,
+  kMaxValue = kTmpDirectoryDifferentVolume,
 };
 
 void LogStagingDirectoryLocation(StagingDirectoryStep step) {
-  UMA_HISTOGRAM_ENUMERATION("OSX.StagingDirectoryLocation", step);
+  UMA_HISTOGRAM_ENUMERATION("OSX.StagingDirectoryLocation2", step);
 }
 
 void RecordStagingDirectoryStats() {
   NSURL* bundle_url = [base::mac::OuterBundle() bundleURL];
   NSFileManager* file_manager = [NSFileManager defaultManager];
 
-  // 1. NSItemReplacementDirectory
-
-  NSError* error = nil;
-  NSURL* item_replacement_dir =
-      [file_manager URLForDirectory:NSItemReplacementDirectory
-                           inDomain:NSUserDomainMask
-                  appropriateForURL:bundle_url
-                             create:YES
-                              error:&error];
-  if (item_replacement_dir && !error &&
-      IsDirectoryWriteable([item_replacement_dir path])) {
-    LogStagingDirectoryLocation(
-        StagingDirectoryStep::kItemReplacementDirectory);
-    return;
-  }
-
-  // 2. A directory alongside Chromium.
+  // 1. A directory alongside Chromium.
 
   NSURL* bundle_parent_url =
       [[bundle_url URLByStandardizingPath] URLByDeletingLastPathComponent];
@@ -337,7 +322,7 @@
                                          isDirectory:&is_directory];
 
   BOOL success = true;
-  error = nil;
+  NSError* error = nil;
   if (!path_existed) {
     success = [file_manager createDirectoryAtURL:sibling_dir
                      withIntermediateDirectories:YES
@@ -362,6 +347,22 @@
     return;
   }
 
+  // 2. NSItemReplacementDirectory
+
+  error = nil;
+  NSURL* item_replacement_dir =
+      [file_manager URLForDirectory:NSItemReplacementDirectory
+                           inDomain:NSUserDomainMask
+                  appropriateForURL:bundle_url
+                             create:YES
+                              error:&error];
+  if (item_replacement_dir && !error &&
+      IsDirectoryWriteable([item_replacement_dir path])) {
+    LogStagingDirectoryLocation(
+        StagingDirectoryStep::kItemReplacementDirectory);
+    return;
+  }
+
   // 3. NSTemporaryDirectory()
 
   NSString* ns_temporary_dir = NSTemporaryDirectory();
@@ -389,7 +390,14 @@
     return;
   }
 
-  // 6. Give up.
+  // 6. /tmp, but different volume
+
+  if (IsDirectoryWriteable(tmp)) {
+    LogStagingDirectoryLocation(StagingDirectoryStep::kTmpDirectory);
+    return;
+  }
+
+  // 7. Give up.
 
   LogStagingDirectoryLocation(StagingDirectoryStep::kFailedToFindDirectory);
 }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 20926de..3c1f868a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -91,6 +91,7 @@
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/prerender/prerender_message_filter.h"
 #include "chrome/browser/prerender/prerender_util.h"
+#include "chrome/browser/previews/previews_content_util.h"
 #include "chrome/browser/previews/previews_lite_page_decider.h"
 #include "chrome/browser/previews/previews_lite_page_navigation_throttle.h"
 #include "chrome/browser/previews/previews_lite_page_url_loader_interceptor.h"
@@ -227,7 +228,6 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
-#include "components/previews/content/previews_content_util.h"
 #include "components/previews/content/previews_decider_impl.h"
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/content/previews_user_data.h"
@@ -3222,10 +3222,6 @@
 
 #if defined(OS_ANDROID)
   web_prefs->video_fullscreen_detection_enabled = true;
-
-  web_prefs->enable_media_download_in_product_help =
-      base::FeatureList::IsEnabled(
-          feature_engagement::kIPHMediaDownloadFeature);
 #endif  // defined(OS_ANDROID)
 
   if (base::FeatureList::IsEnabled(features::kLowPriorityIframes)) {
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 242fe9f9e..721f7082 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -42,6 +42,10 @@
   "event_rewriter_unittest\.cc": [
     "+ui/events/devices/device_data_manager.h",
   ],
+  "file_manager_browsertest_base.cc": [
+    "+chrome/browser/ui/views/extensions/extension_dialog.h",
+    "+chrome/browser/ui/views/select_file_dialog_extension.h",
+  ],
   "input_method_manager_impl\.cc": [
     # For GetInputMethodKeyboardController. TODO(stevenjb/shuchen): Fix this
     # for Mash. https://crbug.com/756059
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
index a48a691..25af2c2 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
@@ -38,11 +38,6 @@
   // Should be a no-op on ARC. This is managed on the Android side.
 }
 
-void ArcPictureInPictureWindowControllerImpl::SetPictureInPictureCustomControls(
-    const std::vector<blink::PictureInPictureControlInfo>& info) {
-  // Should be a no-op on ARC. This is managed on the Android side.
-}
-
 void ArcPictureInPictureWindowControllerImpl::EmbedSurface(
     const viz::SurfaceId& surface_id,
     const gfx::Size& natural_size) {
@@ -81,11 +76,6 @@
   return false;
 }
 
-void ArcPictureInPictureWindowControllerImpl::CustomControlPressed(
-    const std::string& control_id) {
-  // Should be a no-op on ARC. This is managed on the Android side.
-}
-
 void ArcPictureInPictureWindowControllerImpl::SetAlwaysHidePlayPauseButton(
     bool is_visible) {
   // Should be a no-op on ARC. This is managed on the Android side.
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
index 2af214a..686e4b47 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
@@ -5,9 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ARC_PIP_ARC_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_IMPL_H_
 #define CHROME_BROWSER_CHROMEOS_ARC_PIP_ARC_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_IMPL_H_
 
-#include <string>
-#include <vector>
-
 #include "base/macros.h"
 #include "content/public/browser/picture_in_picture_window_controller.h"
 #include "ui/gfx/geometry/size.h"
@@ -37,8 +34,6 @@
   void Close(bool should_pause_video, bool should_reset_pip_player) override;
   void CloseAndFocusInitiator() override;
   void OnWindowDestroyed() override;
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>& info) override;
   void EmbedSurface(const viz::SurfaceId& surface_id,
                     const gfx::Size& natural_size) override;
   content::OverlayWindow* GetWindowForTesting() override;
@@ -46,7 +41,6 @@
   bool IsPlayerActive() override;
   content::WebContents* GetInitiatorWebContents() override;
   bool TogglePlayPause() override;
-  void CustomControlPressed(const std::string& control_id) override;
   void UpdatePlaybackState(bool is_playing,
                            bool reached_end_of_stream) override;
   void SetAlwaysHidePlayPauseButton(bool is_visible) override;
diff --git a/chrome/browser/chromeos/crostini/crostini_package_notification.cc b/chrome/browser/chromeos/crostini/crostini_package_notification.cc
index 6927981..29698c3 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_notification.cc
+++ b/chrome/browser/chromeos/crostini/crostini_package_notification.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/time_format.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/public/cpp/notification.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
@@ -161,30 +160,8 @@
       title = notification_settings_.progress_title;
       if (notification_type_ == NotificationType::APPLICATION_UNINSTALL) {
         // Uninstalls have a time remaining instead of a fixed message.
-        base::TimeDelta time_since_started_running =
-            base::Time::Now() - running_start_time_;
+        body = GetTimeRemainingMessage(running_start_time_, progress_percent);
 
-        // Don't estimate if we don't have enough data yet. At the moment we
-        // start the uninstall, we have no idea how long it will take. Only
-        // estimate once we've spent at least 3 seconds OR gotten 10% of the
-        // way through the uninstall.
-        constexpr base::TimeDelta kMinTimeForEstimate =
-            base::TimeDelta::FromSeconds(3);
-        constexpr base::TimeDelta kTimeDeltaZero =
-            base::TimeDelta::FromSeconds(0);
-        constexpr int kMinPercentForEstimate = 10;
-        if ((time_since_started_running >= kMinTimeForEstimate &&
-             progress_percent > 0) ||
-            (progress_percent >= kMinPercentForEstimate &&
-             time_since_started_running > kTimeDeltaZero)) {
-          base::TimeDelta total_time_expected =
-              (time_since_started_running * 100) / progress_percent;
-          base::TimeDelta time_remaining =
-              total_time_expected - time_since_started_running;
-          body = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
-                                        ui::TimeFormat::LENGTH_SHORT,
-                                        time_remaining);
-        }
         // else leave body blank
       } else {
         body = notification_settings_.progress_body;
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path.cc b/chrome/browser/chromeos/crostini/crostini_share_path.cc
index 068b4d0..1e60135d 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path.cc
+++ b/chrome/browser/chromeos/crostini/crostini_share_path.cc
@@ -317,10 +317,6 @@
                                   bool persist,
                                   SharePathCallback callback) {
   DCHECK(callback);
-  if (!base::FeatureList::IsEnabled(chromeos::features::kCrostiniFiles)) {
-    std::move(callback).Run(path, false, "Flag crostini-files not enabled");
-    return;
-  }
   CallSeneschalSharePath(std::move(vm_name), path, persist,
                          std::move(callback));
 }
@@ -364,8 +360,6 @@
 
 std::vector<base::FilePath> CrostiniSharePath::GetPersistedSharedPaths() {
   std::vector<base::FilePath> result;
-  if (!base::FeatureList::IsEnabled(chromeos::features::kCrostiniFiles))
-    return result;
   PrefService* pref_service = profile_->GetPrefs();
   const base::ListValue* shared_paths =
       pref_service->GetList(prefs::kCrostiniSharedPaths);
@@ -424,8 +418,7 @@
 
 void CrostiniSharePath::OnVolumeMounted(chromeos::MountError error_code,
                                         const file_manager::Volume& volume) {
-  if (!base::FeatureList::IsEnabled(chromeos::features::kCrostiniFiles) ||
-      error_code != chromeos::MountError::MOUNT_ERROR_NONE ||
+  if (error_code != chromeos::MountError::MOUNT_ERROR_NONE ||
       !crostini::CrostiniManager::GetForProfile(profile_)->IsVmRunning(
           kCrostiniDefaultVmName)) {
     return;
@@ -442,8 +435,7 @@
 
 void CrostiniSharePath::OnVolumeUnmounted(chromeos::MountError error_code,
                                           const file_manager::Volume& volume) {
-  if (!base::FeatureList::IsEnabled(chromeos::features::kCrostiniFiles) ||
-      error_code != chromeos::MountError::MOUNT_ERROR_NONE ||
+  if (error_code != chromeos::MountError::MOUNT_ERROR_NONE ||
       !crostini::CrostiniManager::GetForProfile(profile_)->IsVmRunning(
           kCrostiniDefaultVmName)) {
     return;
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc b/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
index 58d284b6..af83fac 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
@@ -254,8 +254,7 @@
 };
 
 TEST_F(CrostiniSharePathTest, SuccessDownloadsRoot) {
-  features_.InitWithFeatures({chromeos::features::kCrostiniFiles},
-                             {chromeos::features::kMyFilesVolume});
+  features_.InitWithFeatures({}, {chromeos::features::kMyFilesVolume});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", root_, PERSIST_NO,
@@ -268,9 +267,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessMyFilesRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   base::FilePath my_files =
       file_manager::util::GetMyFilesFolderForProfile(profile());
@@ -285,9 +282,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessNoPersist) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", share_path_, PERSIST_NO,
@@ -300,9 +295,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessPersist) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", share_path_, PERSIST_YES,
@@ -315,8 +308,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessDriveFsMyDrive) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("root").Append("my"), PERSIST_NO,
@@ -329,8 +321,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, FailureDriveFsDisabled) {
-  features_.InitWithFeatures({chromeos::features::kCrostiniFiles},
-                             {chromeos::features::kDriveFs});
+  features_.InitWithFeatures({}, {chromeos::features::kDriveFs});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("root").Append("my"), PERSIST_NO,
@@ -342,8 +333,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessDriveFsMyDriveRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("root"), PERSIST_NO,
@@ -356,8 +346,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, FailDriveFsRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_, PERSIST_NO,
@@ -369,8 +358,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessDriveFsTeamDrives) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("team_drives").Append("team"), PERSIST_NO,
@@ -384,8 +372,7 @@
 
 // TODO(crbug.com/917920): Enable when DriveFS enforces allowed write paths.
 TEST_F(CrostiniSharePathTest, DISABLED_SuccessDriveFsComputersGrandRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("Computers"), PERSIST_NO,
@@ -399,8 +386,7 @@
 
 // TODO(crbug.com/917920): Remove when DriveFS enforces allowed write paths.
 TEST_F(CrostiniSharePathTest, Bug917920DriveFsComputersGrandRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("Computers"), PERSIST_NO,
@@ -413,8 +399,7 @@
 
 // TODO(crbug.com/917920): Enable when DriveFS enforces allowed write paths.
 TEST_F(CrostiniSharePathTest, DISABLED_SuccessDriveFsComputerRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("Computers").Append("pc"), PERSIST_NO,
@@ -428,8 +413,7 @@
 
 // TODO(crbug.com/917920): Remove when DriveFS enforces allowed write paths.
 TEST_F(CrostiniSharePathTest, Bug917920DriveFsComputerRoot) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append("Computers").Append("pc"), PERSIST_NO,
@@ -441,8 +425,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessDriveFsComputersLevel3) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running",
@@ -457,8 +440,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, FailDriveFsTrash) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kDriveFs}, {});
+  features_.InitWithFeatures({chromeos::features::kDriveFs}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", drivefs_.Append(".Trash").Append("in-the-trash"),
@@ -471,7 +453,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, SuccessRemovable) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", base::FilePath("/media/removable/MyUSB"), PERSIST_NO,
@@ -484,7 +465,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, FailRemovableRoot) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-running", base::FilePath("/media/removable"), PERSIST_NO,
@@ -496,9 +476,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePathErrorSeneschal) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   vm_tools::concierge::StartVmResponse start_vm_response;
   start_vm_response.set_status(vm_tools::concierge::VM_STATUS_RUNNING);
@@ -521,7 +499,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePathErrorPathNotAbsolute) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   const base::FilePath path("not/absolute/dir");
   crostini_share_path()->SharePath(
@@ -534,7 +511,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePathErrorReferencesParent) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   const base::FilePath path("/path/../references/parent");
   crostini_share_path()->SharePath(
@@ -547,7 +523,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePathErrorNotUnderDownloads) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   const base::FilePath path("/not/under/downloads");
   crostini_share_path()->SharePath(
@@ -560,9 +535,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePathVmToBeRestarted) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   crostini_share_path()->SharePath(
       "vm-to-be-started", share_path_, PERSIST_YES,
@@ -575,7 +548,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePathErrorVmCouldNotBeStarted) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   vm_tools::concierge::StartVmResponse start_vm_response;
   start_vm_response.set_status(vm_tools::concierge::VM_STATUS_FAILURE);
@@ -591,7 +563,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, SharePersistedPaths) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   base::FilePath share_path2_ = root_.AppendASCII("path-to-share-2");
   ASSERT_TRUE(base::CreateDirectory(share_path2_));
@@ -673,9 +644,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, UnsharePathSuccess) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   crostini_share_path()->UnsharePath(
       "vm-running", shared_path_,
@@ -728,32 +697,11 @@
   base::FilePath not_downloads("/not/downloads");
   shared_paths.AppendString(not_downloads.value());
   std::string prefstr;
-  // CrostiniFiles disabled, MyFilesVolume disabled.
-  // Result is empty, prefs unchanged.
-  {
-    base::test::ScopedFeatureList features;
-    features.InitWithFeatures({}, {chromeos::features::kCrostiniFiles,
-                                   chromeos::features::kMyFilesVolume});
-    storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
-        file_manager::util::GetDownloadsMountPointName(profile()));
-    profile()->GetPrefs()->Set(prefs::kCrostiniSharedPaths, shared_paths);
-    std::vector<base::FilePath> paths =
-        crostini_share_path()->GetPersistedSharedPaths();
-    EXPECT_EQ(paths.size(), 0U);
-    const base::ListValue* prefs =
-        profile()->GetPrefs()->GetList(prefs::kCrostiniSharedPaths);
-    EXPECT_EQ(prefs->GetSize(), 2U);
-    prefs->GetString(0, &prefstr);
-    EXPECT_EQ(prefstr, downloads_file.value());
-    prefs->GetString(1, &prefstr);
-    EXPECT_EQ(prefstr, not_downloads.value());
-  }
-  // CrostiniFiles enabled, MyFilesVolume disabled.
+  // MyFilesVolume disabled.
   // Return prefs unchanged.
   {
     base::test::ScopedFeatureList features;
-    features.InitWithFeatures({chromeos::features::kCrostiniFiles},
-                              {chromeos::features::kMyFilesVolume});
+    features.InitWithFeatures({}, {chromeos::features::kMyFilesVolume});
     storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
         file_manager::util::GetDownloadsMountPointName(profile()));
     profile()->GetPrefs()->Set(prefs::kCrostiniSharedPaths, shared_paths);
@@ -770,13 +718,11 @@
     prefs->GetString(1, &prefstr);
     EXPECT_EQ(prefstr, not_downloads.value());
   }
-  // CrostiniFiles enabled, MyFilesVolume enabled.
+  // MyFilesVolume enabled.
   // Migrate prefs and return.
   {
     base::test::ScopedFeatureList features;
-    features.InitWithFeatures({chromeos::features::kCrostiniFiles,
-                               chromeos::features::kMyFilesVolume},
-                              {});
+    features.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
     storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
         file_manager::util::GetDownloadsMountPointName(profile()));
     profile()->GetPrefs()->Set(prefs::kCrostiniSharedPaths, shared_paths);
@@ -798,9 +744,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, ShareOnMountSuccessParentMount) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
       kCrostiniDefaultVmName);
@@ -816,9 +760,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, ShareOnMountSuccessSelfMount) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
       kCrostiniDefaultVmName);
@@ -835,42 +777,7 @@
   run_loop()->Run();
 }
 
-TEST_F(CrostiniSharePathTest, ShareOnMountFeatureNotEnabled) {
-  features_.InitAndDisableFeature(chromeos::features::kCrostiniFiles);
-  SetUpVolume();
-  CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
-      kCrostiniDefaultVmName);
-
-  // Test mount.
-  crostini_share_path_->OnVolumeMounted(chromeos::MountError::MOUNT_ERROR_NONE,
-                                        *volume_downloads_);
-  EXPECT_EQ(fake_seneschal_client_->share_path_called(), false);
-
-  // Test unmount.
-  crostini_share_path_->OnVolumeUnmounted(
-      chromeos::MountError::MOUNT_ERROR_NONE, *volume_downloads_);
-  EXPECT_EQ(fake_seneschal_client_->share_path_called(), false);
-}
-
-TEST_F(CrostiniSharePathTest, ShareOnMountMountError) {
-  features_.InitAndDisableFeature(chromeos::features::kCrostiniFiles);
-  SetUpVolume();
-  CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
-      kCrostiniDefaultVmName);
-
-  // Test mount.
-  crostini_share_path_->OnVolumeMounted(
-      chromeos::MountError::MOUNT_ERROR_UNKNOWN, *volume_downloads_);
-  EXPECT_EQ(fake_seneschal_client_->share_path_called(), false);
-
-  // Test unmount.
-  crostini_share_path_->OnVolumeUnmounted(
-      chromeos::MountError::MOUNT_ERROR_UNKNOWN, *volume_downloads_);
-  EXPECT_EQ(fake_seneschal_client_->share_path_called(), false);
-}
-
 TEST_F(CrostiniSharePathTest, ShareOnMountVmNotRunning) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
 
   // Test mount.
@@ -885,7 +792,6 @@
 }
 
 TEST_F(CrostiniSharePathTest, ShareOnMountVolumeUnrelated) {
-  features_.InitAndEnableFeature(chromeos::features::kCrostiniFiles);
   SetUpVolume();
   auto volume_unrelated_ = file_manager::Volume::CreateForDownloads(
       base::FilePath("/unrelated/path"));
@@ -902,9 +808,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, UnshareOnUnmountSuccessParentMount) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
       kCrostiniDefaultVmName);
@@ -920,9 +824,7 @@
 }
 
 TEST_F(CrostiniSharePathTest, UnshareOnUnmountSuccessSelfMount) {
-  features_.InitWithFeatures(
-      {chromeos::features::kCrostiniFiles, chromeos::features::kMyFilesVolume},
-      {});
+  features_.InitWithFeatures({chromeos::features::kMyFilesVolume}, {});
   SetUpVolume();
   CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
       kCrostiniDefaultVmName);
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index e40765a..9437bbc 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -35,9 +35,12 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
+#include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 
 namespace {
 
@@ -461,4 +464,24 @@
       vm_name, container_name);
 }
 
+base::string16 GetTimeRemainingMessage(base::Time start, int percent) {
+  // Only estimate once we've spent at least 3 seconds OR gotten 10% of the way
+  // through.
+  constexpr base::TimeDelta kMinTimeForEstimate =
+      base::TimeDelta::FromSeconds(3);
+  constexpr base::TimeDelta kTimeDeltaZero = base::TimeDelta::FromSeconds(0);
+  constexpr int kMinPercentForEstimate = 10;
+  base::TimeDelta elapsed = base::Time::Now() - start;
+  if ((elapsed >= kMinTimeForEstimate && percent > 0) ||
+      (percent >= kMinPercentForEstimate && elapsed > kTimeDeltaZero)) {
+    base::TimeDelta total_time_expected = (elapsed * 100) / percent;
+    base::TimeDelta time_remaining = total_time_expected - elapsed;
+    return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
+                                  ui::TimeFormat::LENGTH_SHORT, time_remaining);
+  } else {
+    return l10n_util::GetStringUTF16(
+        IDS_CROSTINI_NOTIFICATION_OPERATION_STARTING);
+  }
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index 343540e..e4116fd6d 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -165,6 +165,11 @@
                                  std::string vm_name,
                                  std::string container_name);
 
+// Returns a string to be displayed in a notification with the estimated time
+// left for an operation to run which started and time |start| and is current
+// at |percent| way through.
+base::string16 GetTimeRemainingMessage(base::Time start, int percent);
+
 }  // namespace crostini
 
 #endif  // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 6655601..b38bf62 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -360,8 +360,7 @@
     // without such tight coupling.
     browser()->profile()->GetPrefs()->SetBoolean(
         crostini::prefs::kCrostiniEnabled, true);
-    scoped_feature_list->InitWithFeatures(
-        {features::kCrostini, chromeos::features::kCrostiniFiles}, {});
+    scoped_feature_list->InitWithFeatures({features::kCrostini}, {});
     // Profile must be signed in with email for crostini.
     identity::SetPrimaryAccount(
         IdentityManagerFactory::GetForProfileIfExists(browser()->profile()),
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 7ba87fe..fa6b443 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -43,9 +43,6 @@
   // TODO(crbug.com/868747): Find a better solution for demo mode.
   dict->SetBoolean("HIDE_SPACE_INFO",
                    chromeos::DemoSession::IsDeviceInDemoMode());
-  dict->SetBoolean(
-      "CROSTINI_FILES_ENABLED",
-      base::FeatureList::IsEnabled(chromeos::features::kCrostiniFiles));
   dict->SetBoolean("DRIVE_FS_ENABLED",
                    base::FeatureList::IsEnabled(chromeos::features::kDriveFs));
   dict->SetBoolean(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index ac13ccd..5e64f90 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -113,7 +113,6 @@
 
   const char* test_case_name = nullptr;
   GuestMode guest_mode = NOT_IN_GUEST_MODE;
-  bool trusted_events = false;
   bool tablet_mode = false;
   base::Optional<bool> enable_drivefs;
   base::Optional<bool> enable_myfiles_volume;
@@ -124,13 +123,6 @@
   bool mount_no_volumes = false;
 };
 
-// EventCase: FilesAppBrowserTest with trusted JS Events.
-struct EventCase : public TestCase {
-  explicit EventCase(const char* name) : TestCase(name) {
-    trusted_events = true;
-  }
-};
-
 // ZipCase: FilesAppBrowserTest with zip/unzip support.
 struct ZipCase : public TestCase {
   explicit ZipCase(const char* name) : TestCase(name) { needs_zip = true; }
@@ -145,14 +137,6 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     FileManagerBrowserTestBase::SetUpCommandLine(command_line);
-
-    // Prevent Blink swallowing Tab key with its default handlers: forward
-    // the Tab key event to the Files.App JS page under test instead.
-    if (GetParam().trusted_events) {
-      command_line->AppendSwitchASCII("disable-blink-features",
-                                      "TrustedEventsDefaultAction");
-    }
-
     // Default mode is clamshell: force Ash into tablet mode if requested,
     // and enable the Ash virtual keyboard sub-system therein.
     if (GetParam().tablet_mode) {
@@ -276,6 +260,9 @@
         TestCase("fileDisplayUnmountDriveWithSharedWithMeSelected"),
         TestCase("fileDisplayUnmountDriveWithSharedWithMeSelected")
             .EnableMyFilesVolume(),
+        TestCase("fileDisplayUnmountRemovableRoot"),
+        TestCase("fileDisplayUnmountFirstPartition"),
+        TestCase("fileDisplayUnmountLastPartition"),
         TestCase("fileSearchCaseInsensitive"),
         TestCase("fileSearchNotFound")));
 
@@ -700,46 +687,44 @@
                       TestCase("sortColumns").InGuestMode()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
-    TabIndex, /* tab_index.js: tabindex tests require trusted JS Events. */
+    TabIndex, /* tab_index.js: */
     FilesAppBrowserTest,
     ::testing::Values(
-        EventCase("tabindexSearchBoxFocus"),
-        EventCase("tabindexSearchBoxFocus").EnableMyFilesVolume(),
-        EventCase("tabindexFocus"),
-        EventCase("tabindexFocus").EnableMyFilesVolume(),
-        EventCase("tabindexFocusDownloads"),
-        EventCase("tabindexFocusDownloads").EnableMyFilesVolume(),
-        EventCase("tabindexFocusDownloads").InGuestMode(),
-        EventCase("tabindexFocusDownloads").InGuestMode().EnableMyFilesVolume(),
-        EventCase("tabindexFocusBreadcrumbBackground"),
-        EventCase("tabindexFocusDirectorySelected"),
-        EventCase("tabindexFocusDirectorySelected").EnableMyFilesVolume(),
-        EventCase("tabindexOpenDialogDrive").WithBrowser().DisableDriveFs(),
-        EventCase("tabindexOpenDialogDrive").WithBrowser().EnableDriveFs(),
-        EventCase("tabindexOpenDialogDrive")
+        TestCase("tabindexSearchBoxFocus"),
+        TestCase("tabindexSearchBoxFocus").EnableMyFilesVolume(),
+        TestCase("tabindexFocus"),
+        TestCase("tabindexFocus").EnableMyFilesVolume(),
+        TestCase("tabindexFocusDownloads"),
+        TestCase("tabindexFocusDownloads").EnableMyFilesVolume(),
+        TestCase("tabindexFocusDownloads").InGuestMode(),
+        TestCase("tabindexFocusDownloads").InGuestMode().EnableMyFilesVolume(),
+        TestCase("tabindexFocusBreadcrumbBackground"),
+        TestCase("tabindexFocusDirectorySelected"),
+        TestCase("tabindexFocusDirectorySelected").EnableMyFilesVolume(),
+        TestCase("tabindexOpenDialogDrive").WithBrowser().DisableDriveFs(),
+        TestCase("tabindexOpenDialogDrive").WithBrowser().EnableDriveFs(),
+        TestCase("tabindexOpenDialogDrive")
             .WithBrowser()
             .EnableDriveFs()
             .EnableMyFilesVolume(),
-        EventCase("tabindexOpenDialogDownloads").WithBrowser(),
-        EventCase("tabindexOpenDialogDownloads")
+        TestCase("tabindexOpenDialogDownloads").WithBrowser(),
+        TestCase("tabindexOpenDialogDownloads")
             .WithBrowser()
             .EnableMyFilesVolume(),
-        EventCase("tabindexOpenDialogDownloads").WithBrowser().InGuestMode(),
-        EventCase("tabindexOpenDialogDownloads")
+        TestCase("tabindexOpenDialogDownloads").WithBrowser().InGuestMode(),
+        TestCase("tabindexOpenDialogDownloads")
             .WithBrowser()
             .InGuestMode()
             .EnableMyFilesVolume(),
-        EventCase("tabindexSaveFileDialogDrive").WithBrowser().DisableDriveFs(),
-        EventCase("tabindexSaveFileDialogDrive").WithBrowser().EnableDriveFs(),
-        EventCase("tabindexSaveFileDialogDrive")
+        TestCase("tabindexSaveFileDialogDrive").WithBrowser().DisableDriveFs(),
+        TestCase("tabindexSaveFileDialogDrive").WithBrowser().EnableDriveFs(),
+        TestCase("tabindexSaveFileDialogDrive")
             .WithBrowser()
             .EnableDriveFs()
             .EnableMyFilesVolume(),
-        EventCase("tabindexSaveFileDialogDownloads").WithBrowser(),
-        EventCase("tabindexSaveFileDialogDownloads")
-            .WithBrowser()
-            .InGuestMode(),
-        EventCase("tabindexSaveFileDialogDownloads")
+        TestCase("tabindexSaveFileDialogDownloads").WithBrowser(),
+        TestCase("tabindexSaveFileDialogDownloads").WithBrowser().InGuestMode(),
+        TestCase("tabindexSaveFileDialogDownloads")
             .WithBrowser()
             .InGuestMode()
             .EnableMyFilesVolume()));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 8e3e09c..c25e9b4 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -42,6 +42,8 @@
 #include "chrome/browser/sync_file_system/mock_remote_file_sync_service.h"
 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
 #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h"
+#include "chrome/browser/ui/views/extensions/extension_dialog.h"
+#include "chrome/browser/ui/views/select_file_dialog_extension.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
@@ -80,6 +82,31 @@
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/message_center/public/cpp/notification.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "ui/shell_dialogs/select_file_dialog_factory.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+class SelectFileDialogExtensionTestFactory
+    : public ui::SelectFileDialogFactory {
+ public:
+  SelectFileDialogExtensionTestFactory() = default;
+  ~SelectFileDialogExtensionTestFactory() override = default;
+
+  ui::SelectFileDialog* Create(
+      ui::SelectFileDialog::Listener* listener,
+      std::unique_ptr<ui::SelectFilePolicy> policy) override {
+    last_select_ =
+        SelectFileDialogExtension::Create(listener, std::move(policy));
+    return last_select_.get();
+  }
+
+  views::Widget* GetLastWidget() {
+    return last_select_->extension_dialog_->GetWidget();
+  }
+
+ private:
+  scoped_refptr<SelectFileDialogExtension> last_select_;
+};
 
 namespace file_manager {
 namespace {
@@ -653,6 +680,12 @@
     return true;
   }
 
+  void Unmount(Profile* profile) {
+    VolumeManager::Get(profile)->RemoveVolumeForTesting(
+        root_path(), volume_type_, device_type_, read_only_, device_path_,
+        drive_label_);
+  }
+
  private:
   storage::ExternalMountPoints* GetMountPoints() {
     return storage::ExternalMountPoints::GetSystemInstance();
@@ -660,7 +693,7 @@
 
   const VolumeType volume_type_;
   const chromeos::DeviceType device_type_;
-  const base::FilePath& device_path_;
+  const base::FilePath device_path_;
   const bool read_only_ = false;
   const std::string drive_label_;
 
@@ -829,6 +862,11 @@
     return true;
   }
 
+  void Unmount(Profile* profile) {
+    VolumeManager::Get(profile)->RemoveVolumeForTesting(
+        root_path(), volume_type_, device_type_, read_only_);
+  }
+
  private:
   storage::ExternalMountPoints* GetMountPoints() {
     return storage::ExternalMountPoints::GetSystemInstance();
@@ -1272,7 +1310,6 @@
 
   if (!IsGuestModeTest()) {
     enabled_features.emplace_back(features::kCrostini);
-    enabled_features.emplace_back(chromeos::features::kCrostiniFiles);
   }
 
   if (!IsNativeSmbTest()) {
@@ -1396,6 +1433,14 @@
   if (IsTabletModeTest()) {
     EnableVirtualKeyboard();
   }
+
+  select_factory_ = new SelectFileDialogExtensionTestFactory();
+  ui::SelectFileDialog::SetFactory(select_factory_);
+}
+
+void FileManagerBrowserTestBase::TearDownOnMainThread() {
+  select_factory_ = nullptr;
+  ui::SelectFileDialog::SetFactory(nullptr);
 }
 
 bool FileManagerBrowserTestBase::GetTabletMode() const {
@@ -1637,43 +1682,40 @@
     return;
   }
 
-  if (name == "mountFakePartitions") {
+  if (name == "unmountUsb") {
+    DCHECK(usb_volume_);
+    usb_volume_->Unmount(profile());
+  }
+
+  if (name == "mountUsbWithPartitions") {
     // Create a device path to mimic a realistic device path.
-    constexpr char kMultiPartitionDevicePath[] =
+    constexpr char kDevicePath[] =
         "sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2/1-2.2:1.0/host0/"
         "target0:0:0/0:0:0:0";
-    const base::FilePath partition_device_path(kMultiPartitionDevicePath);
-
-    constexpr char kSingleUsbDevicePath[] =
-        "sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/host1/"
-        "target1:0:0/1:0:0:0";
-    const base::FilePath usb_device_path(kSingleUsbDevicePath);
+    const base::FilePath device_path(kDevicePath);
 
     // Create partition volumes with the same device path and drive label.
     partition_1_ = std::make_unique<RemovableTestVolume>(
         "partition-1", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
-        chromeos::DEVICE_TYPE_USB, partition_device_path,
-        "PARTITION_DRIVE_LABEL");
+        chromeos::DEVICE_TYPE_USB, device_path, "Drive Label");
     partition_2_ = std::make_unique<RemovableTestVolume>(
         "partition-2", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
-        chromeos::DEVICE_TYPE_USB, partition_device_path,
-        "PARTITION_DRIVE_LABEL");
-
-    // Create an unpartitioned usb volume with a unique device path and
-    // unique device label.
-    single_usb_volume_ = std::make_unique<RemovableTestVolume>(
-        "singleUSB", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
-        chromeos::DEVICE_TYPE_USB, usb_device_path, "SINGLE_DRIVE_LABEL");
+        chromeos::DEVICE_TYPE_USB, device_path, "Drive Label");
 
     // Create fake entries on partitions.
     ASSERT_TRUE(partition_1_->PreparePartitionTestEntries(profile()));
     ASSERT_TRUE(partition_2_->PreparePartitionTestEntries(profile()));
-    ASSERT_TRUE(single_usb_volume_->PrepareUsbTestEntries(profile()));
 
     ASSERT_TRUE(partition_1_->Mount(profile()));
     ASSERT_TRUE(partition_2_->Mount(profile()));
-    ASSERT_TRUE(single_usb_volume_->Mount(profile()));
+    return;
+  }
 
+  if (name == "unmountPartitions") {
+    DCHECK(partition_1_);
+    DCHECK(partition_2_);
+    partition_1_->Unmount(profile());
+    partition_2_->Unmount(profile());
     return;
   }
 
@@ -1766,6 +1808,30 @@
     return;
   }
 
+  if (name == "dispatchTabKey") {
+    ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_TAB, 0);
+
+    // Try to dispatch the event close-to-native without pulling in too many
+    // dependencies (i.e. X11/Ozone/Wayland/Mus). aura::WindowTreeHost is pretty
+    // high up in the dispatch stack, but we might need event_injector.mojom
+    // for a more realistic Mus dispatch.
+    const auto& app_windows =
+        extensions::AppWindowRegistry::Get(profile())->app_windows();
+    aura::WindowTreeHost* host = nullptr;
+    if (app_windows.empty()) {
+      ASSERT_TRUE(select_factory_);
+      views::Widget* widget = select_factory_->GetLastWidget();
+      ASSERT_TRUE(widget);
+      host = widget->GetNativeWindow()->GetHost();
+    } else {
+      host = app_windows.front()->GetNativeWindow()->GetHost();
+    }
+    ASSERT_TRUE(host);
+    host->DispatchKeyEventPostIME(&key_event, base::BindOnce([](bool) {}));
+    *output = "tabKeyDispatched";
+    return;
+  }
+
   if (name == "getAppWindowId") {
     std::string window_url;
     ASSERT_TRUE(value.GetString("windowUrl", &window_url));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
index 3534e47..78a0cf8 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 
 class NotificationDisplayServiceTester;
+class SelectFileDialogExtensionTestFactory;
 
 namespace file_manager {
 
@@ -40,6 +41,7 @@
   bool SetUpUserDataDirectory() override;
   void SetUpInProcessBrowserTestFixture() override;
   void SetUpOnMainThread() override;
+  void TearDownOnMainThread() override;
 
   // Mandatory overrides for each File Manager test extension type.
   virtual GuestMode GetGuestMode() const = 0;
@@ -136,7 +138,6 @@
   std::unique_ptr<FakeTestVolume> mtp_volume_;
   std::unique_ptr<RemovableTestVolume> partition_1_;
   std::unique_ptr<RemovableTestVolume> partition_2_;
-  std::unique_ptr<RemovableTestVolume> single_usb_volume_;
 
   drive::DriveIntegrationServiceFactory::FactoryCallback
       create_drive_integration_service_;
@@ -145,6 +146,9 @@
 
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
 
+  // Not owned.
+  SelectFileDialogExtensionTestFactory* select_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(FileManagerBrowserTestBase);
 };
 
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
index 3ed556e..e7b18c0 100644
--- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -386,6 +386,7 @@
 }
 
 TEST_F(FileManagerPathUtilTest, MigrateToDriveFs) {
+  content::TestServiceManagerContext service_manager_context;
   base::FilePath home("/home/chronos/u-0123456789abcdef");
   base::FilePath other("/some/other/path");
   base::FilePath old_drive("/special/drive-0123456789abcdef");
@@ -395,15 +396,17 @@
   // DriveFS disabled, no changes.
   base::FilePath result;
   {
-    drive::DriveIntegrationServiceFactory::GetForProfile(profile_.get())
-        ->SetEnabled(true);
     base::test::ScopedFeatureList feature_list;
     feature_list.InitAndDisableFeature(chromeos::features::kDriveFs);
+    drive::DriveIntegrationServiceFactory::GetForProfile(profile_.get())
+        ->SetEnabled(true);
     EXPECT_FALSE(MigrateToDriveFs(profile_.get(), other, &result));
     EXPECT_FALSE(MigrateToDriveFs(profile_.get(), my_drive, &result));
   }
-  // MyFilesVolume enabled, migrate paths under Downloads.
+  // DriveFS enabled, migrate paths under old drive mount.
   {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitAndEnableFeature(chromeos::features::kDriveFs);
     TestingProfile profile2(base::FilePath("/home/chronos/u-0123456789abcdef"));
     chromeos::FakeChromeUserManager user_manager;
     user_manager.AddUser(
@@ -413,8 +416,6 @@
     drive::DriveIntegrationServiceFactory::GetForProfile(&profile2)->SetEnabled(
         true);
 
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndEnableFeature(chromeos::features::kDriveFs);
     EXPECT_FALSE(MigrateToDriveFs(&profile2, other, &result));
     EXPECT_TRUE(MigrateToDriveFs(&profile2, my_drive, &result));
     EXPECT_EQ(base::FilePath(
@@ -429,6 +430,8 @@
 }
 
 TEST_F(FileManagerPathUtilTest, ConvertFileSystemURLToPathInsideCrostini) {
+  base::test::ScopedFeatureList initial_features;
+  initial_features.InitAndEnableFeature(chromeos::features::kDriveFs);
   content::TestServiceManagerContext service_manager_context;
 
   storage::ExternalMountPoints* mount_points =
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 922037b..c90b65d4 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -744,6 +744,19 @@
   DoMountEvent(chromeos::MOUNT_ERROR_NONE, std::move(volume));
 }
 
+void VolumeManager::RemoveVolumeForTesting(const base::FilePath& path,
+                                           VolumeType volume_type,
+                                           chromeos::DeviceType device_type,
+                                           bool read_only,
+                                           const base::FilePath& device_path,
+                                           const std::string& drive_label) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DoUnmountEvent(
+      chromeos::MOUNT_ERROR_NONE,
+      *Volume::CreateForTesting(path, volume_type, device_type, read_only,
+                                device_path, drive_label));
+}
+
 void VolumeManager::OnFileSystemMounted() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h
index 28625a1..52dda8b9 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -345,6 +345,14 @@
   // For testing purpose, adds the volume info to the volume manager.
   void AddVolumeForTesting(std::unique_ptr<Volume> volume);
 
+  void RemoveVolumeForTesting(
+      const base::FilePath& path,
+      VolumeType volume_type,
+      chromeos::DeviceType device_type,
+      bool read_only,
+      const base::FilePath& device_path = base::FilePath(),
+      const std::string& drive_label = "");
+
   // drive::DriveIntegrationServiceObserver overrides.
   void OnFileSystemMounted() override;
   void OnFileSystemBeingUnmounted() override;
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 4606b1a9..4a4f51d 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
+#include "base/threading/platform_thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -494,24 +495,20 @@
   }
 
   // Requests |http_server_|'s client-cert test page in the webview with the id
-  // |webview_id|.  Returns the content of the client-cert test page.  If
-  // |watch_new_webcontents| is true, this function will watch for newly-created
-  // WebContents when determining if the navigation to the test page has
-  // finished. This can be used for webviews which have not navigated yet, as
-  // their WebContents will be created on-demand.
-  std::string RequestClientCertTestPageInFrame(std::string webview_id,
-                                               bool watch_new_webcontents) {
+  // |webview_id|. Returns the content of the client-cert test page.
+  std::string RequestClientCertTestPageInFrame(const std::string& webview_id) {
     const GURL url = https_server_->GetURL("client-cert");
     content::TestNavigationObserver navigation_observer(url);
-    if (watch_new_webcontents)
-      navigation_observer.StartWatchingNewWebContents();
-    else
-      navigation_observer.WatchExistingWebContents();
+    navigation_observer.WatchExistingWebContents();
+    navigation_observer.StartWatchingNewWebContents();
 
+    // TODO(https://crbug.com/830337): Remove the logs if flakiness is gone.
+    // If you see this after April 2019, please ping the owner of the above bug.
+    LOG(INFO) << "Triggering navigation to " << url.spec() << ".";
     test::OobeJS().Evaluate(base::StringPrintf(
         "$('%s').src='%s'", webview_id.c_str(), url.spec().c_str()));
-
     navigation_observer.Wait();
+    LOG(INFO) << "Navigation done.";
 
     content::WebContents* main_web_contents = GetLoginUI()->GetWebContents();
     content::WebContents* frame_web_contents =
@@ -519,6 +516,16 @@
     test::JSChecker frame_js_checker(frame_web_contents);
     const std::string https_reply_content =
         frame_js_checker.GetString("document.body.textContent");
+    // TODO(https://crbug.com/830337): Remove this is if flakiness does not
+    // reproduce.
+    // If you see this after April 2019, please ping the owner of the above bug.
+    if (https_reply_content.empty()) {
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1000));
+      const std::string https_reply_content_after_sleep =
+          frame_js_checker.GetString("document.body.textContent");
+      if (!https_reply_content_after_sleep.empty())
+        LOG(INFO) << "Magic - textContent appeared after sleep.";
+    }
 
     return https_reply_content;
   }
@@ -611,15 +618,8 @@
 // Test that client certificate authentication using certificates from the
 // system slot is enabled in the sign-in frame. The server does not request
 // certificates signed by a specific authority.
-//
-// Disabled due to flaky timeouts: https://crbug.com/830337.
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER)
-#define MAYBE_SigninFrameNoAuthorityGiven DISABLED_SigninFrameNoAuthorityGiven
-#else
-#define MAYBE_SigninFrameNoAuthorityGiven SigninFrameNoAuthorityGiven
-#endif
 IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
-                       MAYBE_SigninFrameNoAuthorityGiven) {
+                       SigninFrameNoAuthorityGiven) {
   ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
@@ -629,10 +629,10 @@
       R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})"};
   SetAutoSelectCertificatePatterns(autoselect_patterns);
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
   EXPECT_EQ(
       "got client cert with fingerprint: "
       "c66145f49caca4d1325db96ace0f12f615ba4981",
@@ -655,10 +655,10 @@
       R"({"pattern": "*", "filter": {"ISSUER": {"CN": "foo baz bar"}}})"};
   SetAutoSelectCertificatePatterns(autoselect_patterns);
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
   EXPECT_EQ(
       "got client cert with fingerprint: "
       "c66145f49caca4d1325db96ace0f12f615ba4981",
@@ -667,25 +667,17 @@
 
 // Test that if no client certificate is auto-selected using policy on the
 // sign-in frame, the client does not send up any client certificate.
-//
-// Disabled due to flaky timeouts: https://crbug.com/830337.
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER)
-#define MAYBE_SigninFrameCertNotAutoSelected \
-  DISABLED_SigninFrameCertNotAutoSelected
-#else
-#define MAYBE_SigninFrameCertNotAutoSelected SigninFrameCertNotAutoSelected
-#endif
 IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
-                       MAYBE_SigninFrameCertNotAutoSelected) {
+                       SigninFrameCertNotAutoSelected) {
   ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
   ASSERT_NO_FATAL_FAILURE(StartHttpsServer(ssl_options));
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
 
   EXPECT_EQ("got no client cert", https_reply_content);
 }
@@ -693,15 +685,7 @@
 // Test that client certificate authentication using certificates from the
 // system slot is enabled in the sign-in frame. The server requests
 // a certificate signed by a specific authority.
-//
-// Disabled due to flaky timeouts: https://crbug.com/830337.
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER)
-#define MAYBE_SigninFrameAuthorityGiven DISABLED_SigninFrameAuthorityGiven
-#else
-#define MAYBE_SigninFrameAuthorityGiven SigninFrameAuthorityGiven
-#endif
-IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
-                       MAYBE_SigninFrameAuthorityGiven) {
+IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest, SigninFrameAuthorityGiven) {
   ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
@@ -714,10 +698,10 @@
       R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})"};
   SetAutoSelectCertificatePatterns(autoselect_patterns);
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
   EXPECT_EQ(
       "got client cert with fingerprint: "
       "c66145f49caca4d1325db96ace0f12f615ba4981",
@@ -728,10 +712,8 @@
 // system slot is enabled in the sign-in frame. The server requests
 // a certificate signed by a specific authority. The client doesn't have a
 // matching certificate.
-//
-// Disabled due to flaky timeouts: https://crbug.com/830337.
 IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
-                       DISABLED_SigninFrameAuthorityGivenNoMatchingCert) {
+                       SigninFrameAuthorityGivenNoMatchingCert) {
   ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
@@ -744,10 +726,10 @@
       R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})"};
   SetAutoSelectCertificatePatterns(autoselect_patterns);
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
   EXPECT_EQ("got no client cert", https_reply_content);
 }
 
@@ -756,17 +738,8 @@
 // issued by an intermediate authority, and the intermediate authority is not
 // known on the device (it has not been made available through device ONC
 // policy).
-//
-// Disabled due to flaky timeouts: https://crbug.com/830337.
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER)
-#define MAYBE_SigninFrameIntermediateAuthorityUnknown \
-  DISABLED_SigninFrameIntermediateAuthorityUnknown
-#else
-#define MAYBE_SigninFrameIntermediateAuthorityUnknown \
-  SigninFrameIntermediateAuthorityUnknown
-#endif
 IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
-                       MAYBE_SigninFrameIntermediateAuthorityUnknown) {
+                       SigninFrameIntermediateAuthorityUnknown) {
   ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
@@ -779,10 +752,10 @@
       R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})"};
   SetAutoSelectCertificatePatterns(autoselect_patterns);
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
   EXPECT_EQ("got no client cert", https_reply_content);
 }
 
@@ -790,17 +763,8 @@
 // certificates signed by a root authority, the installed certificate has been
 // issued by an intermediate authority, and the intermediate authority is
 // known on the device (it has been made available through device ONC policy).
-//
-// Disabled due to flaky timeouts: https://crbug.com/830337.
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER)
-#define MAYBE_SigninFrameIntermediateAuthorityKnown \
-  DISABLED_SigninFrameIntermediateAuthorityKnown
-#else
-#define MAYBE_SigninFrameIntermediateAuthorityKnown \
-  SigninFrameIntermediateAuthorityKnown
-#endif
 IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
-                       MAYBE_SigninFrameIntermediateAuthorityKnown) {
+                       SigninFrameIntermediateAuthorityKnown) {
   ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
@@ -818,10 +782,10 @@
   ASSERT_NO_FATAL_FAILURE(
       SetIntermediateAuthorityInDeviceOncPolicy(intermediate_ca_path));
 
-  WaitForGaiaPageLoad();
+  WaitForGaiaPageLoadAndPropertyUpdate();
 
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      gaia_frame_parent_, false /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame(gaia_frame_parent_);
   EXPECT_EQ(
       "got client cert with fingerprint: "
       "c66145f49caca4d1325db96ace0f12f615ba4981",
@@ -847,8 +811,8 @@
   ShowEulaScreen();
 
   // Use |watch_new_webcontents| because the EULA webview has not navigated yet.
-  std::string https_reply_content = RequestClientCertTestPageInFrame(
-      "cros-eula-frame", true /* watch_new_webcontents */);
+  const std::string https_reply_content =
+      RequestClientCertTestPageInFrame("cros-eula-frame");
   EXPECT_EQ("got no client cert", https_reply_content);
 }
 
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 6348208..301d22f 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -213,7 +213,7 @@
           DeviceNetworkConfigurationUpdater::DeviceAssetIDFetcher());
   // NetworkCertLoader may be not initialized in tests.
   if (chromeos::NetworkCertLoader::IsInitialized()) {
-    chromeos::NetworkCertLoader::Get()->AddPolicyCertificateProvider(
+    chromeos::NetworkCertLoader::Get()->SetDevicePolicyCertificateProvider(
         device_network_configuration_updater_.get());
   }
 
@@ -247,8 +247,8 @@
 void BrowserPolicyConnectorChromeOS::Shutdown() {
   // NetworkCertLoader may be not initialized in tests.
   if (chromeos::NetworkCertLoader::IsInitialized()) {
-    chromeos::NetworkCertLoader::Get()->RemovePolicyCertificateProvider(
-        device_network_configuration_updater_.get());
+    chromeos::NetworkCertLoader::Get()->SetDevicePolicyCertificateProvider(
+        nullptr);
   }
   device_network_configuration_updater_.reset();
 
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index eafb8df..3388e7c 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -69,6 +69,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using testing::_;
 using testing::AnyNumber;
 using testing::AtMost;
 using testing::DoAll;
@@ -79,7 +80,6 @@
 using testing::SetArgPointee;
 using testing::StrictMock;
 using testing::WithArgs;
-using testing::_;
 
 namespace em = enterprise_management;
 
@@ -127,10 +127,7 @@
   DeviceCloudPolicyManagerChromeOSTest()
       : fake_cryptohome_client_(new chromeos::FakeCryptohomeClient()),
         state_keys_broker_(&fake_session_manager_client_),
-        store_(nullptr),
-        test_shared_loader_factory_(
-            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-                &test_url_loader_factory_)) {
+        store_(nullptr) {
     fake_statistics_provider_.SetMachineStatistic(
         chromeos::system::kSerialNumberKeyForTest, "test_sn");
     fake_statistics_provider_.SetMachineStatistic(
@@ -171,13 +168,13 @@
     // SharedURLLoaderFactory and LocalState singletons have to be set since
     // they are accessed by EnrollmentHandlerChromeOS and StartupUtils.
     TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory(
-        test_shared_loader_factory_);
+        test_url_loader_factory_.GetSafeWeakWrapper());
     TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
 
     // SystemSaltGetter is used in DeviceOAuth2TokenService.
     chromeos::SystemSaltGetter::Initialize();
     chromeos::DeviceOAuth2TokenServiceFactory::Initialize(
-        test_shared_loader_factory_, &local_state_);
+        test_url_loader_factory_.GetSafeWeakWrapper(), &local_state_);
 
     url_fetcher_response_code_ = net::HTTP_OK;
     url_fetcher_response_string_ = "{\"access_token\":\"accessToken4Test\","
@@ -209,7 +206,6 @@
     chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
     chromeos::SystemSaltGetter::Shutdown();
     TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
-    test_shared_loader_factory_->Detach();
   }
 
   void LockDevice() {
@@ -239,7 +235,7 @@
     initializer_->SetSigningServiceForTesting(
         std::make_unique<FakeSigningService>());
     initializer_->SetSystemURLLoaderFactoryForTesting(
-        test_shared_loader_factory_);
+        test_url_loader_factory_.GetSafeWeakWrapper());
     initializer_->Init();
   }
 
@@ -288,8 +284,6 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
 
  private:
-  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
-      test_shared_loader_factory_;
   // This property is required to instantiate the session manager, a singleton
   // which is used by the device status collector.
   session_manager::SessionManager session_manager_;
@@ -663,8 +657,7 @@
                 data.certificate_type());
       req->CopyFrom(data.device_register_request());
     } else {
-      req->CopyFrom(
-          register_request_.register_request());
+      req->CopyFrom(register_request_.register_request());
     }
     return req;
   }
@@ -766,16 +759,14 @@
   session_manager_client_.set_store_policy_success(false);
   RunTest();
   ExpectFailedEnrollment(EnrollmentStatus::STORE_ERROR);
-  EXPECT_EQ(CloudPolicyStore::STATUS_STORE_ERROR,
-            status_.store_status());
+  EXPECT_EQ(CloudPolicyStore::STATUS_STORE_ERROR, status_.store_status());
 }
 
 TEST_P(DeviceCloudPolicyManagerChromeOSEnrollmentTest, LoadError) {
   loaded_blob_.clear();
   RunTest();
   ExpectFailedEnrollment(EnrollmentStatus::STORE_ERROR);
-  EXPECT_EQ(CloudPolicyStore::STATUS_LOAD_ERROR,
-            status_.store_status());
+  EXPECT_EQ(CloudPolicyStore::STATUS_LOAD_ERROR, status_.store_status());
 }
 
 TEST_P(DeviceCloudPolicyManagerChromeOSEnrollmentTest, UnregisterSucceeds) {
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 3ad4c033..b9e1714 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -387,14 +387,14 @@
     }
   }
 
-  if (policy.has_device_reboot_after_user_signout()) {
-    const em::DeviceRebootAfterUserSignoutProto& container(
-        policy.device_reboot_after_user_signout());
-    if (container.has_reboot_after_signout_mode()) {
+  if (policy.has_device_reboot_on_user_signout()) {
+    const em::DeviceRebootOnUserSignoutProto& container(
+        policy.device_reboot_on_user_signout());
+    if (container.has_reboot_on_signout_mode()) {
       policies->Set(
-          key::kDeviceRebootAfterUserSignout, POLICY_LEVEL_MANDATORY,
+          key::kDeviceRebootOnUserSignout, POLICY_LEVEL_MANDATORY,
           POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-          std::make_unique<base::Value>(container.reboot_after_signout_mode()),
+          std::make_unique<base::Value>(container.reboot_on_signout_mode()),
           nullptr);
     }
   }
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
index 5feacd5..a39f5de 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
@@ -130,7 +130,7 @@
 bool DeviceCommandScreenshotJob::ParseCommandPayload(
     const std::string& command_payload) {
   std::unique_ptr<base::Value> root(
-      base::JSONReader().ReadToValue(command_payload));
+      base::JSONReader().ReadToValueDeprecated(command_payload));
   if (!root.get())
     return false;
   base::DictionaryValue* payload = nullptr;
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc
index 3810e21..910a4bd 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc
@@ -35,7 +35,7 @@
 bool DeviceCommandSetVolumeJob::ParseCommandPayload(
     const std::string& command_payload) {
   std::unique_ptr<base::Value> root(
-      base::JSONReader().ReadToValue(command_payload));
+      base::JSONReader().ReadToValueDeprecated(command_payload));
   if (!root.get())
     return false;
   base::DictionaryValue* payload = nullptr;
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc
index 2a1f9208..cf3a1794 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc
@@ -139,7 +139,7 @@
 bool DeviceCommandStartCRDSessionJob::ParseCommandPayload(
     const std::string& command_payload) {
   std::unique_ptr<base::Value> root(
-      base::JSONReader().ReadToValue(command_payload));
+      base::JSONReader().ReadToValueDeprecated(command_payload));
   if (!root)
     return false;
   if (!root->is_dict())
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
index 26653ad6..82bb1b4 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
@@ -30,8 +30,10 @@
 
 UserNetworkConfigurationUpdater::~UserNetworkConfigurationUpdater() {
   // NetworkCertLoader may be not initialized in tests.
-  if (chromeos::NetworkCertLoader::IsInitialized())
-    chromeos::NetworkCertLoader::Get()->RemovePolicyCertificateProvider(this);
+  if (chromeos::NetworkCertLoader::IsInitialized()) {
+    chromeos::NetworkCertLoader::Get()->SetUserPolicyCertificateProvider(
+        nullptr);
+  }
 }
 
 // static
@@ -84,7 +86,7 @@
   // only created for the primary profile. NetworkCertLoader may be not
   // initialized in tests.
   if (chromeos::NetworkCertLoader::IsInitialized())
-    chromeos::NetworkCertLoader::Get()->AddPolicyCertificateProvider(this);
+    chromeos::NetworkCertLoader::Get()->SetUserPolicyCertificateProvider(this);
 }
 
 void UserNetworkConfigurationUpdater::ImportClientCertificates() {
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
index 1e68bb9..434f9f7 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
@@ -122,10 +122,7 @@
   }
 
   // chromeos::NetworkCertLoader::Observer
-  void OnCertificatesLoaded(
-      const net::ScopedCERTCertificateList& all_certs) override {
-    run_loop_.Quit();
-  }
+  void OnCertificatesLoaded() override { run_loop_.Quit(); }
 
   void Wait() { run_loop_.Run(); }
 
@@ -336,10 +333,11 @@
   return cert_found;
 }
 
-bool IsCertInCertificateList(const net::X509Certificate* cert,
-                             const net::ScopedCERTCertificateList& cert_list) {
-  for (const auto& cert_list_element : cert_list) {
-    if (net::x509_util::IsSameCertificate(cert_list_element.get(), cert))
+bool IsCertInCertificateList(
+    const net::X509Certificate* cert,
+    const chromeos::NetworkCertLoader::NetworkCertList& network_cert_list) {
+  for (const auto& network_cert : network_cert_list) {
+    if (net::x509_util::IsSameCertificate(network_cert.cert(), cert))
       return true;
   }
   return false;
@@ -408,9 +406,9 @@
   ASSERT_TRUE(chromeos::NetworkCertLoader::IsInitialized());
   chromeos::NetworkCertLoader::Get()->SetUserNSSDB(test_nss_cert_db_.get());
 
-  EXPECT_FALSE(
-      IsCertInCertificateList(user_policy_certs_helper_.root_cert().get(),
-                              chromeos::NetworkCertLoader::Get()->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(
+      user_policy_certs_helper_.root_cert().get(),
+      chromeos::NetworkCertLoader::Get()->authority_certs()));
   NetworkCertLoaderTestObserver network_cert_loader_observer(
       chromeos::NetworkCertLoader::Get());
   user_policy_certs_helper_.SetRootCertONCUserPolicy(browser()->profile());
@@ -419,9 +417,9 @@
   // Check that |NetworkCertLoader| is aware of the authority certificate.
   // (Web Trust does not matter for the NetworkCertLoader, but we currently only
   // set a policy with a certificate requesting Web Trust here).
-  EXPECT_TRUE(
-      IsCertInCertificateList(user_policy_certs_helper_.root_cert().get(),
-                              chromeos::NetworkCertLoader::Get()->all_certs()));
+  EXPECT_TRUE(IsCertInCertificateList(
+      user_policy_certs_helper_.root_cert().get(),
+      chromeos::NetworkCertLoader::Get()->authority_certs()));
 }
 
 // Base class for testing policy-provided trust roots with device-local
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 7f9b4de..37147210 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -84,7 +84,7 @@
     kDeviceQuirksDownloadEnabled,
     kDeviceUnaffiliatedCrostiniAllowed,
     kDeviceDisplayResolution,
-    kDeviceRebootAfterUserSignout,
+    kDeviceRebootOnUserSignout,
     kDisplayRotationDefault,
     kExtensionCacheSize,
     kHeartbeatEnabled,
@@ -753,13 +753,13 @@
     new_values_cache->SetValue(kDeviceNativePrintersWhitelist, std::move(list));
   }
 
-  if (policy.has_device_reboot_after_user_signout()) {
-    const em::DeviceRebootAfterUserSignoutProto& container(
-        policy.device_reboot_after_user_signout());
-    if (container.has_reboot_after_signout_mode()) {
+  if (policy.has_device_reboot_on_user_signout()) {
+    const em::DeviceRebootOnUserSignoutProto& container(
+        policy.device_reboot_on_user_signout());
+    if (container.has_reboot_on_signout_mode()) {
       new_values_cache->SetValue(
-          kDeviceRebootAfterUserSignout,
-          base::Value(container.reboot_after_signout_mode()));
+          kDeviceRebootOnUserSignout,
+          base::Value(container.reboot_on_signout_mode()));
     }
   }
 }
diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
index 227fe188..5bd7af1 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
@@ -262,12 +262,12 @@
     BuildAndInstallDevicePolicy();
   }
 
-  void SetDeviceRebootAfterUserSignout(
-      em::DeviceRebootAfterUserSignoutProto::RebootOnSignoutMode value) {
+  void SetDeviceRebootOnUserSignout(
+      em::DeviceRebootOnUserSignoutProto::RebootOnSignoutMode value) {
     EXPECT_CALL(*this, SettingChanged(_)).Times(AtLeast(1));
-    em::DeviceRebootAfterUserSignoutProto* proto =
-        device_policy_.payload().mutable_device_reboot_after_user_signout();
-    proto->set_reboot_after_signout_mode(value);
+    em::DeviceRebootOnUserSignoutProto* proto =
+        device_policy_.payload().mutable_device_reboot_on_user_signout();
+    proto->set_reboot_on_signout_mode(value);
     device_policy_.Build();
     session_manager_client_.set_device_policy(device_policy_.GetBlob());
     ReloadDeviceSettings();
@@ -693,26 +693,26 @@
 }
 
 TEST_F(DeviceSettingsProviderTest, DeviceRebootAfterUserSignout) {
-  using PolicyProto = em::DeviceRebootAfterUserSignoutProto;
+  using PolicyProto = em::DeviceRebootOnUserSignoutProto;
 
-  VerifyPolicyValue(kDeviceRebootAfterUserSignout, nullptr);
+  VerifyPolicyValue(kDeviceRebootOnUserSignout, nullptr);
 
   {
-    SetDeviceRebootAfterUserSignout(PolicyProto::NEVER);
+    SetDeviceRebootOnUserSignout(PolicyProto::NEVER);
     base::Value expected_value(PolicyProto::NEVER);
-    VerifyPolicyValue(kDeviceRebootAfterUserSignout, &expected_value);
+    VerifyPolicyValue(kDeviceRebootOnUserSignout, &expected_value);
   }
 
   {
-    SetDeviceRebootAfterUserSignout(PolicyProto::ARC_SESSION);
+    SetDeviceRebootOnUserSignout(PolicyProto::ARC_SESSION);
     base::Value expected_value(PolicyProto::ARC_SESSION);
-    VerifyPolicyValue(kDeviceRebootAfterUserSignout, &expected_value);
+    VerifyPolicyValue(kDeviceRebootOnUserSignout, &expected_value);
   }
 
   {
-    SetDeviceRebootAfterUserSignout(PolicyProto::ALWAYS);
+    SetDeviceRebootOnUserSignout(PolicyProto::ALWAYS);
     base::Value expected_value(PolicyProto::ALWAYS);
-    VerifyPolicyValue(kDeviceRebootAfterUserSignout, &expected_value);
+    VerifyPolicyValue(kDeviceRebootOnUserSignout, &expected_value);
   }
 }
 
diff --git a/chrome/browser/conflicts/module_info_util_win.h b/chrome/browser/conflicts/module_info_util_win.h
index 2641cd28..8bd90ea 100644
--- a/chrome/browser/conflicts/module_info_util_win.h
+++ b/chrome/browser/conflicts/module_info_util_win.h
@@ -37,8 +37,8 @@
   // NO_CERTIFICATE.
   base::FilePath path;
 
-  // The "Subject" name of the certificate. This is the signer (ie,
-  // "Google Inc." or "Microsoft Inc.").
+  // The "Subject" name of the certificate. This is the signer (e.g.,
+  // "Google LLC" or "Microsoft Corporation").
   base::string16 subject;
 };
 
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
index 748e882..2763812 100644
--- a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
@@ -22,10 +22,14 @@
 #endif
 
 namespace {
+
 // Returns true if the module is signed by Google.
 bool IsGoogleModule(base::StringPiece16 subject) {
-  static const wchar_t kGoogle[] = L"Google Inc";
-  return subject == kGoogle;
+  static constexpr base::StringPiece16 kGoogleLlc(
+      STRING16_LITERAL("Google LLC"));
+  static constexpr base::StringPiece16 kGoogleInc(
+      STRING16_LITERAL("Google Inc"));
+  return subject == kGoogleLlc || subject == kGoogleInc;
 }
 
 }  // namespace
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
index 96266dc..7749d2c 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -27,6 +27,7 @@
 #include "components/data_reduction_proxy/proto/client_config.pb.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/network_service_instance.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
@@ -73,7 +74,7 @@
 
 void SimulateNetworkChange(network::mojom::ConnectionType type) {
   if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-      !content::IsNetworkServiceRunningInProcess()) {
+      !content::IsInProcessNetworkService()) {
     network::mojom::NetworkServiceTestPtr network_service_test;
     content::ServiceManagerConnection::GetForProcess()
         ->GetConnector()
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc
index 60a5d1d..faf2dc8 100644
--- a/chrome/browser/download/notification/download_notification_browsertest.cc
+++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -39,6 +39,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_item_utils.h"
 #include "content/public/browser/download_manager.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
 #include "content/public/test/url_loader_interceptor.h"
@@ -276,7 +277,7 @@
         browser()->profile());
 
     if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-        !content::IsNetworkServiceRunningInProcess()) {
+        !content::IsInProcessNetworkService()) {
       interceptor_ = std::make_unique<SlowDownloadInterceptor>();
     } else {
       base::PostTaskWithTraits(
diff --git a/chrome/browser/extensions/api/declarative_net_request/rule_indexing_unittest.cc b/chrome/browser/extensions/api/declarative_net_request/rule_indexing_unittest.cc
index 19e3f5d..0191dbe1 100644
--- a/chrome/browser/extensions/api/declarative_net_request/rule_indexing_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/rule_indexing_unittest.cc
@@ -421,7 +421,7 @@
       }
     ]
   )";
-  SetRules(base::JSONReader::Read(kRules));
+  SetRules(base::JSONReader::ReadDeprecated(kRules));
 
   extension_loader()->set_ignore_manifest_warnings(true);
   LoadAndExpectSuccess(1 /* rules count */);
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
index 0dfad1b..23d4a382 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -59,8 +59,6 @@
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/value_builder.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
@@ -155,7 +153,8 @@
 
 class TestListener : public content::NotificationObserver {
  public:
-  TestListener(const std::string& message, const base::Closure& callback)
+  TestListener(const std::string& message,
+               const base::RepeatingClosure& callback)
       : message_(message), callback_(callback) {
     registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_TEST_MESSAGE,
                    content::NotificationService::AllSources());
@@ -172,7 +171,7 @@
 
  private:
   std::string message_;
-  base::Closure callback_;
+  base::RepeatingClosure callback_;
 
   content::NotificationRegistrar registrar_;
 
@@ -493,22 +492,6 @@
     return std::make_unique<TestNetworkingCastPrivateDelegate>();
   }
 
-  bool SetupCertificates() {
-    base::ScopedAllowBlockingForTesting allow_io;
-    net::ScopedCERTCertificateList cert_list =
-        net::CreateCERTCertificateListFromFile(
-            net::GetTestCertsDirectory(), "client_1_ca.pem",
-            net::X509Certificate::FORMAT_AUTO);
-    if (cert_list.empty())
-      return false;
-    // TODO(stevenjb): Figure out a simple way to import a test user cert.
-
-    chromeos::NetworkHandler::Get()
-        ->network_certificate_handler()
-        ->SetCertificatesForTest(cert_list);
-    return true;
-  }
-
  protected:
   NetworkPortalDetectorTestImpl* detector() { return detector_; }
 
@@ -820,11 +803,12 @@
 
 IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
                        OnCertificateListsChangedEvent) {
-  TestListener listener("eventListenerReady", base::Bind([]() {
-                          chromeos::NetworkHandler::Get()
-                              ->network_certificate_handler()
-                              ->NotifyCertificatsChangedForTest();
-                        }));
+  TestListener listener(
+      "eventListenerReady", base::BindRepeating([]() {
+        chromeos::NetworkHandler::Get()
+            ->network_certificate_handler()
+            ->AddAuthorityCertificateForTest("authority_cert");
+      }));
   EXPECT_TRUE(RunNetworkingSubtest("onCertificateListsChangedEvent"))
       << message_;
 }
@@ -969,7 +953,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetCertificateLists) {
-  ASSERT_TRUE(SetupCertificates());
+  chromeos::NetworkHandler::Get()
+      ->network_certificate_handler()
+      ->AddAuthorityCertificateForTest("authority_cert");
   EXPECT_TRUE(RunNetworkingSubtest("getCertificateLists")) << message_;
 }
 
diff --git a/chrome/browser/extensions/background_xhr_browsertest.cc b/chrome/browser/extensions/background_xhr_browsertest.cc
index e24cede..4a2f7d14 100644
--- a/chrome/browser/extensions/background_xhr_browsertest.cc
+++ b/chrome/browser/extensions/background_xhr_browsertest.cc
@@ -142,7 +142,7 @@
     std::string json;
     EXPECT_TRUE(message_queue.WaitForMessage(&json));
     base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
-    std::unique_ptr<base::Value> value = reader.ReadToValue(json);
+    std::unique_ptr<base::Value> value = reader.ReadToValueDeprecated(json);
     std::string result;
     EXPECT_TRUE(value->GetAsString(&result));
     EXPECT_TRUE(result == "true" || result == "false") << result;
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
index a642984..84a7aea 100644
--- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
+++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -222,7 +222,7 @@
     std::string json;
     EXPECT_TRUE(message_queue->WaitForMessage(&json));
     base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
-    std::unique_ptr<base::Value> value = reader.ReadToValue(json);
+    std::unique_ptr<base::Value> value = reader.ReadToValueDeprecated(json);
     std::string result;
     EXPECT_TRUE(value->GetAsString(&result));
     return result;
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index d1e657a..15493f7 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -210,7 +210,6 @@
 
   const ManagementPolicy* policy = extensions::ExtensionSystem::Get(
       extension_service_->profile())->management_policy();
-  bool force_disabled = false;
 
   if (extension_prefs_->IsExtensionDisabled(extension->id())) {
     int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
@@ -243,13 +242,9 @@
     disable_reason::DisableReason disable_reason = disable_reason::DISABLE_NONE;
     if (policy->MustRemainDisabled(extension.get(), &disable_reason, nullptr)) {
       extension_prefs_->SetExtensionDisabled(extension->id(), disable_reason);
-      force_disabled = true;
     }
   }
 
-  UMA_HISTOGRAM_BOOLEAN("ExtensionInstalledLoader.ForceDisabled2",
-                        force_disabled);
-
   if (write_to_prefs)
     extension_prefs_->UpdateManifest(extension.get());
 
diff --git a/chrome/browser/extensions/updater/update_service_browsertest.cc b/chrome/browser/extensions/updater/update_service_browsertest.cc
index 3d5136b..47d498f7 100644
--- a/chrome/browser/extensions/updater/update_service_browsertest.cc
+++ b/chrome/browser/extensions/updater/update_service_browsertest.cc
@@ -118,7 +118,7 @@
   const std::string update_request =
       std::get<0>(update_interceptor_->GetRequests()[0]);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(update_request);
+    const auto root = base::JSONReader().ReadDeprecated(update_request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.10", app.FindKey("version")->GetString());
@@ -190,7 +190,7 @@
   const std::string update_request =
       std::get<0>(update_interceptor_->GetRequests()[0]);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(update_request);
+    const auto root = base::JSONReader().ReadDeprecated(update_request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.10", app.FindKey("version")->GetString());
@@ -353,7 +353,7 @@
   const std::string update_request =
       std::get<0>(update_interceptor_->GetRequests()[0]);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(update_request);
+    const auto root = base::JSONReader().ReadDeprecated(update_request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.10", app.FindKey("version")->GetString());
@@ -458,7 +458,7 @@
   const std::string update_request =
       std::get<0>(update_interceptor_->GetRequests()[0]);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(update_request);
+    const auto root = base::JSONReader().ReadDeprecated(update_request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.0.0.0", app.FindKey("version")->GetString());
@@ -704,7 +704,7 @@
   const std::string update_request =
       std::get<0>(update_interceptor_->GetRequests()[0]);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(update_request);
+    const auto root = base::JSONReader().ReadDeprecated(update_request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(id_, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.0.0.0", app.FindKey("version")->GetString());
@@ -835,7 +835,7 @@
   const std::string update_request =
       std::get<0>(update_interceptor_->GetRequests()[0]);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(update_request);
+    const auto root = base::JSONReader().ReadDeprecated(update_request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(id_, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.0.0.0", app.FindKey("version")->GetString());
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 5796a493..2c4cbdf3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -457,11 +457,6 @@
     "expiry_milestone": 77
   },
   {
-    "name": "crostini-files",
-    "owners": [ "joelhockey", "nverne", "benwells" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "crostini-usb-support",
     "owners": [ "jopra", "nverne", "benwells" ],
     "expiry_milestone": 76
@@ -610,11 +605,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "disable-software-rasterizer",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "disable-system-timezone-automatic-detection",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index e319c983..89b70b4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -496,11 +496,6 @@
 const char kEnableCaptivePortalRandomUrlDescription[] =
     "Enable Captive Portal URL randomization.";
 
-const char kEnableChromevoxDeveloperOptionName[] =
-    "Enable Chromevox developer option";
-const char kEnableChromevoxDeveloperOptionDescription[] =
-    "This option provides tools for developing in chromevox.";
-
 const char kEnableDataSaverLiteModeRebrandName[] =
     "Data Saver Lite Mode Rebranding";
 const char kEnableDataSaverLiteModeRebrandDescription[] =
@@ -1680,12 +1675,6 @@
     "Extend byte-for-byte update check for scripts that are imported by the "
     "service worker script via importScripts().";
 
-const char kServiceWorkerServicificationName[] = "Servicified service workers";
-const char kServiceWorkerServicificationDescription[] =
-    "Enable the servicified service workers. A servicified service worker can "
-    "have direct connection from its clients, so that fetch events can be "
-    "dispatched through the connection without hopping to the browser process.";
-
 const char kServiceWorkerLongRunningMessageName[] =
     "Service worker long running message dispatch.";
 const char kServiceWorkerLongRunningMessageDescription[] =
@@ -1777,10 +1766,6 @@
 const char kSmoothScrollingDescription[] =
     "Animate smoothly when scrolling page content.";
 
-const char kSoftwareRasterizerName[] = "3D software rasterizer";
-const char kSoftwareRasterizerDescription[] =
-    "Fall back to a 3D software rasterizer when the GPU cannot be used.";
-
 const char kSoleIntegrationName[] = "Sole integration";
 const char kSoleIntegrationDescription[] =
     "Enable Sole integration for browser customization. You must restart "
@@ -2688,15 +2673,25 @@
     "Forces the update menu type to a specific type";
 const char kUpdateMenuTypeDescription[] =
     "When set, forces the update type to be a specific one, which impacts "
-    "the app menu badge and menu item for updates.";
+    "the app menu badge and menu item for updates. For Inline Update, the "
+    "update available flag is implied. The 'Inline Update: Success' selection "
+    "goes through the whole inline update flow to the end with a successful "
+    "outcome. The other 'Inline Update' options go through the same flow, but "
+    "stop at various stages, see their error type for details.";
 const char kUpdateMenuTypeNone[] = "None";
 const char kUpdateMenuTypeUpdateAvailable[] = "Update Available";
 const char kUpdateMenuTypeUnsupportedOSVersion[] = "Unsupported OS Version";
-const char kUpdateMenuTypeInlineUpdateAvailable[] = "Inline Update Available";
-const char kUpdateMenuTypeInlineUpdateDownloading[] =
-    "Inline Update Downloading";
-const char kUpdateMenuTypeInlineUpdateReady[] = "Inline Update Ready";
-const char kUpdateMenuTypeInlineUpdateFailed[] = "Inline Update Failed";
+const char kUpdateMenuTypeInlineUpdateSuccess[] = "Inline Update: Success";
+const char kUpdateMenuTypeInlineUpdateDialogCanceled[] =
+    "Inline Update Error: Dialog Canceled";
+const char kUpdateMenuTypeInlineUpdateDialogFailed[] =
+    "Inline Update Error: Dialog Failed";
+const char kUpdateMenuTypeInlineUpdateDownloadFailed[] =
+    "Inline Update Error: Download Failed";
+const char kUpdateMenuTypeInlineUpdateDownloadCanceled[] =
+    "Inline Update Error: Download Canceled";
+const char kUpdateMenuTypeInlineUpdateInstallFailed[] =
+    "Inline Update Error: Install Failed";
 
 const char kThirdPartyDoodlesName[] =
     "Enable Doodles for third-party search engines";
@@ -3093,10 +3088,6 @@
 const char kCrostiniBackupName[] = "Crostini Backup";
 const char kCrostiniBackupDescription[] = "Enable Crostini export and import.";
 
-const char kCrostiniFilesName[] = "Crostini Files";
-const char kCrostiniFilesDescription[] =
-    "Enable Crostini file sharing in Files app.";
-
 const char kCrostiniUsbSupportName[] = "Crostini Usb Support";
 const char kCrostiniUsbSupportDescription[] =
     "Enable mounting Usb devices in Crostini.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f4110b9..8434d8d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -333,9 +333,6 @@
 extern const char kEnableCaptivePortalRandomUrl[];
 extern const char kEnableCaptivePortalRandomUrlDescription[];
 
-extern const char kEnableChromevoxDeveloperOptionName[];
-extern const char kEnableChromevoxDeveloperOptionDescription[];
-
 extern const char kEnableDataSaverLiteModeRebrandName[];
 extern const char kEnableDataSaverLiteModeRebrandDescription[];
 
@@ -1001,9 +998,6 @@
 extern const char kServiceWorkerImportedScriptUpdateCheckName[];
 extern const char kServiceWorkerImportedScriptUpdateCheckDescription[];
 
-extern const char kServiceWorkerServicificationName[];
-extern const char kServiceWorkerServicificationDescription[];
-
 extern const char kServiceWorkerLongRunningMessageName[];
 extern const char kServiceWorkerLongRunningMessageDescription[];
 
@@ -1057,9 +1051,6 @@
 extern const char kSmoothScrollingName[];
 extern const char kSmoothScrollingDescription[];
 
-extern const char kSoftwareRasterizerName[];
-extern const char kSoftwareRasterizerDescription[];
-
 extern const char kSoleIntegrationName[];
 extern const char kSoleIntegrationDescription[];
 
@@ -1587,10 +1578,12 @@
 extern const char kUpdateMenuTypeNone[];
 extern const char kUpdateMenuTypeUpdateAvailable[];
 extern const char kUpdateMenuTypeUnsupportedOSVersion[];
-extern const char kUpdateMenuTypeInlineUpdateAvailable[];
-extern const char kUpdateMenuTypeInlineUpdateDownloading[];
-extern const char kUpdateMenuTypeInlineUpdateReady[];
-extern const char kUpdateMenuTypeInlineUpdateFailed[];
+extern const char kUpdateMenuTypeInlineUpdateSuccess[];
+extern const char kUpdateMenuTypeInlineUpdateDialogCanceled[];
+extern const char kUpdateMenuTypeInlineUpdateDialogFailed[];
+extern const char kUpdateMenuTypeInlineUpdateDownloadFailed[];
+extern const char kUpdateMenuTypeInlineUpdateDownloadCanceled[];
+extern const char kUpdateMenuTypeInlineUpdateInstallFailed[];
 
 extern const char kThirdPartyDoodlesName[];
 extern const char kThirdPartyDoodlesDescription[];
@@ -1855,9 +1848,6 @@
 extern const char kCrostiniBackupName[];
 extern const char kCrostiniBackupDescription[];
 
-extern const char kCrostiniFilesName[];
-extern const char kCrostiniFilesDescription[];
-
 extern const char kCrostiniUsbSupportName[];
 extern const char kCrostiniUsbSupportDescription[];
 
diff --git a/chrome/browser/metrics/perf/perf_output.cc b/chrome/browser/metrics/perf/perf_output.cc
index 54b715e..a5730a8 100644
--- a/chrome/browser/metrics/perf/perf_output.cc
+++ b/chrome/browser/metrics/perf/perf_output.cc
@@ -43,11 +43,11 @@
   // The callback may delete us, so it's hammertime: Can't touch |this|.
 }
 
-void PerfOutputCall::OnGetPerfOutput(bool success) {
+void PerfOutputCall::OnGetPerfOutput(base::Optional<uint64_t> result) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Signal pipe reader to shut down.
-  if (!success && perf_data_pipe_reader_.get()) {
+  if (!result.has_value() && perf_data_pipe_reader_.get()) {
     perf_data_pipe_reader_.reset();
     std::move(done_callback_).Run(std::string());
   }
diff --git a/chrome/browser/metrics/perf/perf_output.h b/chrome/browser/metrics/perf/perf_output.h
index 293c8f9..0ea2df5 100644
--- a/chrome/browser/metrics/perf/perf_output.h
+++ b/chrome/browser/metrics/perf/perf_output.h
@@ -38,7 +38,7 @@
  private:
   // Internal callbacks.
   void OnIOComplete(base::Optional<std::string> data);
-  void OnGetPerfOutput(bool success);
+  void OnGetPerfOutput(base::Optional<uint64_t> result);
 
   // Used to capture perf data written to a pipe.
   std::unique_ptr<chromeos::PipeReader> perf_data_pipe_reader_;
diff --git a/chrome/browser/net/chrome_network_service_restart_browsertest.cc b/chrome/browser/net/chrome_network_service_restart_browsertest.cc
index 951746b..e9c5330 100644
--- a/chrome/browser/net/chrome_network_service_restart_browsertest.cc
+++ b/chrome/browser/net/chrome_network_service_restart_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "services/network/public/cpp/features.h"
@@ -44,7 +45,7 @@
 // after crash.
 IN_PROC_BROWSER_TEST_F(ChromeNetworkServiceRestartBrowserTest,
                        StoragePartitionGetNetworkContext) {
-  if (content::IsNetworkServiceRunningInProcess())
+  if (content::IsInProcessNetworkService())
     return;
 #if defined(OS_MACOSX)
   // |NetworkServiceTestHelper| doesn't work on browser_tests on macOS.
@@ -74,7 +75,7 @@
 // after crash.
 IN_PROC_BROWSER_TEST_F(ChromeNetworkServiceRestartBrowserTest,
                        SystemNetworkContextManagerGetContext) {
-  if (content::IsNetworkServiceRunningInProcess())
+  if (content::IsInProcessNetworkService())
     return;
 #if defined(OS_MACOSX)
   // |NetworkServiceTestHelper| doesn't work on browser_tests on macOS.
diff --git a/chrome/browser/net/network_connection_tracker_browsertest.cc b/chrome/browser/net/network_connection_tracker_browsertest.cc
index 6499b47..ef006af 100644
--- a/chrome/browser/net/network_connection_tracker_browsertest.cc
+++ b/chrome/browser/net/network_connection_tracker_browsertest.cc
@@ -94,8 +94,7 @@
 
   // Simulates a network connection change.
   void SimulateNetworkChange(network::mojom::ConnectionType type) {
-    if (network_service_enabled_ &&
-        !content::IsNetworkServiceRunningInProcess()) {
+    if (network_service_enabled_ && !content::IsInProcessNetworkService()) {
       network::mojom::NetworkServiceTestPtr network_service_test;
       content::ServiceManagerConnection::GetForProcess()
           ->GetConnector()
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index cc2521b..938b68d 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -46,6 +46,7 @@
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/simple_url_loader_test_helper.h"
@@ -589,13 +590,13 @@
   bool IsRestartStateWithInProcessNetworkService() {
     return GetParam().network_service_state ==
                NetworkServiceState::kRestarted &&
-           content::IsNetworkServiceRunningInProcess();
+           content::IsInProcessNetworkService();
   }
 
  private:
   void SimulateNetworkServiceCrashIfNecessary() {
     if (GetParam().network_service_state != NetworkServiceState::kRestarted ||
-        content::IsNetworkServiceRunningInProcess()) {
+        content::IsInProcessNetworkService()) {
       return;
     }
 
diff --git a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
index 2f92419..39c29b04 100644
--- a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
@@ -13,12 +13,12 @@
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "chrome/browser/previews/previews_content_util.h"
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/previews/content/previews_content_util.h"
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/previews_experiments.h"
 #include "content/public/browser/navigation_handle.h"
diff --git a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
index f57cf73..e70ffeed 100644
--- a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
@@ -14,11 +14,11 @@
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "chrome/browser/previews/previews_content_util.h"
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/previews/content/previews_content_util.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/previews_state.h"
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index a91d698..956aafd8 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -38,7 +38,6 @@
 #include "services/media_session/public/cpp/features.h"
 #include "skia/ext/image_operations.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "ui/aura/window.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -77,8 +76,6 @@
   MOCK_METHOD2(Close, void(bool, bool));
   MOCK_METHOD0(CloseAndFocusInitiator, void());
   MOCK_METHOD0(OnWindowDestroyed, void());
-  MOCK_METHOD1(SetPictureInPictureCustomControls,
-               void(const std::vector<blink::PictureInPictureControlInfo>&));
   MOCK_METHOD2(EmbedSurface, void(const viz::SurfaceId&, const gfx::Size&));
   MOCK_METHOD0(GetWindowForTesting, content::OverlayWindow*());
   MOCK_METHOD0(UpdateLayerBounds, void());
@@ -86,7 +83,6 @@
   MOCK_METHOD0(GetInitiatorWebContents, content::WebContents*());
   MOCK_METHOD2(UpdatePlaybackState, void(bool, bool));
   MOCK_METHOD0(TogglePlayPause, bool());
-  MOCK_METHOD1(CustomControlPressed, void(const std::string&));
   MOCK_METHOD1(SetAlwaysHidePlayPauseButton, void(bool));
   MOCK_METHOD0(SkipAd, void());
   MOCK_METHOD0(NextTrack, void());
@@ -183,16 +179,6 @@
   DISALLOW_COPY_AND_ASSIGN(PictureInPictureWindowControllerBrowserTest);
 };
 
-class ControlPictureInPictureWindowControllerBrowserTest
-    : public PictureInPictureWindowControllerBrowserTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    PictureInPictureWindowControllerBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(
-        switches::kEnableExperimentalWebPlatformFeatures);
-  }
-};
-
 // Checks the creation of the window controller, as well as basic window
 // creation, visibility and activation.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
@@ -456,160 +442,6 @@
                 .WaitAndGetTitle());
 }
 
-// Tests that when a custom control is clicked on a Picture-in-Picture window
-// an event is sent to the caller.
-IN_PROC_BROWSER_TEST_F(ControlPictureInPictureWindowControllerBrowserTest,
-                       PictureInPictureControlEventFired) {
-  GURL test_page_url = ui_test_utils::GetTestUrl(
-      base::FilePath(base::FilePath::kCurrentDirectory),
-      base::FilePath(
-          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
-  ui_test_utils::NavigateToURL(browser(), test_page_url);
-
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(active_web_contents);
-
-  SetUpWindowController(active_web_contents);
-  ASSERT_TRUE(window_controller());
-
-  content::OverlayWindow* overlay_window =
-      window_controller()->GetWindowForTesting();
-  ASSERT_TRUE(overlay_window);
-  ASSERT_FALSE(overlay_window->IsVisible());
-
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "enterPictureInPicture();", &result));
-  EXPECT_TRUE(result);
-
-  std::string control_id = "Test custom control ID";
-  base::string16 expected_title = base::ASCIIToUTF16(control_id);
-
-  window_controller()->CustomControlPressed(control_id);
-
-  EXPECT_EQ(expected_title,
-            content::TitleWatcher(active_web_contents, expected_title)
-                .WaitAndGetTitle());
-}
-
-// Tests that when a custom control is clicked on a Picture-in-Picture window
-// with one custom control on it, the correct event is sent to the caller.
-IN_PROC_BROWSER_TEST_F(ControlPictureInPictureWindowControllerBrowserTest,
-                       PictureInPictureAddControlAndFireEvent) {
-  GURL test_page_url = ui_test_utils::GetTestUrl(
-      base::FilePath(base::FilePath::kCurrentDirectory),
-      base::FilePath(
-          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
-  ui_test_utils::NavigateToURL(browser(), test_page_url);
-
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(active_web_contents);
-
-  SetUpWindowController(active_web_contents);
-  ASSERT_TRUE(window_controller());
-
-  content::OverlayWindow* overlay_window =
-      window_controller()->GetWindowForTesting();
-  ASSERT_TRUE(overlay_window);
-  ASSERT_FALSE(overlay_window->IsVisible());
-
-  LoadTabAndEnterPictureInPicture(browser());
-
-  const std::string kControlId = "control_id";
-  EXPECT_EQ(true, content::EvalJs(
-                      active_web_contents,
-                      content::JsReplace("setControls([$1]);", kControlId)));
-
-  base::string16 expected_title = base::ASCIIToUTF16(kControlId);
-
-  window_controller()->CustomControlPressed(kControlId);
-  EXPECT_EQ(expected_title,
-            content::TitleWatcher(active_web_contents, expected_title)
-                .WaitAndGetTitle());
-}
-
-// Tests that when the first custom control added to a Picture-in-Picture window
-// with two custom controls on it is clicked the corresponding event is sent to
-// the caller.
-IN_PROC_BROWSER_TEST_F(ControlPictureInPictureWindowControllerBrowserTest,
-                       PictureInPictureAddTwoControlsAndFireLeftEvent) {
-  GURL test_page_url = ui_test_utils::GetTestUrl(
-      base::FilePath(base::FilePath::kCurrentDirectory),
-      base::FilePath(
-          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
-  ui_test_utils::NavigateToURL(browser(), test_page_url);
-
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(active_web_contents);
-
-  SetUpWindowController(active_web_contents);
-  ASSERT_TRUE(window_controller());
-
-  content::OverlayWindow* overlay_window =
-      window_controller()->GetWindowForTesting();
-  ASSERT_TRUE(overlay_window);
-  ASSERT_FALSE(overlay_window->IsVisible());
-
-  LoadTabAndEnterPictureInPicture(browser());
-
-  const std::string kLeftControlId = "left-control";
-  const std::string kRightControlId = "right-control";
-  EXPECT_EQ(true, content::EvalJs(
-                      active_web_contents,
-                      content::JsReplace("setControls([$1, $2]);",
-                                         kLeftControlId, kRightControlId)));
-
-  base::string16 left_expected_title = base::ASCIIToUTF16(kLeftControlId);
-
-  window_controller()->CustomControlPressed(kLeftControlId);
-  EXPECT_EQ(left_expected_title,
-            content::TitleWatcher(active_web_contents, left_expected_title)
-                .WaitAndGetTitle());
-}
-
-// Tests that when the second custom control added to a Picture-in-Picture
-// window with two custom controls on it is clicked the corresponding event is
-// sent to the caller.
-IN_PROC_BROWSER_TEST_F(ControlPictureInPictureWindowControllerBrowserTest,
-                       PictureInPictureAddTwoControlsAndFireRightEvent) {
-  GURL test_page_url = ui_test_utils::GetTestUrl(
-      base::FilePath(base::FilePath::kCurrentDirectory),
-      base::FilePath(
-          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
-  ui_test_utils::NavigateToURL(browser(), test_page_url);
-
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(active_web_contents);
-
-  SetUpWindowController(active_web_contents);
-  ASSERT_TRUE(window_controller());
-
-  content::OverlayWindow* overlay_window =
-      window_controller()->GetWindowForTesting();
-  ASSERT_TRUE(overlay_window);
-  ASSERT_FALSE(overlay_window->IsVisible());
-
-  LoadTabAndEnterPictureInPicture(browser());
-
-  const std::string kLeftControlId = "left-control";
-  const std::string kRightControlId = "right-control";
-  EXPECT_EQ(true, content::EvalJs(
-                      active_web_contents,
-                      content::JsReplace("setControls([$1, $2]);",
-                                         kLeftControlId, kRightControlId)));
-
-  base::string16 right_expected_title = base::ASCIIToUTF16(kRightControlId);
-
-  window_controller()->CustomControlPressed(kRightControlId);
-  EXPECT_EQ(right_expected_title,
-            content::TitleWatcher(active_web_contents, right_expected_title)
-                .WaitAndGetTitle());
-}
-
 #endif  // !defined(OS_ANDROID)
 
 // Tests that when closing a Picture-in-Picture window, the video element is
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 7a86f0c4..2836197 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -53,7 +53,6 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/policy/cloud/user_policy_signin_service_mobile.h"
-#include "components/signin/core/browser/child_account_info_fetcher_android.h"
 #else
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 #endif
@@ -766,15 +765,11 @@
 }
 
 TEST_F(UserPolicySigninServiceTest, SignOutThenSignInAgain) {
-#if defined(OS_ANDROID)
-  ChildAccountInfoFetcherAndroid::InitializeForTests();
-
   // Explicitly forcing this call is necessary for the clearing of the primary
   // account to result in the account being fully removed in this testing
-  // context.
+  // context
   identity_test_env()
       ->EnableOnAccountUpdatedAndOnAccountRemovedWithInfoCallbacks();
-#endif
 
   ASSERT_NO_FATAL_FAILURE(TestSuccessfulSignin());
 
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index e22aa126..dba4a56 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -5514,7 +5514,7 @@
                   update_disabled ? " updatedisabled=\"true\"" : "")));
   } else if (base::StartsWith(request, R"({"request":{)",
                               base::CompareCase::SENSITIVE)) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     ASSERT_TRUE(root);
     const auto* update_check =
         root->FindKey("request")->FindKey("app")->GetList()[0].FindKey(
diff --git a/chrome/browser/previews/OWNERS b/chrome/browser/previews/OWNERS
index 52c14e4..fd70f95 100644
--- a/chrome/browser/previews/OWNERS
+++ b/chrome/browser/previews/OWNERS
@@ -1 +1,3 @@
 file://components/previews/OWNERS
+
+# COMPONENT: Blink>Previews
diff --git a/components/previews/content/previews_content_util.cc b/chrome/browser/previews/previews_content_util.cc
similarity index 95%
rename from components/previews/content/previews_content_util.cc
rename to chrome/browser/previews/previews_content_util.cc
index 09cda2dc..02cb95e 100644
--- a/components/previews/content/previews_content_util.cc
+++ b/chrome/browser/previews/previews_content_util.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/previews/content/previews_content_util.h"
+#include "chrome/browser/previews/previews_content_util.h"
 
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -77,9 +77,12 @@
     has_page_hints = previews_decider->LoadPageHints(url);
   }
 
-  // Note: this is for the beginning of navigation so we should not
+  // Note: this is for the beginning of navigation/redirect so we should not
   // check for https here (since an http request may redirect to https).
-  if ((!has_page_hints || params::LitePagePreviewsOverridePageHints()) &&
+  // TODO(robertogden): Add other eligibility reasons and log scheme/other
+  // previews taking precedence, etc. https://crbug.com/921755
+  if (url.SchemeIsCryptographic() &&
+      (!has_page_hints || params::LitePagePreviewsOverridePageHints()) &&
       previews_decider->ShouldAllowPreviewAtNavigationStart(
           previews_data, url, is_reload,
           previews::PreviewsType::LITE_PAGE_REDIRECT)) {
diff --git a/components/previews/content/previews_content_util.h b/chrome/browser/previews/previews_content_util.h
similarity index 91%
rename from components/previews/content/previews_content_util.h
rename to chrome/browser/previews/previews_content_util.h
index 7a34605..f26a3d49 100644
--- a/components/previews/content/previews_content_util.h
+++ b/chrome/browser/previews/previews_content_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PREVIEWS_CONTENT_PREVIEWS_CONTENT_UTIL_H_
-#define COMPONENTS_PREVIEWS_CONTENT_PREVIEWS_CONTENT_UTIL_H_
+#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_CONTENT_UTIL_H_
+#define CHROME_BROWSER_PREVIEWS_PREVIEWS_CONTENT_UTIL_H_
 
 #include "components/previews/core/previews_decider.h"
 #include "content/public/common/previews_state.h"
@@ -47,4 +47,4 @@
 
 }  // namespace previews
 
-#endif  // COMPONENTS_PREVIEWS_CONTENT_PREVIEWS_CONTENT_UTIL_H_
+#endif  // CHROME_BROWSER_PREVIEWS_PREVIEWS_CONTENT_UTIL_H_
diff --git a/components/previews/content/previews_content_util_unittest.cc b/chrome/browser/previews/previews_content_util_unittest.cc
similarity index 97%
rename from components/previews/content/previews_content_util_unittest.cc
rename to chrome/browser/previews/previews_content_util_unittest.cc
index 902ffa75..a6ab179 100644
--- a/components/previews/content/previews_content_util_unittest.cc
+++ b/chrome/browser/previews/previews_content_util_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/previews/content/previews_content_util.h"
+#include "chrome/browser/previews/previews_content_util.h"
 
 #include <memory>
 #include <vector>
@@ -249,15 +249,16 @@
   bool is_reload = false;
   bool is_redirect = false;
   bool is_data_saver_user = true;
-  // Verify preview is enabled on HTTP and HTTPS.
+  // Verify preview is enabled on HTTPS.
   EXPECT_TRUE(content::LITE_PAGE_REDIRECT_ON &
               previews::DetermineAllowedClientPreviewsState(
                   &user_data, GURL("https://www.google.com"), is_reload,
                   is_redirect, is_data_saver_user, enabled_previews_decider()));
-  EXPECT_TRUE(content::LITE_PAGE_REDIRECT_ON &
-              previews::DetermineAllowedClientPreviewsState(
-                  &user_data, GURL("http://www.google.com"), is_reload,
-                  is_redirect, is_data_saver_user, enabled_previews_decider()));
+  EXPECT_FALSE(content::LITE_PAGE_REDIRECT_ON &
+               previews::DetermineAllowedClientPreviewsState(
+                   &user_data, GURL("http://www.google.com"), is_reload,
+                   is_redirect, is_data_saver_user,
+                   enabled_previews_decider()));
 
   // Verify non-HTTP[S] URL has no previews enabled.
   EXPECT_EQ(content::PREVIEWS_UNSPECIFIED,
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index 3ef580c9..efb48cc 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -763,12 +763,6 @@
     ui_test_utils::NavigateToURL(browser(), HttpLitePageURL(kSuccess));
     VerifyPreviewNotLoaded();
     ClearDeciderState();
-    histogram_tester.ExpectBucketCount(
-        "Previews.ServerLitePage.IneligibleReasons",
-        PreviewsLitePageNavigationThrottle::IneligibleReason::kNonHttpsScheme,
-        1);
-    histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
-                                       false, 1);
   }
 
   {
@@ -871,7 +865,7 @@
         ->ReportEffectiveConnectionTypeForTesting(
             net::EFFECTIVE_CONNECTION_TYPE_3G);
 
-    ui_test_utils::NavigateToURL(browser(), HttpLitePageURL(kSuccess));
+    ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
 
     VerifyPreviewNotLoaded();
     ClearDeciderState();
@@ -895,7 +889,7 @@
         ->ReportEffectiveConnectionTypeForTesting(
             net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
 
-    ui_test_utils::NavigateToURL(browser(), HttpLitePageURL(kSuccess));
+    ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
 
     VerifyPreviewNotLoaded();
     ClearDeciderState();
@@ -961,8 +955,6 @@
 
 IN_PROC_BROWSER_TEST_P(PreviewsLitePageServerBrowserTest,
                        DISABLE_ON_WIN_MAC(LitePagePreviewsReloadEnabled)) {
-  if (GetParam())
-    return;
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
       {}, {previews::features::kPreviewsDisallowedOnReloads});
@@ -986,8 +978,6 @@
 
 IN_PROC_BROWSER_TEST_P(PreviewsLitePageServerBrowserTest,
                        DISABLE_ON_WIN_MAC(LitePagePreviewsReloadDisabled)) {
-  if (GetParam())
-    return;
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
       {previews::features::kPreviewsDisallowedOnReloads}, {});
@@ -1013,8 +1003,6 @@
 
 IN_PROC_BROWSER_TEST_P(PreviewsLitePageServerBrowserTest,
                        DISABLE_ON_WIN_MAC(LitePagePreviewsRedirect)) {
-  if (GetParam())
-    return;
   {
     // Verify the preview is triggered when an HTTP page redirects to HTTPS.
     base::HistogramTester histogram_tester;
@@ -1022,8 +1010,10 @@
     VerifyPreviewLoaded();
     VerifyInfoStatus(&histogram_tester,
                      previews::ServerLitePageStatus::kSuccess);
-    histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
-                                       true, 1);
+    if (!GetParam()) {
+      histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
+                                         true, 1);
+    }
   }
 
   {
@@ -1033,8 +1023,10 @@
     VerifyPreviewLoaded();
     VerifyInfoStatus(&histogram_tester,
                      previews::ServerLitePageStatus::kSuccess);
-    histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
-                                       true, 1);
+    if (!GetParam()) {
+      histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
+                                         true, 1);
+    }
   }
 
   {
@@ -1047,11 +1039,13 @@
     VerifyInfoStatus(&histogram_tester,
                      previews::ServerLitePageStatus::kRedirect);
     ClearDeciderState();
-    histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
-                                       true, 1);
-    histogram_tester.ExpectBucketCount(
-        "Previews.ServerLitePage.ServerResponse",
-        PreviewsLitePageNavigationThrottle::ServerResponse::kRedirect, 1);
+    if (!GetParam()) {
+      histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
+                                         true, 1);
+      histogram_tester.ExpectBucketCount(
+          "Previews.ServerLitePage.ServerResponse",
+          PreviewsLitePageNavigationThrottle::ServerResponse::kRedirect, 1);
+    }
   }
 
   {
@@ -1063,14 +1057,17 @@
     VerifyInfoStatus(&histogram_tester,
                      previews::ServerLitePageStatus::kSuccess);
     ClearDeciderState();
-    histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
-                                       true, 2);
-    histogram_tester.ExpectBucketCount(
-        "Previews.ServerLitePage.ServerResponse",
-        PreviewsLitePageNavigationThrottle::ServerResponse::kRedirect, 1);
-    histogram_tester.ExpectBucketCount(
-        "Previews.ServerLitePage.ServerResponse",
-        PreviewsLitePageNavigationThrottle::ServerResponse::kOk, 1);
+
+    if (!GetParam()) {
+      histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered",
+                                         true, 2);
+      histogram_tester.ExpectBucketCount(
+          "Previews.ServerLitePage.ServerResponse",
+          PreviewsLitePageNavigationThrottle::ServerResponse::kRedirect, 1);
+      histogram_tester.ExpectBucketCount(
+          "Previews.ServerLitePage.ServerResponse",
+          PreviewsLitePageNavigationThrottle::ServerResponse::kOk, 1);
+    }
   }
 }
 
@@ -1310,8 +1307,6 @@
 
 IN_PROC_BROWSER_TEST_P(PreviewsLitePageServerBrowserTest,
                        DISABLE_ON_WIN_MAC(LitePagePreviewsNavigation)) {
-  if (GetParam())
-    return;
   ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
   VerifyPreviewLoaded();
 
@@ -1609,8 +1604,6 @@
 IN_PROC_BROWSER_TEST_P(
     PreviewsLitePageNotificationDSDisabledBrowserTest,
     DISABLE_ON_WIN_MAC(LitePagePreviewsInfoBarNonDataSaverUser)) {
-  if (GetParam())
-    return;
   ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
   VerifyPreviewNotLoaded();
   ClearDeciderState();
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
index 895aa00..7e37125 100644
--- a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
+++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
@@ -417,6 +417,10 @@
     experiment_query =
         "&x=" + net::EscapeQueryParamValue(experiment_id, true /* use_plus */);
   }
+  std::string fragment;
+  if (original_url.has_ref()) {
+    fragment = "#" + original_url.ref();
+  }
 
   std::string origin_hash = base::ToLowerASCII(base32::Base32Encode(
       crypto::SHA256HashString(
@@ -429,7 +433,7 @@
       previews_host.host() +
       (previews_host.has_port() ? (":" + previews_host.port()) : "") + "/p?u=" +
       net::EscapeQueryParamValue(original_url.spec(), true /* use_plus */) +
-      experiment_query);
+      experiment_query + fragment);
   DCHECK(previews_url.is_valid());
   DCHECK_EQ(previews_host.scheme(), previews_url.scheme());
   return previews_url;
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle_unittest.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle_unittest.cc
index 1199586da..24276ec 100644
--- a/chrome/browser/previews/previews_lite_page_navigation_throttle_unittest.cc
+++ b/chrome/browser/previews/previews_lite_page_navigation_throttle_unittest.cc
@@ -75,7 +75,7 @@
           "https://shta44dh4bi7rc6fnpjnkrtytwlabygjhk53v2trlot2wddylwua."
           "previews.host.com/p?u="
           "https%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes"
-          "%23fragment",
+          "%23fragment#fragment",
           "",
       },
       {
@@ -88,7 +88,8 @@
           "enable_HTCPCP",
       },
       {
-          "https://previews.host.com", "https://[::1]:12345",
+          "https://previews.host.com",
+          "https://[::1]:12345",
           "https://2ikmbopbfxagkb7uer2vgfxmbzu2vw4qq3d3ixe3h2hfhgcabvua."
           "previews.host.com/p?u=https%3A%2F%2F%5B%3A%3A1%5D%3A12345%2F",
           "",
diff --git a/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc b/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc
index c8eabbe..c049eb0 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc
+++ b/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/previews/previews_lite_page_redirect_url_loader.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -46,6 +47,30 @@
   GURL lite_page_url = PreviewsLitePageNavigationThrottle::GetPreviewsURLForURL(
       modified_resource_request_.url);
 
+  CreateRedirectInformation(lite_page_url);
+
+  modified_resource_request_.headers.MergeFrom(chrome_proxy_headers);
+
+  serving_url_loader_ = std::make_unique<PreviewsLitePageServingURLLoader>(
+      base::BindOnce(&PreviewsLitePageRedirectURLLoader::OnResultDetermined,
+                     weak_ptr_factory_.GetWeakPtr()));
+  // |serving_url_loader_| can be null after this call.
+  serving_url_loader_->StartNetworkRequest(
+      modified_resource_request_, network_loader_factory, frame_tree_node_id);
+}
+
+void PreviewsLitePageRedirectURLLoader::StartRedirectToOriginalURL(
+    const GURL& original_url) {
+  CreateRedirectInformation(original_url);
+
+  std::move(callback_).Run(
+      nullptr, base::BindOnce(&PreviewsLitePageRedirectURLLoader::
+                                  StartHandlingRedirectToModifiedRequest,
+                              weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PreviewsLitePageRedirectURLLoader::CreateRedirectInformation(
+    const GURL& redirect_url) {
   bool insecure_scheme_was_upgraded = false;
   bool copy_fragment = true;
 
@@ -56,8 +81,7 @@
       net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT,
       modified_resource_request_.referrer_policy,
       modified_resource_request_.referrer.spec(), net::HTTP_TEMPORARY_REDIRECT,
-      lite_page_url, base::nullopt, insecure_scheme_was_upgraded,
-      copy_fragment);
+      redirect_url, base::nullopt, insecure_scheme_was_upgraded, copy_fragment);
 
   bool should_clear_upload = false;
   net::RedirectUtil::UpdateHttpRequest(
@@ -65,8 +89,6 @@
       redirect_info_, base::nullopt, base::nullopt,
       &modified_resource_request_.headers, &should_clear_upload);
 
-  modified_resource_request_.headers.MergeFrom(chrome_proxy_headers);
-
   DCHECK(!should_clear_upload);
 
   modified_resource_request_.url = redirect_info_.new_url;
@@ -78,17 +100,14 @@
   modified_resource_request_.referrer = GURL(redirect_info_.new_referrer);
   modified_resource_request_.referrer_policy =
       redirect_info_.new_referrer_policy;
-
-  serving_url_loader_ = std::make_unique<PreviewsLitePageServingURLLoader>(
-      base::BindOnce(&PreviewsLitePageRedirectURLLoader::OnResultDetermined,
-                     weak_ptr_factory_.GetWeakPtr()));
-  // |serving_url_loader_| can be null after this call.
-  serving_url_loader_->StartNetworkRequest(
-      modified_resource_request_, network_loader_factory, frame_tree_node_id);
 }
 
 void PreviewsLitePageRedirectURLLoader::OnResultDetermined(
-    ServingLoaderResult result) {
+    ServingLoaderResult result,
+    base::Optional<net::RedirectInfo> redirect_info,
+    scoped_refptr<network::ResourceResponse> response) {
+  DCHECK(!redirect_info || result == ServingLoaderResult::kRedirect);
+  DCHECK(!response || result == ServingLoaderResult::kRedirect);
   switch (result) {
     case ServingLoaderResult::kSuccess:
       OnLitePageSuccess();
@@ -96,6 +115,9 @@
     case ServingLoaderResult::kFallback:
       OnLitePageFallback();
       return;
+    case ServingLoaderResult::kRedirect:
+      OnLitePageRedirect(redirect_info.value(), response->head);
+      return;
   }
   NOTREACHED();
 }
@@ -103,9 +125,22 @@
 void PreviewsLitePageRedirectURLLoader::OnLitePageSuccess() {
   std::move(callback_).Run(
       std::move(serving_url_loader_),
-      base::BindOnce(
-          &PreviewsLitePageRedirectURLLoader::StartHandlingRedirectToLitePage,
-          weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(&PreviewsLitePageRedirectURLLoader::
+                         StartHandlingRedirectToModifiedRequest,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PreviewsLitePageRedirectURLLoader::OnLitePageRedirect(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& response_head) {
+  redirect_info_ = redirect_info;
+
+  response_head_ = response_head;
+
+  std::move(callback_).Run(
+      nullptr,
+      base::BindOnce(&PreviewsLitePageRedirectURLLoader::StartHandlingRedirect,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void PreviewsLitePageRedirectURLLoader::OnLitePageFallback() {
@@ -113,13 +148,12 @@
   std::move(callback_).Run(nullptr, {});
 }
 
-void PreviewsLitePageRedirectURLLoader::StartHandlingRedirectToLitePage(
+void PreviewsLitePageRedirectURLLoader::StartHandlingRedirectToModifiedRequest(
     const network::ResourceRequest& resource_request,
     network::mojom::URLLoaderRequest request,
     network::mojom::URLLoaderClientPtr client) {
-  network::ResourceResponseHead response_head;
-  response_head.request_start = base::TimeTicks::Now();
-  response_head.response_start = response_head.request_start;
+  response_head_.request_start = base::TimeTicks::Now();
+  response_head_.response_start = response_head_.request_start;
 
   std::string header_string = base::StringPrintf(
       "HTTP/1.1 %i Temporary Redirect\n"
@@ -131,16 +165,14 @@
       new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
           header_string.c_str(), header_string.length()));
 
-  response_head.headers = fake_headers_for_redirect;
-  response_head.encoded_data_length = 0;
+  response_head_.headers = fake_headers_for_redirect;
+  response_head_.encoded_data_length = 0;
 
-  StartHandlingRedirect(redirect_info_, response_head, resource_request,
-                        std::move(request), std::move(client));
+  StartHandlingRedirect(resource_request, std::move(request),
+                        std::move(client));
 }
 
 void PreviewsLitePageRedirectURLLoader::StartHandlingRedirect(
-    const net::RedirectInfo& redirect_info,
-    const network::ResourceResponseHead& head,
     const network::ResourceRequest& /* resource_request */,
     network::mojom::URLLoaderRequest request,
     network::mojom::URLLoaderClientPtr client) {
@@ -157,7 +189,7 @@
     return;
   }
 
-  client_->OnReceiveRedirect(redirect_info, head);
+  client_->OnReceiveRedirect(redirect_info_, response_head_);
 }
 
 void PreviewsLitePageRedirectURLLoader::FollowRedirect(
diff --git a/chrome/browser/previews/previews_lite_page_redirect_url_loader.h b/chrome/browser/previews/previews_lite_page_redirect_url_loader.h
index dbde43a3..4d16ba4 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_url_loader.h
+++ b/chrome/browser/previews/previews_lite_page_redirect_url_loader.h
@@ -6,13 +6,16 @@
 #define CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_REDIRECT_URL_LOADER_H_
 
 #include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/previews/previews_lite_page_serving_url_loader.h"
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 
@@ -42,6 +45,9 @@
           network_loader_factory,
       int frame_tree_node_id);
 
+  // Creates a redirect to |original_url|.
+  void StartRedirectToOriginalURL(const GURL& original_url);
+
  private:
   // network::mojom::URLLoader:
   void FollowRedirect(const std::vector<std::string>& removed_headers,
@@ -54,39 +60,54 @@
   void ResumeReadingBodyFromNet() override;
 
   // Processes |result|. Used as a callback for |serving_url_loader_|.
-  void OnResultDetermined(ServingLoaderResult result);
+  // |redirect_info| and |response| should be present if and only if |result| is
+  // kRedirect.
+  void OnResultDetermined(ServingLoaderResult result,
+                          base::Optional<net::RedirectInfo> redirect_info,
+                          scoped_refptr<network::ResourceResponse> response);
 
   // Called when the lite page can be successfully served.
   void OnLitePageSuccess();
 
-  // Called when a non-200 response is received.
+  // Called when a non-200, non-307 response is received from the previews
+  // server.
   void OnLitePageFallback();
 
+  // Called when a redirect (307) is received from the previews server.
+  void OnLitePageRedirect(const net::RedirectInfo& redirect_info,
+                          const network::ResourceResponseHead& response_head);
+
   // The handler when trying to serve the lite page to the user. Serves a
   // redirect to the lite page server URL.
-  void StartHandlingRedirectToLitePage(
+  void StartHandlingRedirectToModifiedRequest(
       const network::ResourceRequest& resource_request,
       network::mojom::URLLoaderRequest request,
       network::mojom::URLLoaderClientPtr client);
 
   // Helper method for setting up and serving |redirect_info| to |client|.
   void StartHandlingRedirect(
-      const net::RedirectInfo& redirect_info,
-      const network::ResourceResponseHead& head,
       const network::ResourceRequest& /* resource_request */,
       network::mojom::URLLoaderRequest request,
       network::mojom::URLLoaderClientPtr client);
 
+  // Helper method to create redirect information to |redirect_url| and modify
+  // |redirect_info_| and |modified_resource_request_|.
+  void CreateRedirectInformation(const GURL& redirect_url);
+
   // Mojo error handling. Deletes |this|.
   void OnConnectionClosed();
 
   // The underlying URLLoader that speculatively tries to fetch the lite page.
   std::unique_ptr<PreviewsLitePageServingURLLoader> serving_url_loader_;
 
-  // A copy of the initial resource request that has been modified to fetch the
-  // lite page.
+  // A copy of the initial resource request that has been modified to fetch
+  // the lite page.
   network::ResourceRequest modified_resource_request_;
 
+  // Stores the response when a 307 (redirect) is received from the previews
+  // server.
+  network::ResourceResponseHead response_head_;
+
   // Information about the redirect to the lite page server.
   net::RedirectInfo redirect_info_;
 
diff --git a/chrome/browser/previews/previews_lite_page_serving_url_loader.cc b/chrome/browser/previews/previews_lite_page_serving_url_loader.cc
index 1a28445..9b48e5fdf 100644
--- a/chrome/browser/previews/previews_lite_page_serving_url_loader.cc
+++ b/chrome/browser/previews/previews_lite_page_serving_url_loader.cc
@@ -87,7 +87,8 @@
 
 void PreviewsLitePageServingURLLoader::Fallback() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::move(result_callback_).Run(ServingLoaderResult::kFallback);
+  std::move(result_callback_)
+      .Run(ServingLoaderResult::kFallback, base::nullopt, nullptr);
 }
 
 RequestHandler PreviewsLitePageServingURLLoader::ServingResponseHandler() {
@@ -148,17 +149,22 @@
   resource_response_->head = head;
 
   url_loader_binding_.PauseIncomingMethodCallProcessing();
-  std::move(result_callback_).Run(ServingLoaderResult::kSuccess);
+  std::move(result_callback_)
+      .Run(ServingLoaderResult::kSuccess, base::nullopt, nullptr);
 }
 
 void PreviewsLitePageServingURLLoader::OnReceiveRedirect(
     const net::RedirectInfo& redirect_info,
     const network::ResourceResponseHead& head) {
   DCHECK(!forwarding_client_);
-  // We might receive a redirect from the lite page server, and we should treat
-  // that appropriately. For now fallback.
-  // TODO(ryansturm): Handle redirects. https://crbug.com/921744
-  Fallback();
+
+  // Store head and pause new messages until the forwarding client is set up.
+  // Make a deep copy of ResourceResponseHead before passing it cross-thread.
+  resource_response_ = base::MakeRefCounted<network::ResourceResponse>();
+  resource_response_->head = head;
+
+  std::move(result_callback_)
+      .Run(ServingLoaderResult::kRedirect, redirect_info, resource_response_);
 }
 
 void PreviewsLitePageServingURLLoader::OnUploadProgress(
diff --git a/chrome/browser/previews/previews_lite_page_serving_url_loader.h b/chrome/browser/previews/previews_lite_page_serving_url_loader.h
index d0d57c5..ccdcacd 100644
--- a/chrome/browser/previews/previews_lite_page_serving_url_loader.h
+++ b/chrome/browser/previews/previews_lite_page_serving_url_loader.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -20,12 +21,17 @@
 namespace previews {
 
 enum class ServingLoaderResult {
-  kSuccess,  // The Preview can be served.
-  kFallback  // The Preview cannot be served and fallback to default URLLoader
-             // should occur.
+  kSuccess,   // The Preview can be served.
+  kFallback,  // The Preview cannot be served and fallback to default URLLoader
+              // should occur.
+  kRedirect,  // The URL returns a redirect, and we should pass that on to the
+              // navigation code.
 };
 
-using ResultCallback = base::OnceCallback<void(ServingLoaderResult)>;
+using ResultCallback =
+    base::OnceCallback<void(ServingLoaderResult,
+                            base::Optional<net::RedirectInfo> redirect_info,
+                            scoped_refptr<network::ResourceResponse> response)>;
 
 using RequestHandler =
     base::OnceCallback<void(const network::ResourceRequest& resource_request,
diff --git a/chrome/browser/previews/previews_lite_page_url_loader_interceptor.cc b/chrome/browser/previews/previews_lite_page_url_loader_interceptor.cc
index 50cfed0..47b25cf8 100644
--- a/chrome/browser/previews/previews_lite_page_url_loader_interceptor.cc
+++ b/chrome/browser/previews/previews_lite_page_url_loader_interceptor.cc
@@ -4,16 +4,19 @@
 
 #include "chrome/browser/previews/previews_lite_page_url_loader_interceptor.h"
 
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/previews/core/previews_features.h"
+#include "components/previews/core/previews_lite_page_redirect.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/resource_type.h"
@@ -91,8 +94,21 @@
     return;
   }
 
-  // TODO(ryansturm): Handle reloads by handling non-intercepted attempts at
-  // fetching the lite page server. https://crbug.com/921756
+  // Do not attempt to serve the same URL multiple times.
+  if (base::ContainsKey(urls_processed_, tentative_resource_request.url)) {
+    std::move(callback).Run({});
+    return;
+  }
+
+  urls_processed_.insert(tentative_resource_request.url);
+
+  std::string original_url;
+  if (previews::ExtractOriginalURLFromLitePageRedirectURL(
+          tentative_resource_request.url, &original_url)) {
+    CreateOriginalURLLoader(tentative_resource_request, GURL(original_url),
+                            std::move(callback));
+    return;
+  }
 
   if (ShouldCreateLoader(tentative_resource_request)) {
     CreateRedirectLoader(tentative_resource_request, resource_context,
@@ -123,20 +139,35 @@
       frame_tree_node_id_);
 }
 
+void PreviewsLitePageURLLoaderInterceptor::CreateOriginalURLLoader(
+    const network::ResourceRequest& tentative_resource_request,
+    const GURL& original_url,
+    content::URLLoaderRequestInterceptor::LoaderCallback callback) {
+  redirect_url_loader_ = std::make_unique<PreviewsLitePageRedirectURLLoader>(
+      tentative_resource_request,
+      base::BindOnce(
+          &PreviewsLitePageURLLoaderInterceptor::HandleRedirectLoader,
+          base::Unretained(this), std::move(callback)));
+
+  // |redirect_url_loader_| can be null after this call.
+  redirect_url_loader_->StartRedirectToOriginalURL(original_url);
+}
+
 void PreviewsLitePageURLLoaderInterceptor::HandleRedirectLoader(
     content::URLLoaderRequestInterceptor::LoaderCallback callback,
     std::unique_ptr<PreviewsLitePageServingURLLoader> serving_url_loader,
     RequestHandler handler) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Handle any failure by using default loader.
-  if (!serving_url_loader) {
-    DCHECK(handler.is_null());
+  if (handler.is_null()) {
+    DCHECK(!serving_url_loader_);
     redirect_url_loader_.reset();
     std::move(callback).Run({});
     return;
   }
 
-  // Save the serving loader to handle the next request.
+  // Save the serving loader to handle the next request. It can be null when
+  // serving the original URL on a reload.
   serving_url_loader_ = std::move(serving_url_loader);
 
   // |redirect_url_loader_| now manages its own lifetime via a mojo channel.
diff --git a/chrome/browser/previews/previews_lite_page_url_loader_interceptor.h b/chrome/browser/previews/previews_lite_page_url_loader_interceptor.h
index 2b1b9c7..e44ad39 100644
--- a/chrome/browser/previews/previews_lite_page_url_loader_interceptor.h
+++ b/chrome/browser/previews/previews_lite_page_url_loader_interceptor.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_URL_LOADER_INTERCEPTOR_H_
 
 #include <memory>
+#include <set>
 
 #include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
@@ -14,6 +15,7 @@
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "net/http/http_request_headers.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "url/gurl.h"
 
 namespace previews {
 
@@ -42,12 +44,23 @@
       content::ResourceContext* resource_context,
       content::URLLoaderRequestInterceptor::LoaderCallback callback);
 
+  // Creates a redirect URL loader that immediately serves a redirect to
+  // |original_url|.
+  void CreateOriginalURLLoader(
+      const network::ResourceRequest& tentative_resource_request,
+      const GURL& original_url,
+      content::URLLoaderRequestInterceptor::LoaderCallback callback);
+
   // Runs |callback| with |handler| and stores |serving_url_loader|.
   void HandleRedirectLoader(
       content::URLLoaderRequestInterceptor::LoaderCallback callback,
       std::unique_ptr<PreviewsLitePageServingURLLoader> serving_url_loader,
       RequestHandler handler);
 
+  // All URLs already seen in this navigation. This prevents redirect loops,
+  // etc.
+  std::set<GURL> urls_processed_;
+
   // While attempting to fetch a lite page, this object manages communication
   // with the lite page server and serving redirects. Once, a decision has been
   // made regarding serving the preview, this object will be null.
diff --git a/chrome/browser/previews/previews_lite_page_url_loader_interceptor_unittest.cc b/chrome/browser/previews/previews_lite_page_url_loader_interceptor_unittest.cc
index 95cbf2a..b7930495a 100644
--- a/chrome/browser/previews/previews_lite_page_url_loader_interceptor_unittest.cc
+++ b/chrome/browser/previews/previews_lite_page_url_loader_interceptor_unittest.cc
@@ -58,7 +58,11 @@
 
   base::Optional<bool> callback_was_empty() { return callback_was_empty_; }
 
-  void ResetTest() { callback_was_empty_ = base::nullopt; }
+  void ResetTest() {
+    interceptor_ = std::make_unique<PreviewsLitePageURLLoaderInterceptor>(
+        shared_factory_, 1);
+    callback_was_empty_ = base::nullopt;
+  }
 
   PreviewsLitePageURLLoaderInterceptor& interceptor() { return *interceptor_; }
 
diff --git a/chrome/browser/previews/previews_ui_tab_helper.cc b/chrome/browser/previews/previews_ui_tab_helper.cc
index 49bbee5..a851b57 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
+#include "chrome/browser/previews/previews_content_util.h"
 #include "chrome/browser/previews/previews_infobar_delegate.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
@@ -25,7 +26,6 @@
 #include "components/network_time/network_time_tracker.h"
 #include "components/offline_pages/buildflags/buildflags.h"
 #include "components/offline_pages/core/offline_page_item.h"
-#include "components/previews/content/previews_content_util.h"
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/core/previews_experiments.h"
 #include "components/previews/core/previews_features.h"
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
index 14a3259..a4ef961 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
@@ -8,11 +8,11 @@
 #include "base/bind_helpers.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
+#include "chrome/browser/previews/previews_content_util.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/previews/content/previews_content_util.h"
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/previews_experiments.h"
diff --git a/chrome/browser/printing/cloud_print/privet_http_unittest.cc b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
index e32cd78..49e47f0 100644
--- a/chrome/browser/printing/cloud_print/privet_http_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
@@ -770,7 +770,7 @@
   local_print_operation_->SetJobname("Sample job name");
   local_print_operation_->SetData(RefCountedBytesFromString("foobar"));
   std::unique_ptr<base::Value> ticket =
-      base::JSONReader::Read(kSampleCJTDuplex);
+      base::JSONReader::ReadDeprecated(kSampleCJTDuplex);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
@@ -807,7 +807,8 @@
   local_print_operation_->SetUsername("sample@gmail.com");
   local_print_operation_->SetJobname("Sample job name");
   local_print_operation_->SetData(RefCountedBytesFromString("foobar"));
-  std::unique_ptr<base::Value> ticket = base::JSONReader::Read(kSampleCJTMono);
+  std::unique_ptr<base::Value> ticket =
+      base::JSONReader::ReadDeprecated(kSampleCJTMono);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
@@ -842,7 +843,8 @@
   local_print_operation_->SetUsername("sample@gmail.com");
   local_print_operation_->SetJobname("Sample job name");
   local_print_operation_->SetData(RefCountedBytesFromString("foobar"));
-  std::unique_ptr<base::Value> ticket = base::JSONReader::Read(kSampleCJTMono);
+  std::unique_ptr<base::Value> ticket =
+      base::JSONReader::ReadDeprecated(kSampleCJTMono);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
@@ -876,7 +878,8 @@
 TEST_P(PrivetLocalPrintTest, SuccessfulLocalPrintWithCreatejob) {
   local_print_operation_->SetUsername("sample@gmail.com");
   local_print_operation_->SetJobname("Sample job name");
-  std::unique_ptr<base::Value> ticket = base::JSONReader::Read(kSampleCJT);
+  std::unique_ptr<base::Value> ticket =
+      base::JSONReader::ReadDeprecated(kSampleCJT);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
@@ -910,7 +913,8 @@
   local_print_operation_->SetUsername("sample@gmail.com");
   local_print_operation_->SetJobname(
       "123456789:123456789:123456789:123456789:123456789:123456789:123456789:");
-  std::unique_ptr<base::Value> ticket = base::JSONReader::Read(kSampleCJT);
+  std::unique_ptr<base::Value> ticket =
+      base::JSONReader::ReadDeprecated(kSampleCJT);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
@@ -936,7 +940,8 @@
 TEST_P(PrivetLocalPrintTest, PDFPrintInvalidDocumentTypeRetry) {
   local_print_operation_->SetUsername("sample@gmail.com");
   local_print_operation_->SetJobname("Sample job name");
-  std::unique_ptr<base::Value> ticket = base::JSONReader::Read(kSampleCJT);
+  std::unique_ptr<base::Value> ticket =
+      base::JSONReader::ReadDeprecated(kSampleCJT);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
@@ -966,7 +971,8 @@
 TEST_P(PrivetLocalPrintTest, LocalPrintRetryOnInvalidJobID) {
   local_print_operation_->SetUsername("sample@gmail.com");
   local_print_operation_->SetJobname("Sample job name");
-  std::unique_ptr<base::Value> ticket = base::JSONReader::Read(kSampleCJT);
+  std::unique_ptr<base::Value> ticket =
+      base::JSONReader::ReadDeprecated(kSampleCJT);
   ASSERT_TRUE(ticket);
   local_print_operation_->SetTicket(
       base::Value::FromUniquePtrValue(std::move(ticket)));
diff --git a/chrome/browser/printing/cloud_print/privet_url_loader.cc b/chrome/browser/printing/cloud_print/privet_url_loader.cc
index 70ed0e2..ad286bd2 100644
--- a/chrome/browser/printing/cloud_print/privet_url_loader.cc
+++ b/chrome/browser/printing/cloud_print/privet_url_loader.cc
@@ -251,7 +251,8 @@
   }
 
   base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
-  std::unique_ptr<base::Value> value = json_reader.ReadToValue(*response_body);
+  std::unique_ptr<base::Value> value =
+      json_reader.ReadToValueDeprecated(*response_body);
   if (!value || !value->is_dict()) {
     delegate_->OnError(0, JSON_PARSE_ERROR);
     return;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index dcbbb455..c9dc5c38a 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -93,6 +93,7 @@
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/webui/prefs_internals_source.h"
 #include "chrome/common/buildflags.h"
+#include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
@@ -133,6 +134,7 @@
 #include "content/public/browser/url_data_source.h"
 #include "content/public/common/content_constants.h"
 #include "extensions/buildflags/buildflags.h"
+#include "google_apis/google_api_keys.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
@@ -250,6 +252,13 @@
 const char kPrefExitTypeCrashed[] = "Crashed";
 const char kPrefExitTypeSessionEnded[] = "SessionEnded";
 
+// Returns the Chrome Google API key for the channel of this build.
+std::string APIKeyForChannel() {
+  if (chrome::GetChannel() == version_info::Channel::STABLE)
+    return google_apis::GetAPIKey();
+  return google_apis::GetNonStableAPIKey();
+}
+
 void CreateProfileReadme(const base::FilePath& profile_path) {
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   base::FilePath readme_path = profile_path.Append(chrome::kReadmeFilename);
@@ -1223,7 +1232,7 @@
 
   if (service_name == image_annotation::mojom::kServiceName) {
     return std::make_unique<image_annotation::ImageAnnotationService>(
-        std::move(request), GetURLLoaderFactory());
+        std::move(request), APIKeyForChannel(), GetURLLoaderFactory());
   }
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css
index cad5550a..474ef8b 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css
@@ -3,7 +3,7 @@
  * found in the LICENSE file. */
 
 .content {
-  padding-right: 8px;
+  padding-inline-end: 8px;
 }
 
 #title-recording,
@@ -13,7 +13,6 @@
 
 #footer-text {
   color: #757575;
-  padding-top: 48px;
 }
 
 #voice-match-video {
@@ -25,11 +24,10 @@
 #recording-container,
 #already-setup-container {
   display: none;
+  height: 460px;
 }
 
 .intro #intro-container,
-.recording #recording-container,
-.completed #recording-container,
 .already-setup #already-setup-container {
   display: block;
 }
@@ -39,6 +37,25 @@
   display: none;
 }
 
+.recording #recording-container,
+.completed #recording-container {
+  display: table;
+}
+
+#loading-animation {
+  margin: 80px auto;
+  width: 100px;
+}
+
+#loading-spinner {
+  height: 100px;
+  width: 100px;
+}
+
+#footer-text {
+  display: table-footer-group;
+}
+
 .intro #skip-button,
 .intro #agree-button,
 .recording #later-button {
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
index 60d9200..132adc7 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
@@ -29,26 +29,28 @@
                 i18n-content="assistantVoiceMatchRecording"></div>
             <div class="title" id="title-completed"
                 i18n-content="assistantVoiceMatchCompleted"></div>
-            <voice-match-entry id="voice-entry-0">
-              <div class="entry-content"
-                  i18n-content="assistantVoiceMatchInstruction0"></div>
-            </voice-match-entry>
-            <voice-match-entry id="voice-entry-1">
-              <div class="entry-content"
-                  i18n-content="assistantVoiceMatchInstruction1"></div>
-            </voice-match-entry>
-            <voice-match-entry id="voice-entry-2">
-              <div class="entry-content"
-                  i18n-content="assistantVoiceMatchInstruction2"></div>
-            </voice-match-entry>
-            <voice-match-entry id="voice-entry-3">
-              <div class="entry-content"
-                  i18n-content="assistantVoiceMatchInstruction3"></div>
-            </voice-match-entry>
-            <voice-match-entry id="voice-uploading">
-              <div class="entry-content"
-                  i18n-content="assistantVoiceMatchUploading"></div>
-            </voice-match-entry>
+            <div id="voice-match-entries">
+              <voice-match-entry id="voice-entry-0">
+                <div class="entry-content"
+                    i18n-content="assistantVoiceMatchInstruction0"></div>
+              </voice-match-entry>
+              <voice-match-entry id="voice-entry-1">
+                <div class="entry-content"
+                    i18n-content="assistantVoiceMatchInstruction1"></div>
+              </voice-match-entry>
+              <voice-match-entry id="voice-entry-2">
+                <div class="entry-content"
+                    i18n-content="assistantVoiceMatchInstruction2"></div>
+              </voice-match-entry>
+              <voice-match-entry id="voice-entry-3">
+                <div class="entry-content"
+                    i18n-content="assistantVoiceMatchInstruction3"></div>
+              </voice-match-entry>
+            </div>
+            <div id="loading-animation" hidden>
+              <paper-spinner-lite id="loading-spinner" active>
+              </paper-spinner-lite>
+            </div>
             <div class="content" id="footer-text"
                 i18n-content="assistantVoiceMatchFooter"></div>
           </div>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
index 72210ca8..b3f3e75 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
@@ -80,14 +80,13 @@
     currentEntry.setAttribute('completed', true);
     this.currentIndex_++;
     if (this.currentIndex_ == 4) {
-      this.$['voice-uploading'].setAttribute('active', true);
+      this.$['voice-match-entries'].hidden = true;
+      this.$['later-button'].hidden = true;
+      this.$['loading-animation'].hidden = false;
     }
   },
 
   voiceMatchDone: function() {
-    this.$['voice-uploading'].removeAttribute('active');
-    this.$['voice-uploading'].setAttribute('completed', true);
-
     this.removeClass_('recording');
     this.addClass_('completed');
 
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.css b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.css
index 764dc12..229a237 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.css
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.css
@@ -36,8 +36,7 @@
 }
 
 .container {
-    margin-left: auto;
-    margin-right: auto;
+    margin: auto;
     width: 646px;
 }
 
@@ -66,6 +65,24 @@
     width: 40px;
 }
 
+.option .developerLog {
+  height: 60px;
+  padding-inline-end: 0;
+  width: 666px;
+}
+
+.option .sub-description {
+  color: rgb(95, 99, 104);
+  display: block;
+}
+
+.option .developer-option-icon-button {
+  background-color: #fff;
+  float: right;
+  height: 60px;
+  vertical-align: middle;
+}
+
 .option input[type='checkbox']:checked {
     background-image: url(checked.png);
 }
@@ -96,7 +113,7 @@
     border-width: 0;
     font-weight: bold;
     height: 30px;
-    margin-left: 20px;
+    margin-inline-start: 20px;
     padding: 0 20px;
 }
 
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html
index b25b41e7..2d58043b 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html
@@ -12,6 +12,9 @@
 <script type="text/javascript" src="options_loader.js"></script>
 <script type="text/javascript" src="../../chromeVoxChromeOptionsScript.js">
 </script>
+  <link rel="import" href="chrome://resources/cr_elements/icons.html">
+  <link rel="import" href="chrome://resources/html/polymer.html">
+  <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 </head>
 
 <body>
@@ -141,7 +144,6 @@
     <input type="number" min="1" id="virtual_braille_display_columns_input">
   </label>
   </div>
-
   <div class="option">
     <span id="currentDisplayStyle"></span>
     <button id="changeDisplayStyle"></button>
@@ -150,6 +152,19 @@
   <h2 class="i18n" msgid="options_developer_options" id="developerDescription">
     Developer Options
   </h2>
+  <div class="chromeos option" id="developerLog">
+    <label>
+      <paper-icon-button icon="cr:expand-more"
+        class="developer-option-icon-button" id="chromeVoxDeveloperOptionsMore"
+        name="chromeVoxDeveloperOptions"></paper-icon-button>
+      <paper-icon-button icon="cr:expand-less"
+        class="developer-option-icon-button" id="chromeVoxDeveloperOptionsLess"
+        name="chromeVoxDeveloperOptions" hidden></paper-icon-button>
+      <span class="i18n" msgid="options_developer_options">
+        Enable developer options
+      </span>
+    </label>
+  </div>
   <div class="option" id="developerSpeechLogging">
     <label>
       <input id="enableSpeechLogging" type="checkbox"
@@ -179,14 +194,22 @@
   </div>
   <div class="option" id="developerEventStream">
     <label>
-      <input id="enableEventStreamLogging" type="checkbox"
-             class="checkbox pref logging" name="enableEventStreamLogging">
       <span class="i18n" msgid="options_event_stream_logging">
         Enable event stream logging
       </span>
     </label>
     <button id="toggleEventStreamFilters"></button>
   </div>
+   <div class="option" id="showDeveloperLog">
+    <label>
+      <paper-icon-button icon="cr:open-in-new"
+        class="developer-option-icon-button" id="openDeveloperLog">
+      </paper-icon-button>
+      <span class="i18n" msgid="options_show_log"></span>
+      <span class="i18n sub-description" msgid="options_show_log_key"></span>
+    </label>
+  </div>
+
   <div id="eventStreamFilters" hidden>
     <label><div class="option-eventstream">
       <input name="activedescendantchanged" type="checkbox"
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js
index b935095..836597e3 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js
@@ -120,19 +120,39 @@
     });
   };
 
-  chrome.commandLinePrivate.hasSwitch(
-      'enable-chromevox-developer-option', function(enable) {
-        if (!enable) {
-          $('developerDescription').hidden = true;
-          $('developerSpeechLogging').hidden = true;
-          $('developerEarconLogging').hidden = true;
-          $('developerBrailleLogging').hidden = true;
-          $('developerEventStream').hidden = true;
-          return;
-        }
-        registerEventStreamFiltersListener();
-      });
+  var toggleShowDeveloperOptions = function() {
+    $('developerSpeechLogging').hidden = !$('developerSpeechLogging').hidden;
+    $('developerEarconLogging').hidden = !$('developerEarconLogging').hidden;
+    $('developerBrailleLogging').hidden = !$('developerBrailleLogging').hidden;
+    $('developerEventStream').hidden = !$('developerEventStream').hidden;
+    $('showDeveloperLog').hidden = !$('showDeveloperLog').hidden;
+    $('chromeVoxDeveloperOptionsMore').hidden =
+        !($('chromeVoxDeveloperOptionsMore').hidden);
+    $('chromeVoxDeveloperOptionsLess').hidden =
+        !($('chromeVoxDeveloperOptionsLess').hidden);
+  };
 
+  $('chromeVoxDeveloperOptionsMore').addEventListener('click', function(evt) {
+    toggleShowDeveloperOptions();
+  });
+
+  $('chromeVoxDeveloperOptionsLess').addEventListener('click', function(evt) {
+    toggleShowDeveloperOptions();
+  });
+
+  $('openDeveloperLog').addEventListener('click', function(evt) {
+    let logPage = {url: 'cvox2/background/log.html'};
+    chrome.tabs.create(logPage);
+  });
+
+  // Hide developer options by default.
+  $('developerSpeechLogging').hidden = true;
+  $('developerEarconLogging').hidden = true;
+  $('developerBrailleLogging').hidden = true;
+  $('developerEventStream').hidden = true;
+  $('showDeveloperLog').hidden = true;
+
+  registerEventStreamFiltersListener();
   Msgs.addTranslatedMessagesToDom(document);
   cvox.OptionsPage.hidePlatformSpecifics();
 
diff --git a/chrome/browser/resources/chromeos/chromevox/common/command_store.js b/chrome/browser/resources/chromeos/chromevox/common/command_store.js
index 3129f2a..e0df7ed 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/command_store.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/command_store.js
@@ -416,6 +416,13 @@
     'disallowOOBE': true,
     category: 'help_commands'
   },
+  'showLogPage': {
+    announce: false,
+    disallowContinuation: true,
+    msgId: 'show_log_page',
+    'disallowOOBE': true,
+    category: 'help_commands'
+  },
   'showKbExplorerPage': {
     announce: false,
     disallowContinuation: true,
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
index 8b472e9..ff2fed6 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -118,47 +118,25 @@
       chrome.windows.create(explorerPage);
       break;
     case 'showLogPage':
-      chrome.commandLinePrivate.hasSwitch(
-          'enable-chromevox-developer-option', function(enable) {
-            if (enable) {
-              var logPage = {url: 'cvox2/background/log.html'};
-              chrome.tabs.create(logPage);
-            }
-          });
+      var logPage = {url: 'cvox2/background/log.html'};
+      chrome.tabs.create(logPage);
       break;
     case 'enableLogging':
-      chrome.commandLinePrivate.hasSwitch(
-          'enable-chromevox-developer-option', function(enable) {
-            if (enable) {
-              var prefs = new cvox.ChromeVoxPrefs();
-              for (var type in cvox.ChromeVoxPrefs.loggingPrefs) {
-                prefs.setLoggingPrefs(
-                    cvox.ChromeVoxPrefs.loggingPrefs[type], true);
-              }
-            }
-          });
+      var prefs = new cvox.ChromeVoxPrefs();
+      for (var type in cvox.ChromeVoxPrefs.loggingPrefs) {
+        prefs.setLoggingPrefs(cvox.ChromeVoxPrefs.loggingPrefs[type], true);
+      }
       break;
     case 'disableLogging':
-      chrome.commandLinePrivate.hasSwitch(
-          'enable-chromevox-developer-option', function(enable) {
-            if (enable) {
-              var prefs = new cvox.ChromeVoxPrefs();
-              for (var type in cvox.ChromeVoxPrefs.loggingPrefs) {
-                prefs.setLoggingPrefs(
-                    cvox.ChromeVoxPrefs.loggingPrefs[type], false);
-              }
-            }
-          });
+      var prefs = new cvox.ChromeVoxPrefs();
+      for (var type in cvox.ChromeVoxPrefs.loggingPrefs) {
+        prefs.setLoggingPrefs(cvox.ChromeVoxPrefs.loggingPrefs[type], false);
+      }
       break;
     case 'dumpTree':
-      chrome.commandLinePrivate.hasSwitch(
-          'enable-chromevox-developer-option', function(enable) {
-            if (enable) {
-              chrome.automation.getDesktop(function(root) {
-                LogStore.getInstance().writeTreeLog(new TreeDumper(root));
-              });
-            }
-          });
+      chrome.automation.getDesktop(function(root) {
+        LogStore.getInstance().writeTreeLog(new TreeDumper(root));
+      });
       break;
     case 'decreaseTtsRate':
       CommandHandler.increaseOrDecreaseSpeechProperty_(
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
index ce7708d..4997337 100644
--- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -31,11 +31,12 @@
     "tabs",
     "tts",
     "virtualKeyboardPrivate",
+    "chrome://resources/",
     "<all_urls>"
   ],
   "content_scripts": [
     {
-      "matches": [ "<all_urls>" ],
+      "matches": [ "<all_urls>", "chrome://resources/.*" ],
       "exclude_globs": [
 {% if is_webstore is not defined %}
           "chrome-extension://*",
@@ -103,5 +104,6 @@
     "16": "images/chromevox-16.png",
     "48": "images/chromevox-48.png",
     "128": "images/chromevox-128.png"
-  }
+  },
+   "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources; style-src 'unsafe-inline' chrome://resources;"
 }
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
index 059fc8c..0aee7614 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -204,6 +204,9 @@
       <message desc="The description of the showOptionsPage key. Displayed in the Options page." name="IDS_CHROMEVOX_SHOW_OPTIONS_PAGE">
         Open options page
       </message>
+      <message desc="The description of the showLogPage key. Displayed in the ChromeVox panel." name="IDS_CHROMEVOX_SHOW_LOG_PAGE">
+        Open developer log page
+      </message>
       <message desc="The description of the showKbExplorerPage key; this allows users to learn about their keyboard. Displayed in the Options page." name="IDS_CHROMEVOX_SHOW_KB_EXPLORER_PAGE">
         Open learn mode
       </message>
@@ -568,8 +571,8 @@
       <message desc="An option for setting the key combination that will be used as the ChromeVox modifier key (aka, the 'Cvox' key)." name="IDS_CHROMEVOX_OPTIONS_CVOX_MODIFIER_KEY">
         ChromeVox modifier key
       </message>
-      <message desc="List of chromevox developer options." name="IDS_CHROMEVOX_OPTIONS_DEVELOPER_OPTIONS">
-        Developer Options
+      <message desc="Labels the checkbox that enables developer options for ChromeVox." name="IDS_CHROMEVOX_OPTIONS_DEVELOPER_OPTIONS">
+        Enable Developer Options
       </message>
       <message desc="Enable chromevox earcon logging." name="IDS_CHROMEVOX_OPTIONS_DEVELOPER_EARCON_LOGGING">
         Enable earcon logging
@@ -580,6 +583,12 @@
       <message desc="Enable event stream logging in chromevox for developer options." name="IDS_CHROMEVOX_OPTIONS_EVENT_STREAM_LOGGING">
         Enable event stream logging
       </message>
+      <message desc="Show ChromeVox Event Log." name="IDS_CHROMEVOX_OPTIONS_SHOW_LOG">
+        Show Log
+      </message>
+      <message desc="Keyboard shortcut to show the ChromeVox log." name="IDS_CHROMEVOX_OPTIONS_SHOW_LOG_KEY">
+        Search + O + W
+      </message>
       <message desc="Show event stream filters options for event stream logging." name="IDS_CHROMEVOX_OPTIONS_SHOW_EVENT_STREAM_FILTERS">
         Show event stream filters
       </message>
diff --git a/chrome/browser/resources/pdf/metrics.js b/chrome/browser/resources/pdf/metrics.js
index d0cb77c..d965d30 100644
--- a/chrome/browser/resources/pdf/metrics.js
+++ b/chrome/browser/resources/pdf/metrics.js
@@ -2,211 +2,130 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(function() {
 
-'use strict';
+/**
+ * Handles events specific to the PDF viewer and logs the corresponding metrics.
+ */
+class PDFMetrics {
+  /**
+   * Records when the zoom mode is changed to fit a FittingType.
+   *
+   * @param {FittingType} fittingType the new FittingType.
+   */
+  static recordFitTo(fittingType) {
+    if (fittingType == FittingType.FIT_TO_PAGE) {
+      PDFMetrics.record(PDFMetrics.UserAction.FIT_TO_PAGE);
+    } else if (fittingType == FittingType.FIT_TO_WIDTH) {
+      PDFMetrics.record(PDFMetrics.UserAction.FIT_TO_WIDTH);
+    }
+    // There is no user action to do a fit-to-height, this only happens with
+    // the open param "view=FitV".
+  }
+
+  /**
+   * Records the given action to chrome.metricsPrivate.
+   *
+   * @param {PDFMetrics.UserAction} action
+   */
+  static record(action) {
+    if (!chrome.metricsPrivate) {
+      return;
+    }
+    if (!PDFMetrics.actionsMetric_) {
+      PDFMetrics.actionsMetric_ = {
+        'metricName': 'PDF.Actions',
+        'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG,
+        'min': 1,
+        'max': PDFMetrics.UserAction.NUMBER_OF_ACTIONS,
+        'buckets': PDFMetrics.UserAction.NUMBER_OF_ACTIONS + 1
+      };
+    }
+    chrome.metricsPrivate.recordValue(PDFMetrics.actionsMetric_, action);
+    if (PDFMetrics.firstMap_.has(action)) {
+      const firstAction = PDFMetrics.firstMap_.get(action);
+      if (!PDFMetrics.firstActionRecorded_.has(firstAction)) {
+        chrome.metricsPrivate.recordValue(
+            PDFMetrics.actionsMetric_, firstAction);
+        PDFMetrics.firstActionRecorded_.add(firstAction);
+      }
+    }
+  }
+
+  static resetForTesting() {
+    PDFMetrics.firstActionRecorded_.clear();
+    PDFMetrics.actionsMetric_ = null;
+  }
+}
+
+/** @private {Object} */
+PDFMetrics.actionsMetric_ = null;
+
+/** @private {Set} */
+PDFMetrics.firstActionRecorded_ = new Set();
 
 // Keep in sync with enums.xml.
 // Do not change the numeric values or reuse them since these numbers are
 // persisted to logs.
-const UserAction = {
+/**
+ * User Actions that can be recorded by calling PDFMetrics.record.
+ * The *_FIRST values are recorded automaticlly,
+ * eg. PDFMetrics.record(...ROTATE) will also record ROTATE_FIRST
+ * on the first instance.
+ *
+ * @enum {number}
+ */
+PDFMetrics.UserAction = {
+  /**
+   * Recorded when the document is first loaded. This event serves as
+   * denominator to determine percentages of documents in which an action was
+   * taken as well as average number of each action per document.
+   */
   DOCUMENT_OPENED: 0,  // Baseline to use as denominator for all formulas.
   ROTATE_FIRST: 1,
+  /** Recorded when the document is rotated clockwise or counter-clockwise. */
   ROTATE: 2,
   FIT_TO_WIDTH_FIRST: 3,
   FIT_TO_WIDTH: 4,
   FIT_TO_PAGE_FIRST: 5,
   FIT_TO_PAGE: 6,
   OPEN_BOOKMARKS_PANEL_FIRST: 7,
+  /** Recorded when the bookmarks panel is opened. */
   OPEN_BOOKMARKS_PANEL: 8,
   FOLLOW_BOOKMARK_FIRST: 9,
+  /** Recorded when a bookmark is followed. */
   FOLLOW_BOOKMARK: 10,
   PAGE_SELECTOR_NAVIGATE_FIRST: 11,
+  /** Recorded when the page selection is used to navigate to another page. */
   PAGE_SELECTOR_NAVIGATE: 12,
   NUMBER_OF_ACTIONS: 13
 };
 
-/**
- * Handles events specific to the PDF viewer and logs the corresponding metrics.
- *
- * @interface
- */
-window.PDFMetrics = class {
-  constructor() {}
-
-  /**
-   * Call when the document is first loaded. This event serves as denominator to
-   * determine percentages of documents in which an action was taken as well as
-   * average number of each action per document.
-   */
-  onDocumentOpened() {}
-
-  /**
-   * Call when the document is rotated clockwise or counter-clockwise.
-   */
-  onRotation() {}
-
-  /**
-   * Call when the zoom mode is changed to fit a FittingType.
-   *
-   * @param {FittingType} fittingType the new FittingType.
-   */
-  onFitTo(fittingType) {}
-
-  /**
-   * Call when the bookmarks panel is opened.
-   */
-  onOpenBookmarksPanel() {}
-
-  /**
-   * Call when a bookmark is followed.
-   */
-  onFollowBookmark() {}
-
-  /**
-   * Call when the page selection is used to navigate to another page.
-   */
-  onPageSelectorNavigation() {}
-};
-
-/**
- * Dummy implementation of PDFMetrics.
- * This is used in print preview mode to avoid bundling the actions in the PDF
- * viewer and the print preview in the same histogram. Also, metricsPrivate is
- * not available in print preview.
- *
- * @implements {PDFMetrics}
- */
-window.PDFMetricsDummy = class {
-  constructor() {}
-
-  /** @override */
-  onDocumentOpened() {}
-
-  /** @override */
-  onRotation() {}
-
-  /** @override */
-  onFitTo(fittingType) {}
-
-  /** @override */
-  onOpenBookmarksPanel() {}
-
-  /** @override */
-  onFollowBookmark() {}
-
-  /** @override */
-  onPageSelectorNavigation() {}
-};
-
-/**
- * Implementation of PDFMetrics that logs the corresponding metrics to UMA
- * through chrome.metricsPrivate.
- *
- * @implements {PDFMetrics}
- */
-window.PDFMetricsImpl = class {
-  constructor() {
-    /**
-     * @private {Set}
-     */
-    this.firstEventLogged_ = new Set();
-
-    /**
-     * @private {Object}
-     */
-    this.actionsMetric_ = {
-      'metricName': 'PDF.Actions',
-      'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG,
-      'min': 1,
-      'max': UserAction.NUMBER_OF_ACTIONS,
-      'buckets': UserAction.NUMBER_OF_ACTIONS + 1
-    };
-  }
-
-  /** @override */
-  onDocumentOpened() {
-    this.logOnlyFirstTime_(UserAction.DOCUMENT_OPENED);
-  }
-
-  /** @override */
-  onRotation() {
-    this.logFirstAndTotal_(UserAction.ROTATE_FIRST, UserAction.ROTATE);
-  }
-
-  /** @override */
-  onFitTo(fittingType) {
-    if (fittingType == FittingType.FIT_TO_PAGE) {
-      this.logFirstAndTotal_(
-          UserAction.FIT_TO_PAGE_FIRST, UserAction.FIT_TO_PAGE);
-    } else if (fittingType == FittingType.FIT_TO_WIDTH) {
-      this.logFirstAndTotal_(
-          UserAction.FIT_TO_WIDTH_FIRST, UserAction.FIT_TO_WIDTH);
-    }
-    // There is no user action to do a fit-to-height, this only happens with
-    // the open param "view=FitV".
-  }
-
-  /** @override */
-  onOpenBookmarksPanel() {
-    this.logFirstAndTotal_(
-        UserAction.OPEN_BOOKMARKS_PANEL_FIRST, UserAction.OPEN_BOOKMARKS_PANEL);
-  }
-
-  /** @override */
-  onFollowBookmark() {
-    this.logFirstAndTotal_(
-        UserAction.FOLLOW_BOOKMARK_FIRST, UserAction.FOLLOW_BOOKMARK);
-  }
-
-  /** @override */
-  onPageSelectorNavigation() {
-    this.logFirstAndTotal_(
-        UserAction.PAGE_SELECTOR_NAVIGATE_FIRST,
-        UserAction.PAGE_SELECTOR_NAVIGATE);
-  }
-
-  /**
-   * Logs the "first" event code if it hasn't been logged by this instance yet
-   * and also log the "total" event code. This distinction allows analyzing
-   * both:
-   * - in what percentage of documents each action was taken;
-   * - how many times, on average, each action is taken on a document;
-   *
-   * @param {number} firstEventCode event code for the "first" metric.
-   * @return {number} totalEventCode event code for the "total"  metric.
-   * @private
-   */
-  logFirstAndTotal_(firstEventCode, totalEventCode) {
-    this.log_(totalEventCode);
-    this.logOnlyFirstTime_(firstEventCode);
-  }
-
-  /**
-   * Logs the given event code to chrome.metricsPrivate.
-   *
-   * @param {number} eventCode event code to log.
-   * @private
-   */
-  log_(eventCode) {
-    chrome.metricsPrivate.recordValue(this.actionsMetric_, eventCode);
-  }
-
-  /**
-   * Logs the given event code. Subsequent calls of this method with the same
-   * event code have no effect on the this PDFMetrics instance.
-   *
-   * @param {number} eventCode event code to log.
-   * @private
-   */
-  logOnlyFirstTime_(eventCode) {
-    if (!this.firstEventLogged_.has(eventCode)) {
-      this.log_(eventCode);
-      this.firstEventLogged_.add(eventCode);
-    }
-  }
-};
-
-window.PDFMetrics.UserAction = UserAction;
-
-}());
+// Map from UserAction to the 'FIRST' action. These metrics are recorded
+// by PDFMetrics.log the first time each corresponding action occurs.
+/** @private Map<number, number> */
+PDFMetrics.firstMap_ = new Map([
+  [
+    PDFMetrics.UserAction.ROTATE,
+    PDFMetrics.UserAction.ROTATE_FIRST,
+  ],
+  [
+    PDFMetrics.UserAction.FIT_TO_WIDTH,
+    PDFMetrics.UserAction.FIT_TO_WIDTH_FIRST,
+  ],
+  [
+    PDFMetrics.UserAction.FIT_TO_PAGE,
+    PDFMetrics.UserAction.FIT_TO_PAGE_FIRST,
+  ],
+  [
+    PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL,
+    PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL_FIRST,
+  ],
+  [
+    PDFMetrics.UserAction.FOLLOW_BOOKMARK,
+    PDFMetrics.UserAction.FOLLOW_BOOKMARK_FIRST,
+  ],
+  [
+    PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE,
+    PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE_FIRST,
+  ],
+]);
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index 79db54d..55f70057 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -135,12 +135,7 @@
   /** @private {boolean} */
   this.hasEnteredAnnotationMode_ = false;
 
-  /**
-   * @type {!PDFMetrics}
-   */
-  this.metrics =
-      (chrome.metricsPrivate ? new PDFMetricsImpl() : new PDFMetricsDummy());
-  this.metrics.onDocumentOpened();
+  PDFMetrics.record(PDFMetrics.UserAction.DOCUMENT_OPENED);
 
   // Parse open pdf parameters.
   this.paramsParser_ = new OpenPDFParamsParser(
@@ -268,9 +263,9 @@
   document.body.addEventListener('change-page', e => {
     this.viewport_.goToPage(e.detail.page);
     if (e.detail.origin == 'bookmark') {
-      this.metrics.onFollowBookmark();
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
     } else if (e.detail.origin == 'pageselector') {
-      this.metrics.onPageSelectorNavigation();
+      PDFMetrics.record(PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE);
     }
   });
 
@@ -288,7 +283,7 @@
 
   document.body.addEventListener('dropdown-opened', e => {
     if (e.detail == 'bookmarks') {
-      this.metrics.onOpenBookmarksPanel();
+      PDFMetrics.record(PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL);
     }
   });
 
@@ -493,7 +488,7 @@
   /**
    * Handles the annotation mode being toggled on or off.
    *
-   * @param {CustomEvent} e
+   * @param {!CustomEvent<{value: boolean}>} e
    * @private
    */
   annotationModeChanged_: async function(e) {
@@ -548,7 +543,10 @@
   /**
    * Request to change the viewport fitting type.
    *
-   * @param {CustomEvent} e Event received with the new FittingType as detail.
+   * @param {!CustomEvent<{
+   *     fittingType: FittingType,
+   *     userInitiated: boolean
+   * }>} e
    * @private
    */
   fitToChanged_: function(e) {
@@ -563,7 +561,7 @@
     }
 
     if (e.detail.userInitiated) {
-      this.metrics.onFitTo(e.detail.fittingType);
+      PDFMetrics.recordFitTo(e.detail.fittingType);
     }
   },
 
@@ -634,7 +632,7 @@
   goToPageAndXY_: function(origin, page, message) {
     this.viewport_.goToPageAndXY(page, message.x, message.y);
     if (origin == 'bookmark') {
-      this.metrics.onFollowBookmark();
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
     }
   },
 
@@ -1373,14 +1371,14 @@
 
   /** @override */
   rotateClockwise() {
-    this.viewer_.metrics.onRotation();
+    PDFMetrics.record(PDFMetrics.UserAction.ROTATE);
     this.viewport_.rotateClockwise(1);
     this.postMessage({type: 'rotateClockwise'});
   }
 
   /** @override */
   rotateCounterClockwise() {
-    this.viewer_.metrics.onRotation();
+    PDFMetrics.record(PDFMetrics.UserAction.ROTATE);
     this.viewport_.rotateClockwise(3);
     this.postMessage({type: 'rotateCounterclockwise'});
   }
diff --git a/chrome/browser/resources/print_preview/new/app.js b/chrome/browser/resources/print_preview/new/app.js
index eeda43d..ccf60ac 100644
--- a/chrome/browser/resources/print_preview/new/app.js
+++ b/chrome/browser/resources/print_preview/new/app.js
@@ -60,6 +60,7 @@
     destination_: {
       type: Object,
       notify: true,
+      value: null,
     },
 
     /** @private {?print_preview.DestinationStore} */
diff --git a/chrome/browser/resources/print_preview/new/destination_settings.html b/chrome/browser/resources/print_preview/new/destination_settings.html
index d2e86d7b..9e1553a 100644
--- a/chrome/browser/resources/print_preview/new/destination_settings.html
+++ b/chrome/browser/resources/print_preview/new/destination_settings.html
@@ -39,8 +39,8 @@
         margin-inline-start: 13px;
       }
 
-      print-preview-settings-section.destination-status-wrapper,
-      print-preview-settings-section.destination-status-wrapper div {
+      #destination-status-wrapper,
+      #destination-status-wrapper div {
         height: 100%;
         min-height: 0;
       }
@@ -48,25 +48,24 @@
     <print-preview-settings-section>
       <span slot="title">$i18n{destinationLabel}</span>
       <div slot="controls">
-        <div class="throbber-container" hidden$="[[!shouldShowSpinner_]]">
+        <div class="throbber-container" hidden$="[[shouldHideSpinner_]]">
           <div class="throbber"></div>
-          <div class="destination-throbber-name"></div>
         </div>
         <print-preview-destination-select id="destinationSelect"
-            hidden$="[[shouldShowSpinner_]]"
+            hidden$="[[!shouldHideSpinner_]]"
             active-user="[[activeUser]]"
             app-kiosk-mode="[[appKioskMode]]"
             cloud-print-state="[[cloudPrintState]]"
             destination="[[destination]]"
             disabled="[[shouldDisableDropdown_(destinationStore, disabled,
-                                               shouldShowSpinner_, state)]]"
+                                               shouldHideSpinner_, state)]]"
             no-destinations-found="[[noDestinationsFound]]"
             recent-destination-list="[[recentDestinationList_]]"
             on-selected-option-change="onSelectedDestinationOptionChange_">
         </print-preview-destination-select>
       </div>
     </print-preview-settings-section>
-    <print-preview-settings-section class="destination-status-wrapper"
+    <print-preview-settings-section id="destination-status-wrapper"
         hidden$="[[!statusText_]]">
       <div slot="title"></div>
       <div slot="controls">
diff --git a/chrome/browser/resources/print_preview/new/destination_settings.js b/chrome/browser/resources/print_preview/new/destination_settings.js
index 1ba7c43..195bb8e 100644
--- a/chrome/browser/resources/print_preview/new/destination_settings.js
+++ b/chrome/browser/resources/print_preview/new/destination_settings.js
@@ -38,7 +38,6 @@
     noDestinationsFound: {
       type: Boolean,
       value: false,
-      observer: 'updateShouldShowSpinner_',
     },
 
     /** @type {!Array<!print_preview.RecentDestination>} */
@@ -54,23 +53,24 @@
     recentDestinationList_: Array,
 
     /** @private */
-    shouldShowSpinner_: {
+    shouldHideSpinner_: {
       type: Boolean,
-      value: true,
-      observer: 'onShouldShowSpinnerChange_',
+      computed: 'computeShouldHideSpinner_(' +
+          'destination, noDestinationsFound, cloudPrintState)',
     },
 
     /** @private {string} */
     statusText_: {
       type: String,
-      computed: 'computeStatusText_(destination.connectionStatus, ' +
-          'destination.shouldShowInvalidCertificateError)',
+      computed: 'computeStatusText_(destination)',
     },
   },
 
   observers: [
     'updateRecentDestinationList_(' +
         'recentDestinations.*, activeUser, destinationStore)',
+    'updateDestinationSelect_(' +
+        'destination, noDestinationsFound, cloudPrintState)',
   ],
 
   /** @private {!EventTracker} */
@@ -138,7 +138,7 @@
    */
   shouldDisableDropdown_: function() {
     return !this.destinationStore || this.noDestinationsFound ||
-        this.shouldShowSpinner_ ||
+        !this.shouldHideSpinner_ ||
         (this.disabled && this.state != print_preview_new.State.NOT_READY &&
          this.state != print_preview_new.State.INVALID_PRINTER);
   },
@@ -149,10 +149,6 @@
       return;
     }
 
-    if (this.destination && this.destination.account !== '') {
-      this.updateDestination_();
-    }
-
     // Load docs, in case the user was not signed in previously and signed in
     // from the destinations dialog.
     this.destinationStore.startLoadCookieDestination(
@@ -170,7 +166,6 @@
 
   /** @private */
   onDestinationSet_: function() {
-    this.updateShouldShowSpinner_();
     if (this.cloudPrintState === print_preview.CloudPrintState.ENABLED) {
       // Only try to load the docs destination for now. If this request
       // succeeds, it will trigger a transition to SIGNED_IN, and we can
@@ -182,8 +177,14 @@
   },
 
   /** @private */
-  updateShouldShowSpinner_: function() {
-    this.shouldShowSpinner_ = !this.destination && !this.noDestinationsFound;
+  computeShouldHideSpinner_: function() {
+    if (this.noDestinationsFound) {
+      return true;
+    }
+
+    return !!this.destination &&
+        (this.destination.origin !== print_preview.DestinationOrigin.COOKIES ||
+         this.cloudPrintState === print_preview.CloudPrintState.SIGNED_IN);
   },
 
   /**
@@ -222,14 +223,19 @@
   onDialogClose_: function() {
     // Reset the select value if the user dismissed the dialog without
     // selecting a new destination.
-    if (this.destination) {
-      this.updateDestination_();
-    }
+    this.updateDestinationSelect_();
     this.$.destinationSelect.focus();
   },
 
   /** @private */
-  updateDestination_: function() {
+  updateDestinationSelect_: function() {
+    if (!this.destination ||
+        (this.destination.origin === print_preview.DestinationOrigin.COOKIES &&
+         this.cloudPrintState !== print_preview.CloudPrintState.SIGNED_IN) ||
+        this.noDestinationsFound) {
+      return;
+    }
+
     // TODO (rbpotter): Remove this conditional when the Polymer 2 migration
     // is completed.
     if (Polymer.DomIf) {
@@ -242,14 +248,4 @@
       });
     }
   },
-
-  /** @private */
-  onShouldShowSpinnerChange_: function() {
-    if (this.shouldShowSpinner_ || this.noDestinationsFound ||
-        (this.cloudPrintState !== print_preview.CloudPrintState.SIGNED_IN &&
-         this.destination.account !== '')) {
-      return;
-    }
-    this.updateDestination_();
-  },
 });
diff --git a/chrome/browser/resources/settings/people_page/sync_page.js b/chrome/browser/resources/settings/people_page/sync_page.js
index c1c84aa2..dda9dd2 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.js
+++ b/chrome/browser/resources/settings/people_page/sync_page.js
@@ -153,18 +153,33 @@
   browserProxy_: null,
 
   /**
-   * The unload callback is needed because the sign-in flow needs to know
-   * if the user has closed the tab with the sync settings. This property is
-   * non-null if the user is currently navigated on the sync settings route.
+   * If unified consent is enabled, the beforeunload callback is used to
+   * show the 'Leave site' dialog. This makes sure that the user has the chance
+   * to go back and confirm the sync opt-in before leaving.
    *
-   * TODO(crbug.com/862983): When unified consent is rolled out to 100% this
-   * should be removed.
+   * If unified consent is disabled, the beforeunload callback is used
+   * to confirm the sync setup before leaving the opt-in flow.
+   *
+   * This property is non-null if the user is currently navigated on the sync
+   * settings route.
    *
    * @private {?Function}
    */
   beforeunloadCallback_: null,
 
   /**
+   * If unified consent is enabled, the unload callback is used to cancel the
+   * sync setup when the user hits the browser back button after arriving on the
+   * page.
+   * Note: Cases like closing the tab or reloading don't need to be handled,
+   * because they are already caught in |PeopleHandler::~PeopleHandler|
+   * from the C++ code.
+   *
+   * @private {?Function}
+   */
+  unloadCallback_: null,
+
+  /**
    * Whether the initial layout for collapsible sections has been computed. It
    * is computed only once, the first time the sync status is updated.
    * @private {boolean}
@@ -211,6 +226,10 @@
       window.removeEventListener('beforeunload', this.beforeunloadCallback_);
       this.beforeunloadCallback_ = null;
     }
+    if (this.unloadCallback_) {
+      window.removeEventListener('unload', this.unloadCallback_);
+      this.unloadCallback_ = null;
+    }
   },
 
   /**
@@ -316,8 +335,24 @@
 
     this.browserProxy_.didNavigateToSyncPage();
 
-    this.beforeunloadCallback_ = this.onNavigateAwayFromPage_.bind(this);
-    window.addEventListener('beforeunload', this.beforeunloadCallback_);
+    if (this.unifiedConsentEnabled) {
+      this.beforeunloadCallback_ = event => {
+        // When the user tries to leave the sync setup, show the 'Leave site'
+        // dialog.
+        if (this.unifiedConsentEnabled && this.syncStatus &&
+            !!this.syncStatus.setupInProgress) {
+          event.preventDefault();
+          event.returnValue = '';
+        }
+      };
+      window.addEventListener('beforeunload', this.beforeunloadCallback_);
+
+      this.unloadCallback_ = this.onNavigateAwayFromPage_.bind(this);
+      window.addEventListener('unload', this.unloadCallback_);
+    } else {
+      this.beforeunloadCallback_ = this.onNavigateAwayFromPage_.bind(this);
+      window.addEventListener('beforeunload', this.beforeunloadCallback_);
+    }
   },
 
   /** @private */
@@ -335,6 +370,11 @@
 
     window.removeEventListener('beforeunload', this.beforeunloadCallback_);
     this.beforeunloadCallback_ = null;
+
+    if (this.unloadCallback_) {
+      window.removeEventListener('unload', this.unloadCallback_);
+      this.unloadCallback_ = null;
+    }
   },
 
   /**
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js
index 084becdba..ac4599b 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.js
+++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -22,15 +22,6 @@
     blockAutoplayEnabled: Boolean,
 
     /**
-     * The origin that this widget is showing details for.
-     * @private
-     */
-    origin: {
-      type: String,
-      observer: 'onOriginChanged_',
-    },
-
-    /**
      * Use the string representing the origin or extension name as the page
      * title of the settings-subpage parent.
      */
@@ -40,6 +31,12 @@
     },
 
     /**
+     * The origin that this widget is showing details for.
+     * @private
+     */
+    origin_: String,
+
+    /**
      * The amount of data stored for the origin.
      * @private
      */
@@ -91,20 +88,13 @@
     if (!site) {
       return;
     }
-    this.origin = site;
-  },
-
-  /**
-   * Handler for when the origin changes.
-   * @private
-   */
-  onOriginChanged_: function() {
-    this.browserProxy.isOriginValid(this.origin).then((valid) => {
+    this.origin_ = site;
+    this.browserProxy.isOriginValid(this.origin_).then((valid) => {
       if (!valid) {
         settings.navigateToPreviousRoute();
       } else {
         if (this.enableSiteSettings_) {
-          this.$.usageApi.fetchUsageTotal(this.toUrl(this.origin).hostname);
+          this.$.usageApi.fetchUsageTotal(this.toUrl(this.origin_).hostname);
         }
 
         this.updatePermissions_(this.getCategoryList());
@@ -122,7 +112,7 @@
    * @private
    */
   onPermissionChanged_: function(category, origin, embeddingOrigin) {
-    if (this.origin === undefined || this.origin == '' ||
+    if (this.origin_ === undefined || this.origin_ == '' ||
         origin === undefined || origin == '') {
       return;
     }
@@ -132,9 +122,7 @@
 
     // Site details currently doesn't support embedded origins, so ignore it
     // and just check whether the origins are the same.
-    if (this.toUrl(origin).origin == this.toUrl(this.origin).origin) {
-      this.updatePermissions_([category]);
-    }
+    this.updatePermissions_([category]);
   },
 
   // <if expr="chromeos">
@@ -145,7 +133,7 @@
 
   /**
    * Retrieves the permissions listed in |categoryList| from the backend for
-   * |this.origin|.
+   * |this.origin_|.
    * @param {!Array<!settings.ContentSettingsTypes>} categoryList The list
    *     of categories to update permissions for.
    * @private
@@ -166,7 +154,7 @@
             },
             {}));
 
-    this.browserProxy.getOriginPermissions(this.origin, categoryList)
+    this.browserProxy.getOriginPermissions(this.origin_, categoryList)
         .then((exceptionList) => {
           exceptionList.forEach((exception, i) => {
             // |exceptionList| should be in the same order as
@@ -212,10 +200,10 @@
    */
   onResetSettings_: function(e) {
     this.browserProxy.setOriginPermissions(
-        this.origin, this.getCategoryList(), settings.ContentSetting.DEFAULT);
+        this.origin_, this.getCategoryList(), settings.ContentSetting.DEFAULT);
     if (this.getCategoryList().includes(
             settings.ContentSettingsTypes.PLUGINS)) {
-      this.browserProxy.clearFlashPref(this.origin);
+      this.browserProxy.clearFlashPref(this.origin_);
     }
 
     this.onCloseDialog_(e);
@@ -229,7 +217,7 @@
     // Since usage is only shown when "Site Settings" is enabled, don't
     // clear it when it's not shown.
     if (this.enableSiteSettings_ && this.storedData_ != '') {
-      this.$.usageApi.clearUsage(this.toUrl(this.origin).href);
+      this.$.usageApi.clearUsage(this.toUrl(this.origin_).href);
     }
 
     this.onCloseDialog_(e);
@@ -242,7 +230,7 @@
    * @private
    */
   onUsageDeleted_: function(event) {
-    if (event.detail.origin == this.toUrl(this.origin).href) {
+    if (event.detail.origin == this.toUrl(this.origin_).href) {
       this.storedData_ = '';
     }
   },
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc
index 1f6d495..e039826 100644
--- a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc
@@ -40,7 +40,7 @@
       "}";
   base::JSONReader reader;
 
-  std::unique_ptr<base::Value> root(reader.Read(kData));
+  std::unique_ptr<base::Value> root(reader.ReadDeprecated(kData));
   EXPECT_TRUE(root);
   base::DictionaryValue* incidents_sent = nullptr;
   EXPECT_TRUE(root->GetAsDictionary(&incidents_sent));
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 7243922..ab05e3c9 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -504,7 +504,8 @@
   EXPECT_EQ("/pkp", request.relative_url);
   EXPECT_EQ("POST", request.method_string);
   base::JSONReader json_reader;
-  std::unique_ptr<base::Value> value = json_reader.ReadToValue(request.content);
+  std::unique_ptr<base::Value> value =
+      json_reader.ReadToValueDeprecated(request.content);
   EXPECT_TRUE(value);
 
   base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index fbe8461..14e6308 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2653,8 +2653,6 @@
       "views/overlay/back_to_tab_image_button.h",
       "views/overlay/close_image_button.cc",
       "views/overlay/close_image_button.h",
-      "views/overlay/control_image_button.cc",
-      "views/overlay/control_image_button.h",
       "views/overlay/overlay_window_views.cc",
       "views/overlay/overlay_window_views.h",
       "views/overlay/playback_image_button.cc",
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index 20878ed..c20709d7 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
+#include "ash/public/cpp/vector_icons/vector_icons.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
@@ -193,7 +194,11 @@
       bookmark_model && bookmark_model->IsBookmarked(match_.destination_url);
 
   const gfx::VectorIcon& icon =
-      is_bookmarked ? kBookmarkIcon : TypeToVectorIcon(match_.type);
+      is_bookmarked ? kBookmarkIcon
+                    : app_list_features::IsEmbeddedAssistantUIEnabled() &&
+                              AutocompleteMatch::IsSearchType(match_.type)
+                          ? ash::kAssistantIcon
+                          : TypeToVectorIcon(match_.type);
   SetIcon(gfx::CreateVectorIcon(
       icon, AppListConfig::instance().search_list_icon_dimension(),
       kListIconColor));
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
index d84766f..339beb4 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
@@ -254,13 +254,15 @@
   constexpr float kSeparatorOpacity = 0.15f;
 
   gfx::Rect bounds = GetLocalBounds();
+  const gfx::Size separator_size = gfx::Size(bounds.width(), 1);
+
   // Inset the bounds by 1 on the bottom, so we draw the bottom border inside
   // the custom tab bar.
   bounds.Inset(0, 0, 0, 1);
 
   // Custom tab/content separator (bottom border).
-  canvas->DrawLine(
-      bounds.bottom_left(), bounds.bottom_right(),
+  canvas->FillRect(
+      gfx::Rect(bounds.bottom_left(), separator_size),
       color_utils::AlphaBlend(kSeparatorColor, kCustomTabBarViewBackgroundColor,
                               kSeparatorOpacity));
 
@@ -274,7 +276,7 @@
   }
 
   // Frame/Custom tab separator (top border).
-  canvas->DrawLine(bounds.origin(), bounds.top_right(),
+  canvas->FillRect(gfx::Rect(bounds.origin(), separator_size),
                    color_utils::AlphaBlend(kSeparatorColor, title_bar_color_,
                                            kSeparatorOpacity));
 }
diff --git a/chrome/browser/ui/views/overlay/control_image_button.cc b/chrome/browser/ui/views/overlay/control_image_button.cc
deleted file mode 100644
index 8489922..0000000
--- a/chrome/browser/ui/views/overlay/control_image_button.cc
+++ /dev/null
@@ -1,14 +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.
-
-#include "chrome/browser/ui/views/overlay/control_image_button.h"
-
-namespace views {
-
-ControlImageButton::ControlImageButton(ButtonListener* listener)
-    : ImageButton(listener), id_() {}
-
-ControlImageButton::~ControlImageButton() = default;
-
-}  // namespace views
diff --git a/chrome/browser/ui/views/overlay/control_image_button.h b/chrome/browser/ui/views/overlay/control_image_button.h
deleted file mode 100644
index 3063802..0000000
--- a/chrome/browser/ui/views/overlay/control_image_button.h
+++ /dev/null
@@ -1,33 +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.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_CONTROL_IMAGE_BUTTON_H_
-#define CHROME_BROWSER_UI_VIEWS_OVERLAY_CONTROL_IMAGE_BUTTON_H_
-
-#include "ui/views/controls/button/image_button.h"
-
-namespace views {
-
-// An image button with an associated id.
-class ControlImageButton : public views::ImageButton {
- public:
-  explicit ControlImageButton(ButtonListener*);
-
-  ~ControlImageButton() override;
-
-  void set_id(const std::string& id) { id_ = id; }
-
-  const std::string& id() const { return id_; }
-
- private:
-  // The id that is passed back to the browser when interacting with it fires an
-  // event.
-  std::string id_;
-
-  DISALLOW_COPY_AND_ASSIGN(ControlImageButton);
-};
-
-}  // namespace views
-
-#endif  // CHROME_BROWSER_UI_VIEWS_OVERLAY_CONTROL_IMAGE_BUTTON_H_
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 07d1e76..961247d 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -8,14 +8,12 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h"
 #include "chrome/browser/ui/views/overlay/close_image_button.h"
-#include "chrome/browser/ui/views/overlay/control_image_button.h"
 #include "chrome/browser/ui/views/overlay/playback_image_button.h"
 #include "chrome/browser/ui/views/overlay/resize_handle_button.h"
 #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
@@ -26,7 +24,6 @@
 #include "content/public/browser/web_contents.h"
 #include "media/base/media_switches.h"
 #include "media/base/video_util.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -57,20 +54,17 @@
 
 const int kOverlayBorderThickness = 10;
 
-// |button_size_| scales both its width and height to be 30% the size of the
-// smaller of the screen's width and height.
-const float kControlRatioToWindow = 0.3;
+// play/pause control scales both its width and height to be 30% the size of
+// the smaller of the screen's width and height.
+const float kPlayPauseControlRatioToWindow = 0.3;
 
-// Track buttons sizes are 60% smaller than Play/Pause button.
-const float kTrackButtonSizeScale = 0.6;
+// track controls scales both their width and height to be 60% the size of the
+// play/pause control.
+const float kTrackControlRatioToPlayPauseControl = 0.6;
 
 const int kMinControlButtonSize = 48;
 const int kControlButtonMargin = 12;
 
-// Colors for the control buttons.
-SkColor kBgColor = SK_ColorWHITE;
-SkColor kControlIconColor = SK_ColorBLACK;
-
 // Returns the quadrant the OverlayWindowViews is primarily in on the current
 // work area.
 OverlayWindowViews::WindowQuadrant GetCurrentWindowQuadrant(
@@ -125,8 +119,6 @@
         (window->GetBackToTabControlsBounds().Contains(point) ||
          window->GetSkipAdControlsBounds().Contains(point) ||
          window->GetCloseControlsBounds().Contains(point) ||
-         window->GetFirstCustomControlsBounds().Contains(point) ||
-         window->GetSecondCustomControlsBounds().Contains(point) ||
          window->GetPlayPauseControlsBounds().Contains(point) ||
          window->GetNextTrackControlsBounds().Contains(point) ||
          window->GetPreviousTrackControlsBounds().Contains(point))) {
@@ -491,100 +483,24 @@
   controls_parent_view_->SetBoundsRect(
       gfx::Rect(gfx::Point(0, 0), GetBounds().size()));
 
-  // FIXME: Merge with UpdateControlsPositions when custom controls are removed.
-  if (show_next_track_button_ || show_previous_track_button_) {
-    int mid_window_x = GetBounds().size().width() / 2;
-    play_pause_controls_view_->SetBoundsRect(CalculateControlsBounds(
-        mid_window_x - button_size_.width() / 2, button_size_));
-    if (show_next_track_button_)
-      next_track_controls_view_->SetBoundsRect(CalculateControlsBounds(
-          mid_window_x + button_size_.width() / 2 + kControlButtonMargin,
-          next_track_controls_view_->GetLastVisibleSize()));
-    if (show_previous_track_button_)
-      previous_track_controls_view_->SetBoundsRect(CalculateControlsBounds(
-          mid_window_x - button_size_.width() / 2 -
-              previous_track_controls_view_->GetLastVisibleSize().width() -
-              kControlButtonMargin,
-          previous_track_controls_view_->GetLastVisibleSize()));
-  } else {
-    UpdateControlsPositions();
+  int mid_window_x = GetBounds().size().width() / 2;
+  play_pause_controls_view_->SetBoundsRect(CalculateControlsBounds(
+      mid_window_x - play_pause_controls_view_->size().width() / 2,
+      play_pause_controls_view_->size()));
+
+  if (show_next_track_button_) {
+    next_track_controls_view_->SetBoundsRect(CalculateControlsBounds(
+        mid_window_x + play_pause_controls_view_->size().width() / 2 +
+            kControlButtonMargin,
+        next_track_controls_view_->GetLastVisibleSize()));
   }
-}
-
-void OverlayWindowViews::UpdateButtonSize() {
-  const gfx::Size window_size = GetBounds().size();
-  int scaled_button_dimension =
-      window_size.width() < window_size.height()
-          ? window_size.width() * kControlRatioToWindow
-          : window_size.height() * kControlRatioToWindow;
-
-  int new_button_dimension =
-      std::max(kMinControlButtonSize, scaled_button_dimension);
-
-  button_size_.SetSize(new_button_dimension, new_button_dimension);
-}
-
-void OverlayWindowViews::UpdateCustomControlsSize(
-    views::ControlImageButton* control_button) {
-  if (!control_button)
-    return;
-  UpdateButtonSize();
-  control_button->SetSize(button_size_);
-  // TODO(sawtelle): Download the images and add them to the controls.
-  // https://crbug.com/864271.
-  if (control_button == first_custom_controls_view_.get()) {
-    first_custom_controls_view_->SetImage(
-        views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(vector_icons::kPlayArrowIcon,
-                              button_size_.width() / 2, kControlIconColor));
+  if (show_previous_track_button_) {
+    previous_track_controls_view_->SetBoundsRect(CalculateControlsBounds(
+        mid_window_x - play_pause_controls_view_->size().width() / 2 -
+            previous_track_controls_view_->GetLastVisibleSize().width() -
+            kControlButtonMargin,
+        previous_track_controls_view_->GetLastVisibleSize()));
   }
-  if (control_button == second_custom_controls_view_.get()) {
-    second_custom_controls_view_->SetImage(
-        views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(vector_icons::kPauseIcon,
-                              button_size_.width() / 2, kControlIconColor));
-  }
-  const gfx::ImageSkia control_background = gfx::CreateVectorIcon(
-      kPictureInPictureControlBackgroundIcon, button_size_.width(), kBgColor);
-  control_button->SetBackgroundImage(kBgColor, &control_background,
-                                     &control_background);
-}
-
-void OverlayWindowViews::UpdateButtonControlsSize() {
-  // FIXME: Inline UpdateButtonSize() when custom controls are removed.
-  UpdateButtonSize();
-  play_pause_controls_view_->SetSize(button_size_);
-  gfx::Size track_button_size =
-      gfx::ScaleToRoundedSize(button_size_, kTrackButtonSizeScale);
-  next_track_controls_view_->SetSize(track_button_size);
-  previous_track_controls_view_->SetSize(track_button_size);
-}
-
-void OverlayWindowViews::CreateCustomControl(
-    std::unique_ptr<views::ControlImageButton>& control_button,
-    const blink::PictureInPictureControlInfo& info,
-    ControlPosition position) {
-  control_button = std::make_unique<views::ControlImageButton>(this);
-  controls_parent_view_->AddChildView(control_button.get());
-  control_button->set_id(info.id);
-  control_button->set_owned_by_client();
-
-  // Sizing / positioning.
-  control_button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                                    views::ImageButton::ALIGN_MIDDLE);
-  UpdateCustomControlsSize(control_button.get());
-  UpdateControlsBounds();
-
-  // Accessibility.
-  base::string16 custom_button_label = base::UTF8ToUTF16(info.label);
-  control_button->SetAccessibleName(custom_button_label);
-  control_button->SetTooltipText(custom_button_label);
-  control_button->SetInstallFocusRingOnFocus(true);
-  control_button->SetFocusForPlatform();
-}
-
-bool OverlayWindowViews::HasOnlyOneCustomControl() {
-  return first_custom_controls_view_ && !second_custom_controls_view_;
 }
 
 gfx::Rect OverlayWindowViews::CalculateControlsBounds(int x,
@@ -593,44 +509,24 @@
       gfx::Point(x, (GetBounds().size().height() - size.height()) / 2), size);
 }
 
-void OverlayWindowViews::UpdateControlsPositions() {
-  int mid_window_x = GetBounds().size().width() / 2;
+void OverlayWindowViews::UpdateButtonControlsSize() {
+  const gfx::Size window_size = GetBounds().size();
+  int scaled_button_dimension =
+      window_size.width() < window_size.height()
+          ? window_size.width() * kPlayPauseControlRatioToWindow
+          : window_size.height() * kPlayPauseControlRatioToWindow;
 
-  // The controls should always be centered, regardless of how many there are.
-  // When there are only two controls, make them symmetric from the center.
-  //  __________________________
-  // |                          |
-  // |                          |
-  // |        [1]   [P]         |
-  // |                          |
-  // |__________________________|
-  if (HasOnlyOneCustomControl()) {
-    play_pause_controls_view_->SetBoundsRect(
-        CalculateControlsBounds(mid_window_x, button_size_));
-    first_custom_controls_view_->SetBoundsRect(CalculateControlsBounds(
-        mid_window_x - button_size_.width(), button_size_));
-    return;
-  }
+  int new_button_dimension =
+      std::max(kMinControlButtonSize, scaled_button_dimension);
 
-  // Place the play / pause control in the center of the window. If both custom
-  // controls are specified, place them on either side to maintain the balance,
-  // from left to right.
-  //  __________________________
-  // |                          |
-  // |                          |
-  // |     [1]   [P]   [2]      |
-  // |                          |
-  // |__________________________|
-  play_pause_controls_view_->SetBoundsRect(CalculateControlsBounds(
-      mid_window_x - button_size_.width() / 2, button_size_));
+  const gfx::Size play_pause_button_size(new_button_dimension,
+                                         new_button_dimension);
 
-  if (first_custom_controls_view_ && second_custom_controls_view_) {
-    first_custom_controls_view_->SetBoundsRect(CalculateControlsBounds(
-        mid_window_x - button_size_.width() / 2 - button_size_.width(),
-        button_size_));
-    second_custom_controls_view_->SetBoundsRect(CalculateControlsBounds(
-        mid_window_x + button_size_.width() / 2, button_size_));
-  }
+  play_pause_controls_view_->SetSize(play_pause_button_size);
+  gfx::Size track_button_size = gfx::ScaleToRoundedSize(
+      play_pause_button_size, kTrackControlRatioToPlayPauseControl);
+  next_track_controls_view_->SetSize(track_button_size);
+  previous_track_controls_view_->SetSize(track_button_size);
 }
 
 bool OverlayWindowViews::IsActive() const {
@@ -704,6 +600,7 @@
     return;
 
   show_next_track_button_ = is_visible;
+  UpdateButtonControlsSize();
   UpdateControlsBounds();
 }
 
@@ -712,23 +609,10 @@
     return;
 
   show_previous_track_button_ = is_visible;
+  UpdateButtonControlsSize();
   UpdateControlsBounds();
 }
 
-void OverlayWindowViews::SetPictureInPictureCustomControls(
-    const std::vector<blink::PictureInPictureControlInfo>& controls) {
-  // Clear any existing controls.
-  first_custom_controls_view_.reset();
-  second_custom_controls_view_.reset();
-
-  if (controls.size() > 0)
-    CreateCustomControl(first_custom_controls_view_, controls[0],
-                        ControlPosition::kLeft);
-  if (controls.size() > 1)
-    CreateCustomControl(second_custom_controls_view_, controls[1],
-                        ControlPosition::kRight);
-}
-
 ui::Layer* OverlayWindowViews::GetWindowBackgroundLayer() {
   return window_background_view_->layer();
 }
@@ -790,8 +674,6 @@
     UpdateControlsVisibility(false);
 
   // Update the view layers to scale to |new_size|.
-  UpdateCustomControlsSize(first_custom_controls_view_.get());
-  UpdateCustomControlsSize(second_custom_controls_view_.get());
   UpdateButtonControlsSize();
   UpdateLayerBoundsWithLetterboxing(new_size);
 
@@ -929,12 +811,6 @@
 
   if (sender == previous_track_controls_view_.get())
     controller_->PreviousTrack();
-
-  if (sender == first_custom_controls_view_.get())
-    controller_->CustomControlPressed(first_custom_controls_view_->id());
-
-  if (sender == second_custom_controls_view_.get())
-    controller_->CustomControlPressed(second_custom_controls_view_->id());
 }
 
 gfx::Rect OverlayWindowViews::GetBackToTabControlsBounds() {
@@ -965,18 +841,6 @@
   return previous_track_controls_view_->GetMirroredBounds();
 }
 
-gfx::Rect OverlayWindowViews::GetFirstCustomControlsBounds() {
-  if (!first_custom_controls_view_)
-    return gfx::Rect();
-  return first_custom_controls_view_->GetMirroredBounds();
-}
-
-gfx::Rect OverlayWindowViews::GetSecondCustomControlsBounds() {
-  if (!second_custom_controls_view_)
-    return gfx::Rect();
-  return second_custom_controls_view_->GetMirroredBounds();
-}
-
 int OverlayWindowViews::GetResizeHTComponent() const {
   return resize_handle_view_->GetHTComponent();
 }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index e0c8be0..57c805e 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -18,7 +18,6 @@
 
 namespace views {
 class BackToTabImageButton;
-class ControlImageButton;
 class CloseImageButton;
 class PlaybackImageButton;
 class ResizeHandleButton;
@@ -53,8 +52,6 @@
   void SetSkipAdButtonVisibility(bool is_visible) override;
   void SetNextTrackButtonVisibility(bool is_visible) override;
   void SetPreviousTrackButtonVisibility(bool is_visible) override;
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>& controls) override;
   ui::Layer* GetWindowBackgroundLayer() override;
   ui::Layer* GetVideoLayer() override;
   gfx::Rect GetVideoBounds() override;
@@ -82,8 +79,6 @@
   gfx::Rect GetPlayPauseControlsBounds();
   gfx::Rect GetNextTrackControlsBounds();
   gfx::Rect GetPreviousTrackControlsBounds();
-  gfx::Rect GetFirstCustomControlsBounds();
-  gfx::Rect GetSecondCustomControlsBounds();
 
   // Gets the proper hit test component when the hit point is on the resize
   // handle in order to force a drag-to-resize.
@@ -104,9 +99,6 @@
   OverlayWindowViews::PlaybackState playback_state_for_testing() const;
 
  private:
-  // Possible positions for the custom controls added to the window.
-  enum class ControlPosition { kLeft, kRight };
-
   // Determine the intended bounds of |this|. This should be called when there
   // is reason for the bounds to change, such as switching primary displays or
   // playing a new video (i.e. different aspect ratio). This also updates
@@ -126,29 +118,13 @@
   // Updates the bounds of the controls.
   void UpdateControlsBounds();
 
-  // Update the size the controls views use as the size of the window changes.
-  void UpdateButtonSize();
-
   // Update the size of each controls view as the size of the window changes.
-  void UpdateCustomControlsSize(views::ControlImageButton* control_button);
   void UpdateButtonControlsSize();
 
-  void CreateCustomControl(
-      std::unique_ptr<views::ControlImageButton>& control_button,
-      const blink::PictureInPictureControlInfo& info,
-      ControlPosition position);
-
-  // Returns whether there is exactly one custom control on the window.
-  bool HasOnlyOneCustomControl();
-
   // Calculate and set the bounds of the controls.
   gfx::Rect CalculateControlsBounds(int x, const gfx::Size& size);
   void UpdateControlsPositions();
 
-  // Sets the bounds of the custom controls.
-  void SetFirstCustomControlsBounds();
-  void SetSecondCustomControlsBounds();
-
   ui::Layer* GetControlsScrimLayer();
   ui::Layer* GetBackToTabControlsLayer();
   ui::Layer* GetCloseControlsLayer();
@@ -184,9 +160,6 @@
   gfx::Size min_size_;
   gfx::Size max_size_;
 
-  // Current sizes of the control views on the Picture-in-Picture window.
-  gfx::Size button_size_;
-
   // Current bounds of the Picture-in-Picture window.
   gfx::Rect window_bounds_;
 
@@ -201,8 +174,8 @@
   std::unique_ptr<views::View> window_background_view_;
   std::unique_ptr<views::View> video_view_;
   std::unique_ptr<views::View> controls_scrim_view_;
-  // |controls_parent_view_| is the parent view of all control views except
-  // the back-to-tab, close and skip-ad views.
+  // |controls_parent_view_| is the parent view of play/pause, previous
+  // track and next track control views.
   std::unique_ptr<views::View> controls_parent_view_;
   std::unique_ptr<views::BackToTabImageButton> back_to_tab_controls_view_;
   std::unique_ptr<views::SkipAdLabelButton> skip_ad_controls_view_;
@@ -211,8 +184,6 @@
   std::unique_ptr<views::PlaybackImageButton> play_pause_controls_view_;
   std::unique_ptr<views::TrackImageButton> next_track_controls_view_;
   std::unique_ptr<views::TrackImageButton> previous_track_controls_view_;
-  std::unique_ptr<views::ControlImageButton> first_custom_controls_view_;
-  std::unique_ptr<views::ControlImageButton> second_custom_controls_view_;
 #if defined(OS_CHROMEOS)
   std::unique_ptr<ash::RoundedCornerDecorator> decorator_;
 #endif
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
index 0bfac5f..024b7e2b 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
@@ -345,7 +345,7 @@
   // Add the policy setting to prefs.
   Profile* profile = web_contents_helper_.profile();
   profile->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                           *base::JSONReader::Read(kPolicySetting));
+                           *base::JSONReader::ReadDeprecated(kPolicySetting));
   UsbChooserContext* store = UsbChooserContextFactory::GetForProfile(profile);
 
   auto objects = store->GetGrantedObjects(origin, origin);
@@ -397,7 +397,7 @@
   // Add the policy setting to prefs.
   Profile* profile = web_contents_helper_.profile();
   profile->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                           *base::JSONReader::Read(kPolicySetting));
+                           *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   // Connect the UsbChooserContext with FakeUsbDeviceManager.
   device::FakeUsbDeviceManager usb_device_manager;
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.h b/chrome/browser/ui/views/select_file_dialog_extension.h
index 7e112bf..3145aff2 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.h
+++ b/chrome/browser/ui/views/select_file_dialog_extension.h
@@ -78,6 +78,7 @@
  private:
   friend class SelectFileDialogExtensionBrowserTest;
   friend class SelectFileDialogExtensionTest;
+  friend class SelectFileDialogExtensionTestFactory;
 
   // Object is ref-counted, use Create().
   explicit SelectFileDialogExtension(
diff --git a/chrome/browser/ui/webui/explore_sites_internals/explore_sites_internals_page_handler.cc b/chrome/browser/ui/webui/explore_sites_internals/explore_sites_internals_page_handler.cc
index dbe9ff2..7bf71367 100644
--- a/chrome/browser/ui/webui/explore_sites_internals/explore_sites_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/explore_sites_internals/explore_sites_internals_page_handler.cc
@@ -28,6 +28,8 @@
       return "Experiment";
     case ExploreSitesVariation::PERSONALIZED:
       return "Personalized";
+    case ExploreSitesVariation::CONDENSED:
+      return "Condensed";
     case ExploreSitesVariation::DISABLED:
       return "Disabled";
   }
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 35788b8..4318cbcdd9 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -36,7 +36,6 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/http/http_status_code.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 
@@ -304,12 +303,9 @@
 
 class TestMessageLoopCondition {
  public:
-  TestMessageLoopCondition() : signaled_(false),
-                               waiting_(false) {
-  }
+  TestMessageLoopCondition() : signaled_(false), waiting_(false) {}
 
-  ~TestMessageLoopCondition() {
-  }
+  ~TestMessageLoopCondition() {}
 
   // Signal a waiting method that it can continue executing.
   void Signal() {
@@ -339,12 +335,8 @@
 class LocalDiscoveryUITest : public WebUIBrowserTest {
  public:
   LocalDiscoveryUITest()
-      : test_shared_loader_factory_(
-            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-                &test_url_loader_factory_)),
-        set_url_loader_factory_(test_shared_loader_factory_) {}
-
-  ~LocalDiscoveryUITest() override { test_shared_loader_factory_->Detach(); }
+      : set_url_loader_factory_(test_url_loader_factory_.GetSafeWeakWrapper()) {
+  }
 
   void SetUp() override {
     // We need to stub out DualMediaSinkService here, because the profile setup
@@ -391,12 +383,11 @@
 
     SetURLLoaderFactoryForTest(
         ProfileManager::GetActiveUserProfile() /* profile */,
-        test_shared_loader_factory_);
+        test_url_loader_factory_.GetSafeWeakWrapper());
   }
 
   void TearDownOnMainThread() override {
     test_service_discovery_client_ = nullptr;
-    test_shared_loader_factory_->Detach();
     WebUIBrowserTest::TearDownOnMainThread();
   }
 
@@ -439,8 +430,6 @@
   scoped_refptr<TestServiceDiscoveryClient> test_service_discovery_client_;
   TestMessageLoopCondition condition_devices_listed_;
   network::TestURLLoaderFactory test_url_loader_factory_;
-  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
-      test_shared_loader_factory_;
   local_discovery::LocalDiscoveryUIHandler::SetURLLoaderFactoryForTesting
       set_url_loader_factory_;
 
@@ -448,26 +437,24 @@
 };
 
 IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, EmptyTest) {
-  ui_test_utils::NavigateToURL(browser(), GURL(
-      chrome::kChromeUIDevicesURL));
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDevicesURL));
   condition_devices_listed().Wait();
   EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices"));
 }
 
 IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, AddRowTest) {
-  ui_test_utils::NavigateToURL(browser(), GURL(
-      chrome::kChromeUIDevicesURL));
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDevicesURL));
   condition_devices_listed().Wait();
 
-  test_service_discovery_client()->SimulateReceive(
-      kAnnouncePacket, sizeof(kAnnouncePacket));
+  test_service_discovery_client()->SimulateReceive(kAnnouncePacket,
+                                                   sizeof(kAnnouncePacket));
 
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice"));
 
-  test_service_discovery_client()->SimulateReceive(
-      kGoodbyePacket, sizeof(kGoodbyePacket));
+  test_service_discovery_client()->SimulateReceive(kGoodbyePacket,
+                                                   sizeof(kGoodbyePacket));
 
   RunFor(base::TimeDelta::FromMilliseconds(1100));
 
@@ -478,8 +465,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDevicesURL));
   condition_devices_listed().Wait();
 
-  test_service_discovery_client()->SimulateReceive(
-      kAnnouncePacket, sizeof(kAnnouncePacket));
+  test_service_discovery_client()->SimulateReceive(kAnnouncePacket,
+                                                   sizeof(kAnnouncePacket));
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
index d84c91a..5e5186e 100644
--- a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
@@ -324,7 +324,7 @@
 }
 
 base::Value GetJsonAsValue(base::StringPiece json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   return base::Value::FromUniquePtrValue(std::move(value));
 }
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
index c89f4a7..66fd0c20 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
@@ -227,7 +227,7 @@
     return false;
   }
   std::unique_ptr<base::Value> ticket_value =
-      base::JSONReader::Read(*ticket_opt);
+      base::JSONReader::ReadDeprecated(*ticket_opt);
   if (!ticket_value)
     return false;
 
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index 458c086..cb7e026 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -217,8 +217,11 @@
   if (!web_ui())
     return;
 
-  // Note that if the user left the sync page by closing the tab, refresh,
-  // or via the back navigation, it would first go through OnDidClosePage().
+  // If unified consent is enabled and the user left the sync page by closing
+  // the tab, refresh, or via the back navigation, the sync setup needs to be
+  // closed. If this was the first time setup, sync will be cancelled.
+  // Note, if unified consent is disabled, it will first go through
+  // |OnDidClosePage()|.
   CloseSyncSetup();
 }
 
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 8d0a6d5..03cadc4d 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -441,17 +441,19 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   // Site Details Page does not display the number of cookies for the origin.
   const CookieTreeNode* root = cookies_tree_model_->GetRoot();
+  std::string usage_string = "";
   for (int i = 0; i < root->child_count(); ++i) {
     const CookieTreeNode* site = root->GetChild(i);
     std::string title = base::UTF16ToUTF8(site->GetTitle());
-    if (title == usage_host_) {
-      CallJavascriptFunction(
-          "settings.WebsiteUsagePrivateApi.returnUsageTotal",
-          base::Value(usage_host_),
-          base::Value(ui::FormatBytes(site->InclusiveSize())));
-      return;
-    }
+    if (title != usage_host_)
+      continue;
+    int64_t size = site->InclusiveSize();
+    if (size != 0)
+      usage_string = base::UTF16ToUTF8(ui::FormatBytes(size));
+    break;
   }
+  CallJavascriptFunction("settings.WebsiteUsagePrivateApi.returnUsageTotal",
+                         base::Value(usage_host_), base::Value(usage_string));
 }
 
 #if defined(OS_CHROMEOS)
@@ -554,7 +556,6 @@
   usage_host_ = host;
 
   update_site_details_ = true;
-
   if (cookies_tree_model_ && !send_sites_list_) {
     cookies_tree_model_->RemoveCookiesTreeObserver(this);
     cookies_tree_model_.reset();
@@ -567,7 +568,6 @@
   CHECK_EQ(1U, args->GetSize());
   std::string origin;
   CHECK(args->GetString(0, &origin));
-
   GURL url(origin);
   if (!url.is_valid())
     return;
@@ -650,7 +650,6 @@
 
   all_sites_map_.clear();
   origin_permission_set_.clear();
-
   // Convert |types| to a list of ContentSettingsTypes.
   std::vector<ContentSettingsType> content_types;
   for (size_t i = 0; i < types->GetSize(); ++i) {
diff --git a/chrome/browser/usb/usb_chooser_context_unittest.cc b/chrome/browser/usb/usb_chooser_context_unittest.cc
index 8155ca9..2a53f53 100644
--- a/chrome/browser/usb/usb_chooser_context_unittest.cc
+++ b/chrome/browser/usb/usb_chooser_context_unittest.cc
@@ -625,7 +625,7 @@
 TEST_F(UsbChooserContextTest, GetGrantedObjectsWithOnlyPolicyAllowedDevices) {
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   auto objects = store->GetGrantedObjects(kVendorOrigin, kVendorOrigin);
   ASSERT_EQ(objects.size(), 1u);
@@ -642,7 +642,7 @@
 TEST_F(UsbChooserContextTest,
        GetGrantedObjectsWithUserAndPolicyAllowedDevices) {
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   UsbDeviceInfoPtr persistent_device_info =
       device_manager_.CreateAndAddDevice(1000, 1, "Google", "Gizmo", "123ABC");
@@ -693,7 +693,7 @@
 TEST_F(UsbChooserContextTest,
        GetGrantedObjectsWithUserGrantedDeviceAllowedBySpecificDevicePolicy) {
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   UsbDeviceInfoPtr persistent_device_info = device_manager_.CreateAndAddDevice(
       6353, 5678, "Google", "Gizmo", "123ABC");
@@ -726,7 +726,7 @@
 
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   store->GrantDevicePermission(kVendorOrigin, kVendorOrigin,
                                *persistent_device_info);
@@ -752,7 +752,7 @@
 
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   store->GrantDevicePermission(kAnyDeviceOrigin, kAnyDeviceOrigin,
                                *persistent_device_info);
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper_base.h b/chrome/browser/web_applications/components/web_app_tab_helper_base.h
index b7df6d8..ce8ad91 100644
--- a/chrome/browser/web_applications/components/web_app_tab_helper_base.h
+++ b/chrome/browser/web_applications/components/web_app_tab_helper_base.h
@@ -69,8 +69,7 @@
   virtual WebAppTabHelperBase* CloneForWebContents(
       content::WebContents* web_contents) const = 0;
 
-  // Gets AppId from derived platform-specific TabHelper and updates
-  // app_id_ with it.
+  // Gets AppId of app whose scope includes |url|.
   virtual AppId GetAppId(const GURL& url) = 0;
 
   // Returns whether the associated web contents belongs to an app window.
diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc
index a4195079..bffa212 100644
--- a/chrome/renderer/net/net_error_helper_core_unittest.cc
+++ b/chrome/renderer/net/net_error_helper_core_unittest.cc
@@ -428,7 +428,7 @@
 
     base::JSONReader reader;
     std::unique_ptr<base::Value> parsed_body(
-        reader.Read(navigation_correction_request_body));
+        reader.ReadDeprecated(navigation_correction_request_body));
     ASSERT_TRUE(parsed_body);
     base::DictionaryValue* dict = NULL;
     ASSERT_TRUE(parsed_body->GetAsDictionary(&dict));
@@ -493,7 +493,7 @@
 
     base::JSONReader reader;
     std::unique_ptr<base::Value> parsed_body(
-        reader.Read(tracking_request_body));
+        reader.ReadDeprecated(tracking_request_body));
     ASSERT_TRUE(parsed_body);
     base::DictionaryValue* dict = NULL;
     ASSERT_TRUE(parsed_body->GetAsDictionary(&dict));
diff --git a/chrome/service/cloud_print/printer_job_queue_handler_unittest.cc b/chrome/service/cloud_print/printer_job_queue_handler_unittest.cc
index fad27e15..920d2d89 100644
--- a/chrome/service/cloud_print/printer_job_queue_handler_unittest.cc
+++ b/chrome/service/cloud_print/printer_job_queue_handler_unittest.cc
@@ -70,7 +70,8 @@
  protected:
   void SetUp() override {
     base::JSONReader json_reader;
-    data_ = base::DictionaryValue::From(json_reader.Read(kJobListResponse));
+    data_ = base::DictionaryValue::From(
+        json_reader.ReadDeprecated(kJobListResponse));
   }
 
   const base::DictionaryValue& GetDictionary() const { return *data_; }
diff --git a/chrome/services/util_win/public/mojom/util_win.mojom b/chrome/services/util_win/public/mojom/util_win.mojom
index cb990d58..44bb121 100644
--- a/chrome/services/util_win/public/mojom/util_win.mojom
+++ b/chrome/services/util_win/public/mojom/util_win.mojom
@@ -61,8 +61,8 @@
   // Path to the file containing the certificate. Empty if |certificate_type| is
   // kNoCertificate.
   mojo_base.mojom.FilePath certificate_path;
-  // The "Subject" name of the certificate. This is the signer (ie,
-  // "Google Inc." or "Microsoft Inc.").
+  // The "Subject" name of the certificate. This is the signer (e.g.,
+  // "Google LLC" or "Microsoft Corporation").
   mojo_base.mojom.String16 certificate_subject;
 };
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c31751e..edf3124 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2789,6 +2789,7 @@
     "../browser/prerender/prerender_history_unittest.cc",
     "../browser/prerender/prerender_unittest.cc",
     "../browser/prerender/prerender_util_unittest.cc",
+    "../browser/previews/previews_content_util_unittest.cc",
     "../browser/previews/previews_infobar_delegate_unittest.cc",
     "../browser/previews/previews_lite_page_decider_unittest.cc",
     "../browser/previews/previews_lite_page_infobar_delegate_unittest.cc",
diff --git a/chrome/test/chromedriver/chrome/mobile_device.cc b/chrome/test/chromedriver/chrome/mobile_device.cc
index b952ab2..4305360 100644
--- a/chrome/test/chromedriver/chrome/mobile_device.cc
+++ b/chrome/test/chromedriver/chrome/mobile_device.cc
@@ -20,7 +20,7 @@
                         std::unique_ptr<MobileDevice>* mobile_device) {
   base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
   std::unique_ptr<base::Value> devices_value =
-      json_reader.ReadToValue(kMobileDevices);
+      json_reader.ReadToValueDeprecated(kMobileDevices);
   if (!devices_value.get())
     return Status(kUnknownError,
                   "could not parse mobile device list because " +
diff --git a/chrome/test/chromedriver/chrome/network_conditions.cc b/chrome/test/chromedriver/chrome/network_conditions.cc
index 62270bf3..a5dcd17 100644
--- a/chrome/test/chromedriver/chrome/network_conditions.cc
+++ b/chrome/test/chromedriver/chrome/network_conditions.cc
@@ -25,7 +25,7 @@
                          NetworkConditions* network_conditions) {
   base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
   std::unique_ptr<base::Value> networks_value =
-      json_reader.ReadToValue(kNetworks);
+      json_reader.ReadToValueDeprecated(kNetworks);
   if (!networks_value)
     return Status(kUnknownError,
                   "could not parse network list because " +
diff --git a/chrome/test/data/media/picture-in-picture/icon.png b/chrome/test/data/media/picture-in-picture/icon.png
deleted file mode 100644
index f8c474b..0000000
--- a/chrome/test/data/media/picture-in-picture/icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/window-size.html b/chrome/test/data/media/picture-in-picture/window-size.html
index d0a0ef4..9d52e68 100644
--- a/chrome/test/data/media/picture-in-picture/window-size.html
+++ b/chrome/test/data/media/picture-in-picture/window-size.html
@@ -49,10 +49,6 @@
         document.title = 'left';
       }, { once: true });
 
-      video.addEventListener('pictureinpicturecontrolclick', function(event) {
-        document.title = event.id;
-      }, { once: true });
-
       window.domAutomationController.send(true);
     })
     .catch(e => {
@@ -60,27 +56,6 @@
     });
   }
 
-  function setControls(ids) {
-    try{
-      var controls = [];
-      Array.from(ids).forEach(id => {
-        controls.push({
-          id: id,
-          label: "label_" + id,
-          icons: [{
-            src: "icon.png",
-            sizes: "144x144",
-            type: "image/png",
-          }],
-        });
-      });
-      video.setPictureInPictureControls(controls);
-      return true;
-    } catch(error) {
-      return false;
-    }
-  }
-
   function secondPictureInPicture() {
     secondVideo.requestPictureInPicture();
   }
diff --git a/chrome/test/data/pdf/metrics_test.js b/chrome/test/data/pdf/metrics_test.js
index 19ecb51..d90da0d 100644
--- a/chrome/test/data/pdf/metrics_test.js
+++ b/chrome/test/data/pdf/metrics_test.js
@@ -16,98 +16,104 @@
       chrome.test.assertEq('test_histogram_log', metric.type);
       chrome.test.assertEq(1, metric.min);
       chrome.test.assertEq(
-          window.PDFMetrics.UserAction.NUMBER_OF_ACTIONS, metric.max);
+          PDFMetrics.UserAction.NUMBER_OF_ACTIONS, metric.max);
       chrome.test.assertEq(
-          window.PDFMetrics.UserAction.NUMBER_OF_ACTIONS + 1, metric.buckets);
+          PDFMetrics.UserAction.NUMBER_OF_ACTIONS + 1, metric.buckets);
       this.actionCounter[value] = (this.actionCounter[value] + 1) || 1;
     }
   };
 
   return [
     function testMetricsDocumentOpened() {
+      PDFMetrics.resetForTesting();
+
       chrome.metricsPrivate = new MockMetricsPrivate();
-      let metrics = new PDFMetricsImpl();
-      metrics.onDocumentOpened();
+
+      PDFMetrics.record(PDFMetrics.UserAction.DOCUMENT_OPENED);
 
       chrome.test.assertEq(
-          {[window.PDFMetrics.UserAction.DOCUMENT_OPENED]: 1},
+          {[PDFMetrics.UserAction.DOCUMENT_OPENED]: 1},
           chrome.metricsPrivate.actionCounter);
       chrome.test.succeed();
     },
 
     function testMetricsRotation() {
+      PDFMetrics.resetForTesting();
+
       chrome.metricsPrivate = new MockMetricsPrivate();
-      let metrics = new PDFMetricsImpl();
-      metrics.onDocumentOpened();
+      PDFMetrics.record(PDFMetrics.UserAction.DOCUMENT_OPENED);
       for (var i = 0; i < 4; i++)
-        metrics.onRotation();
+        PDFMetrics.record(PDFMetrics.UserAction.ROTATE);
 
       chrome.test.assertEq(
           {
-            [window.PDFMetrics.UserAction.DOCUMENT_OPENED]: 1,
-            [window.PDFMetrics.UserAction.ROTATE_FIRST]: 1,
-            [window.PDFMetrics.UserAction.ROTATE]: 4
+            [PDFMetrics.UserAction.DOCUMENT_OPENED]: 1,
+            [PDFMetrics.UserAction.ROTATE_FIRST]: 1,
+            [PDFMetrics.UserAction.ROTATE]: 4
           },
           chrome.metricsPrivate.actionCounter);
       chrome.test.succeed();
     },
 
     function testMetricsFitTo() {
+      PDFMetrics.resetForTesting();
+
       chrome.metricsPrivate = new MockMetricsPrivate();
-      let metrics = new PDFMetricsImpl();
-      metrics.onDocumentOpened();
-      metrics.onFitTo(FittingType.FIT_TO_HEIGHT);
-      metrics.onFitTo(FittingType.FIT_TO_PAGE);
-      metrics.onFitTo(FittingType.FIT_TO_WIDTH);
-      metrics.onFitTo(FittingType.FIT_TO_PAGE);
-      metrics.onFitTo(FittingType.FIT_TO_WIDTH);
-      metrics.onFitTo(FittingType.FIT_TO_PAGE);
+      PDFMetrics.record(PDFMetrics.UserAction.DOCUMENT_OPENED);
+      PDFMetrics.recordFitTo(FittingType.FIT_TO_HEIGHT);
+      PDFMetrics.recordFitTo(FittingType.FIT_TO_PAGE);
+      PDFMetrics.recordFitTo(FittingType.FIT_TO_WIDTH);
+      PDFMetrics.recordFitTo(FittingType.FIT_TO_PAGE);
+      PDFMetrics.recordFitTo(FittingType.FIT_TO_WIDTH);
+      PDFMetrics.recordFitTo(FittingType.FIT_TO_PAGE);
 
       chrome.test.assertEq(
           {
-            [window.PDFMetrics.UserAction.DOCUMENT_OPENED]: 1,
-            [window.PDFMetrics.UserAction.FIT_TO_PAGE_FIRST]: 1,
-            [window.PDFMetrics.UserAction.FIT_TO_PAGE]: 3,
-            [window.PDFMetrics.UserAction.FIT_TO_WIDTH_FIRST]: 1,
-            [window.PDFMetrics.UserAction.FIT_TO_WIDTH]: 2
+            [PDFMetrics.UserAction.DOCUMENT_OPENED]: 1,
+            [PDFMetrics.UserAction.FIT_TO_PAGE_FIRST]: 1,
+            [PDFMetrics.UserAction.FIT_TO_PAGE]: 3,
+            [PDFMetrics.UserAction.FIT_TO_WIDTH_FIRST]: 1,
+            [PDFMetrics.UserAction.FIT_TO_WIDTH]: 2
           },
           chrome.metricsPrivate.actionCounter);
       chrome.test.succeed();
     },
 
     function testMetricsBookmarks() {
+      PDFMetrics.resetForTesting();
+
       chrome.metricsPrivate = new MockMetricsPrivate();
-      let metrics = new PDFMetricsImpl();
-      metrics.onDocumentOpened();
+      PDFMetrics.record(PDFMetrics.UserAction.DOCUMENT_OPENED);
 
-      metrics.onOpenBookmarksPanel();
-      metrics.onFollowBookmark();
-      metrics.onFollowBookmark();
+      PDFMetrics.record(PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL);
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
 
-      metrics.onOpenBookmarksPanel();
-      metrics.onFollowBookmark();
-      metrics.onFollowBookmark();
-      metrics.onFollowBookmark();
+      PDFMetrics.record(PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL);
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
 
       chrome.test.assertEq(
           {
-            [window.PDFMetrics.UserAction.DOCUMENT_OPENED]: 1,
-            [window.PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL_FIRST]: 1,
-            [window.PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL]: 2,
-            [window.PDFMetrics.UserAction.FOLLOW_BOOKMARK_FIRST]: 1,
-            [window.PDFMetrics.UserAction.FOLLOW_BOOKMARK]: 5
+            [PDFMetrics.UserAction.DOCUMENT_OPENED]: 1,
+            [PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL_FIRST]: 1,
+            [PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL]: 2,
+            [PDFMetrics.UserAction.FOLLOW_BOOKMARK_FIRST]: 1,
+            [PDFMetrics.UserAction.FOLLOW_BOOKMARK]: 5
           },
           chrome.metricsPrivate.actionCounter);
       chrome.test.succeed();
     },
 
     function testMetricsPageSelector() {
-      chrome.metricsPrivate = new MockMetricsPrivate();
-      let metrics = new PDFMetricsImpl();
-      metrics.onDocumentOpened();
+      PDFMetrics.resetForTesting();
 
-      metrics.onPageSelectorNavigation();
-      metrics.onPageSelectorNavigation();
+      chrome.metricsPrivate = new MockMetricsPrivate();
+      PDFMetrics.record(PDFMetrics.UserAction.DOCUMENT_OPENED);
+
+      PDFMetrics.record(PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE);
+      PDFMetrics.record(PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE);
 
       chrome.test.assertEq(
           {
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 2a08f1e..1d8478a 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -4211,13 +4211,13 @@
     "pref_mappings": [{ "pref": "certificate_management_allowed" }]
   },
 
-  "DeviceRebootAfterUserSignout": {
+  "DeviceRebootOnUserSignout": {
     "os": ["chromeos"],
     "test_policy": {
-      "DeviceRebootAfterUserSignout": 0
+      "DeviceRebootOnUserSignout": 0
     },
     "pref_mappings": [
-      { "pref": "cros.device.reboot_after_user_signout"}
+      { "pref": "cros.device.reboot_on_user_signout"}
     ]
   },
 
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_test.js b/chrome/test/data/webui/print_preview/destination_dialog_test.js
index 618f99b..d6ea030 100644
--- a/chrome/test/data/webui/print_preview/destination_dialog_test.js
+++ b/chrome/test/data/webui/print_preview/destination_dialog_test.js
@@ -235,6 +235,7 @@
 
       // Check that both cloud print promo and dropdown are hidden when cloud
       // print is disabled.
+      dialog.cloudPrintState = print_preview.CloudPrintState.DISABLED;
       assertTrue(dialog.$.cloudprintPromo.hidden);
       assertTrue(dialog.$$('.user-info').hidden);
       const userSelect = dialog.$$('.md-select');
diff --git a/chrome/test/data/webui/print_preview/destination_select_test.js b/chrome/test/data/webui/print_preview/destination_select_test.js
index 54297264..68b91f5e 100644
--- a/chrome/test/data/webui/print_preview/destination_select_test.js
+++ b/chrome/test/data/webui/print_preview/destination_select_test.js
@@ -307,7 +307,7 @@
                 page.destinationStore_),
           ])
           .then(function() {
-            assertEquals(undefined, page.destination_);
+            assertEquals(null, page.destination_);
             const destinationSettings =
                 page.$$('print-preview-destination-settings');
             assertTrue(destinationSettings.$$('.throbber-container').hidden);
diff --git a/chrome/test/data/webui/print_preview/destination_settings_test.js b/chrome/test/data/webui/print_preview/destination_settings_test.js
index 496461f..033cfa71 100644
--- a/chrome/test/data/webui/print_preview/destination_settings_test.js
+++ b/chrome/test/data/webui/print_preview/destination_settings_test.js
@@ -60,6 +60,9 @@
       destinationSettings.destinationStore = null;
       destinationSettings.recentDestinations = [];
       destinationSettings.state = print_preview_new.State.NOT_READY;
+      destinationSettings.cloudPrintState =
+          print_preview.CloudPrintState.DISABLED;
+      destinationSettings.noDestinationsFound = false;
       // Disabled is true when state is NOT_READY.
       destinationSettings.disabled = true;
       document.body.appendChild(destinationSettings);
@@ -81,11 +84,12 @@
     // the state.
     test(assert(TestNames.ChangeDropdownState), function() {
       const dropdown = destinationSettings.$.destinationSelect;
-      // Initial state: No destination store, dropdown should be disabled.
-      assertTrue(dropdown.disabled);
+      // Initial state: No destination store means that there is no destination
+      // yet, so the dropdown is hidden.
+      assertTrue(dropdown.hidden);
 
-      // Set up the destination store, but no destination yet. Dropdown is
-      // disabled.
+      // Set up the destination store, but no destination yet. Dropdown is still
+      // hidden.
       const destinationStore =
           print_preview_test_utils.createDestinationStore();
       destinationStore.init(
@@ -94,17 +98,24 @@
           [] /* recentDestinations */);
       destinationSettings.destinationStore = destinationStore;
       destinationSettings.state = print_preview_new.State.NOT_READY;
-      assertTrue(dropdown.disabled);
+      assertTrue(dropdown.hidden);
 
-      // Simulate loading a destination and setting state to ready. The dropdown
-      // is enabled.
+      // Simulate loading a recent destination.
       destinationSettings.destination = new print_preview.Destination(
           'FooDevice', print_preview.DestinationType.LOCAL, getLocalOrigin(),
           'FooName', print_preview.DestinationConnectionStatus.ONLINE);
       destinationSettings.recentDestinations = [
         print_preview.makeRecentDestination(destinationSettings.destination),
       ];
+      destinationSettings.cloudPrintState =
+          print_preview.CloudPrintState.NOT_SIGNED_IN;
       destinationSettings.state = print_preview_new.State.READY;
+
+      // Dropdown is visible but disabled due to NOT_READY state.
+      assertTrue(dropdown.disabled);
+      assertFalse(dropdown.hidden);
+
+      // Enable controls.
       destinationSettings.disabled = false;
       return waitForRender(dropdown).then(() => {
         assertFalse(dropdown.disabled);
diff --git a/chrome/test/data/webui/print_preview/print_preview_test_utils.js b/chrome/test/data/webui/print_preview/print_preview_test_utils.js
index 94e149dc..1ecc0d7 100644
--- a/chrome/test/data/webui/print_preview/print_preview_test_utils.js
+++ b/chrome/test/data/webui/print_preview/print_preview_test_utils.js
@@ -162,6 +162,7 @@
       certificateStatus: invalid ?
           print_preview.DestinationCertificateStatus.NO :
           print_preview.DestinationCertificateStatus.UNKNOWN,
+      account: 'foo@chromium.org',
     };
     const dest = new print_preview.Destination(
         id, print_preview.DestinationType.GOOGLE,
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js
index a06980a8..ec15a0c 100644
--- a/chrome/test/data/webui/settings/site_details_tests.js
+++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -103,6 +103,9 @@
     const siteDetailsElement = document.createElement('site-details');
     document.body.appendChild(siteDetailsElement);
     siteDetailsElement.origin = origin;
+    settings.navigateTo(
+        settings.routes.SITE_SETTINGS_SITE_DETAILS,
+        new URLSearchParams('site=' + origin));
     return siteDetailsElement;
   }
 
@@ -231,7 +234,7 @@
     Polymer.dom.flush();
 
     // Call onOriginChanged_() manually to simulate a new navigation.
-    testElement.onOriginChanged_(testElement.site);
+    testElement.currentRouteChanged(settings.Route);
     return browserProxy.whenCalled('getOriginPermissions').then(() => {
       // Ensure the mock's methods were called and check usage was cleared on
       // clicking the trash button.
@@ -426,14 +429,12 @@
     browserProxy.setIsOriginValid(false);
 
     settings.navigateTo(settings.routes.SITE_SETTINGS);
-    settings.navigateTo(settings.routes.SITE_SETTINGS_SITE_DETAILS);
-    assertEquals(
-        settings.routes.SITE_SETTINGS_SITE_DETAILS.path,
-        settings.getCurrentRoute().path);
 
     loadTimeData.overrideValues({enableSiteSettings: false});
     testElement = createSiteDetails(invalid_url);
-
+    assertEquals(
+        settings.routes.SITE_SETTINGS_SITE_DETAILS.path,
+        settings.getCurrentRoute().path);
     return browserProxy.whenCalled('isOriginValid')
         .then((args) => {
           assertEquals(invalid_url, args);
diff --git a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
index 1137950..bf2d1f17 100644
--- a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
+++ b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
@@ -20,7 +20,7 @@
   page_set = media_router_perf_pages.MediaRouterDialogPageSet
 
   def SetExtraBrowserOptions(self, options):
-    options.clear_sytem_cache_for_browser_and_profile_on_start = True
+    options.flush_os_page_caches_on_start = True
     # This flag is required to enable the communication between the page and
     # the test extension.
     options.disable_background_networking = False
@@ -101,7 +101,7 @@
   page_set = media_router_perf_pages.CPUMemoryPageSet
 
   def SetExtraBrowserOptions(self, options):
-    options.clear_sytem_cache_for_browser_and_profile_on_start = True
+    options.flush_os_page_caches_on_start = True
     # This flag is required to enable the communication between the page and
     # the test extension.
     options.disable_background_networking = False
diff --git a/chrome/test/nacl/nacl_browsertest_util.cc b/chrome/test/nacl/nacl_browsertest_util.cc
index 59b86c7..d5ca34d 100644
--- a/chrome/test/nacl/nacl_browsertest_util.cc
+++ b/chrome/test/nacl/nacl_browsertest_util.cc
@@ -29,7 +29,7 @@
   // Automation messages are stringified before they are sent because the
   // automation channel cannot handle arbitrary objects.  This means we
   // need to decode the json twice to get the original message.
-  std::unique_ptr<base::Value> value = reader.ReadToValue(json);
+  std::unique_ptr<base::Value> value = reader.ReadToValueDeprecated(json);
   if (!value.get())
     return InternalError("Could parse automation JSON: " + json +
                          " because " + reader.GetErrorMessage());
@@ -38,7 +38,7 @@
   if (!value->GetAsString(&temp))
     return InternalError("Message was not a string: " + json);
 
-  value = reader.ReadToValue(temp);
+  value = reader.ReadToValueDeprecated(temp);
   if (!value.get())
     return InternalError("Could not parse message JSON: " + temp +
                          " because " + reader.GetErrorMessage());
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 74157733..a6b5729 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -32,6 +32,7 @@
 #include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
@@ -359,7 +360,7 @@
 
 IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, TCPSocketPrivateCrash_Resolve) {
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      content::IsNetworkServiceRunningInProcess())
+      content::IsInProcessNetworkService())
     return;
 
   network::mojom::NetworkServiceTestPtr network_service_test;
@@ -1260,7 +1261,7 @@
 
 IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, HostResolverCrash_Basic) {
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      content::IsNetworkServiceRunningInProcess())
+      content::IsInProcessNetworkService())
     return;
 
   network::mojom::NetworkServiceTestPtr network_service_test;
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc
index da8394a7..a1f563c1 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.cc
+++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -748,7 +748,7 @@
   // Read in the JSON
   base::JSONReader reader;
   std::unique_ptr<base::Value> value =
-      reader.Read(result, base::JSON_ALLOW_TRAILING_COMMAS);
+      reader.ReadDeprecated(result, base::JSON_ALLOW_TRAILING_COMMAS);
 
   // Convert to dictionary
   base::DictionaryValue* dict_value = NULL;
diff --git a/chromecast/base/metrics/cast_metrics_helper_unittest.cc b/chromecast/base/metrics/cast_metrics_helper_unittest.cc
index 2bf53aac..8e25a7e35 100644
--- a/chromecast/base/metrics/cast_metrics_helper_unittest.cc
+++ b/chromecast/base/metrics/cast_metrics_helper_unittest.cc
@@ -36,19 +36,19 @@
 constexpr base::TimeDelta kAppLoadTimeout = base::TimeDelta::FromMinutes(5);
 
 MATCHER_P2(HasDouble, key, value, "") {
-  auto v = base::JSONReader::Read(arg);
+  auto v = base::JSONReader::ReadDeprecated(arg);
   return v && v->FindKey(key) && v->FindKey(key)->is_double() &&
          v->FindKey(key)->GetDouble() == value;
 }
 
 MATCHER_P2(HasInt, key, value, "") {
-  auto v = base::JSONReader::Read(arg);
+  auto v = base::JSONReader::ReadDeprecated(arg);
   return v && v->FindKey(key) && v->FindKey(key)->is_int() &&
          v->FindKey(key)->GetInt() == value;
 }
 
 MATCHER_P2(HasString, key, value, "") {
-  auto v = base::JSONReader::Read(arg);
+  auto v = base::JSONReader::ReadDeprecated(arg);
   return v && v->FindKey(key) && v->FindKey(key)->is_string() &&
          v->FindKey(key)->GetString() == value;
 }
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java
index df679a1e..400b847d 100644
--- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java
+++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java
@@ -160,7 +160,7 @@
         mShadowActivity = Shadows.shadowOf(mActivity);
         mActivityLifecycle.create();
 
-        Assert.assertTrue(Shadows.shadowOf(mShadowActivity.getWindow())
+        Assert.assertTrue(Shadows.shadowOf(mActivity.getWindow())
                                   .getFlag(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON));
     }
 
@@ -174,14 +174,14 @@
         mShadowActivity = Shadows.shadowOf(mActivity);
         mActivityLifecycle.create();
 
-        Assert.assertFalse(Shadows.shadowOf(mShadowActivity.getWindow())
+        Assert.assertFalse(Shadows.shadowOf(mActivity.getWindow())
                                    .getFlag(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON));
     }
 
     @Test
     public void testSetsKeepScreenOnFlag() {
         mActivityLifecycle.create();
-        Assert.assertTrue(Shadows.shadowOf(mShadowActivity.getWindow())
+        Assert.assertTrue(Shadows.shadowOf(mActivity.getWindow())
                                   .getFlag(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
     }
 
@@ -220,9 +220,9 @@
     }
 
     @Test
-    public void testBackButtonFinishes() {
+    public void testBackButtonDoesNotCauseFinish() {
         mActivityLifecycle.create().start().resume();
         mActivity.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
-        Assert.assertTrue(mShadowActivity.isFinishing());
+        Assert.assertFalse(mShadowActivity.isFinishing());
     }
 }
diff --git a/chromecast/media/cma/backend/cast_audio_json.cc b/chromecast/media/cma/backend/cast_audio_json.cc
index 588c86d5..47d69d2 100644
--- a/chromecast/media/cma/backend/cast_audio_json.cc
+++ b/chromecast/media/cma/backend/cast_audio_json.cc
@@ -71,7 +71,7 @@
 std::unique_ptr<base::Value> CastAudioJsonProviderImpl::GetCastAudioConfig() {
   std::string contents;
   base::ReadFileToString(CastAudioJson::GetFilePath(), &contents);
-  return base::JSONReader::Read(contents);
+  return base::JSONReader::ReadDeprecated(contents);
 }
 
 void CastAudioJsonProviderImpl::SetTuningChangedCallback(
@@ -98,7 +98,8 @@
 
   std::string contents;
   base::ReadFileToString(path, &contents);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(contents);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(contents);
   if (value) {
     callback_.Run(std::move(value));
     return;
diff --git a/chromecast/media/cma/backend/volume_map_unittest.cc b/chromecast/media/cma/backend/volume_map_unittest.cc
index 269dd35b..b5c042da5 100644
--- a/chromecast/media/cma/backend/volume_map_unittest.cc
+++ b/chromecast/media/cma/backend/volume_map_unittest.cc
@@ -33,12 +33,12 @@
 
   void CallTuningChangedCallback(const std::string& new_config) {
     DCHECK(callback_);
-    callback_.Run(base::JSONReader::Read(new_config));
+    callback_.Run(base::JSONReader::ReadDeprecated(new_config));
   }
 
  private:
   std::unique_ptr<base::Value> GetCastAudioConfig() override {
-    return base::JSONReader::Read(file_contents_);
+    return base::JSONReader::ReadDeprecated(file_contents_);
   }
 
   void SetTuningChangedCallback(TuningChangedCallback callback) override {
diff --git a/chromeos/components/proximity_auth/messenger_impl.cc b/chromeos/components/proximity_auth/messenger_impl.cc
index b6e7a7a..e05d1d95 100644
--- a/chromeos/components/proximity_auth/messenger_impl.cc
+++ b/chromeos/components/proximity_auth/messenger_impl.cc
@@ -208,7 +208,8 @@
 
 void MessengerImpl::HandleMessage(const std::string& message) {
   // The decoded message should be a JSON string.
-  std::unique_ptr<base::Value> message_value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> message_value =
+      base::JSONReader::ReadDeprecated(message);
   if (!message_value || !message_value->is_dict()) {
     PA_LOG(ERROR) << "Unable to parse message as JSON:\n" << message;
     return;
diff --git a/chromeos/components/proximity_auth/remote_status_update_unittest.cc b/chromeos/components/proximity_auth/remote_status_update_unittest.cc
index aba21d6..cf74ebc 100644
--- a/chromeos/components/proximity_auth/remote_status_update_unittest.cc
+++ b/chromeos/components/proximity_auth/remote_status_update_unittest.cc
@@ -14,7 +14,7 @@
 // Parses the |json| into a RemoteStatusUpdate instance.
 std::unique_ptr<RemoteStatusUpdate> ParseJson(const std::string& json) {
   std::unique_ptr<base::DictionaryValue> as_dictionary =
-      base::DictionaryValue::From(base::JSONReader::Read(json));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(json));
   return RemoteStatusUpdate::Deserialize(*as_dictionary);
 }
 
diff --git a/chromeos/components/tether/message_wrapper.cc b/chromeos/components/tether/message_wrapper.cc
index 3b7ccf3..570c4b6 100644
--- a/chromeos/components/tether/message_wrapper.cc
+++ b/chromeos/components/tether/message_wrapper.cc
@@ -77,7 +77,8 @@
 // static
 std::unique_ptr<MessageWrapper> MessageWrapper::FromRawMessage(
     const std::string& message) {
-  std::unique_ptr<base::Value> json_value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> json_value =
+      base::JSONReader::ReadDeprecated(message);
   if (!json_value) {
     return nullptr;
   }
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index d328928..28642aa 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -21,10 +21,6 @@
 const base::Feature kCrostiniBackup{"CrostiniBackup",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables or disables Crostini Files.
-const base::Feature kCrostiniFiles{"CrostiniFiles",
-                                   base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables or disables Crostini support for usb mounting.
 const base::Feature kCrostiniUsbSupport{"CrostiniUsbSupport",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
@@ -39,7 +35,7 @@
                                  base::FEATURE_DISABLED_BY_DEFAULT};
 
 // If enabled, DriveFS will be used for Drive sync.
-const base::Feature kDriveFs{"DriveFS", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kDriveFs{"DriveFS", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables or disables web push for background notifications in
 // Android Messages Integration on Chrome OS.
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index cc30749..5955eaf 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -18,7 +18,6 @@
 CHROMEOS_EXPORT extern const base::Feature kAndroidMessagesIntegration;
 CHROMEOS_EXPORT extern const base::Feature kAutoScreenBrightness;
 CHROMEOS_EXPORT extern const base::Feature kCrostiniBackup;
-CHROMEOS_EXPORT extern const base::Feature kCrostiniFiles;
 CHROMEOS_EXPORT extern const base::Feature kCrostiniUsbSupport;
 CHROMEOS_EXPORT extern const base::Feature kCryptAuthV2Enrollment;
 CHROMEOS_EXPORT extern const base::Feature kDiscoverApp;
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index 580afe4..1727d99 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -306,10 +306,6 @@
 // Enables the Cast Receiver.
 const char kEnableCastReceiver[] = "enable-cast-receiver";
 
-// Enables the experimental chromevox developer option.
-const char kEnableChromevoxDeveloperOption[] =
-    "enable-chromevox-developer-option";
-
 // Enables consumer kiosk mode for Chrome OS.
 const char kEnableConsumerKiosk[] = "enable-consumer-kiosk";
 
diff --git a/chromeos/dbus/cryptohome_client.cc b/chromeos/dbus/cryptohome_client.cc
index 333b867..d06792a 100644
--- a/chromeos/dbus/cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome_client.cc
@@ -16,6 +16,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "chromeos/dbus/blocking_method_caller.h"
@@ -44,6 +45,8 @@
 const char kAttestationServerDefault[] = "default";
 const char kAttestationServerTest[] = "test";
 
+constexpr char kCryptohomeClientUmaPrefix[] = "CryptohomeClient.";
+
 static attestation::VerifiedAccessType GetVerifiedAccessType() {
   std::string value =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
@@ -59,6 +62,49 @@
   return attestation::DEFAULT_VA;
 }
 
+void UmaCallbackWraper(const std::string& metric_name,
+                       const base::Time& start_time,
+                       dbus::ObjectProxy::ResponseCallback callback,
+                       dbus::Response* response) {
+  UmaHistogramMediumTimes(metric_name, base::Time::Now() - start_time);
+  std::move(callback).Run(response);
+}
+
+class DbusObjectProxyWithUma {
+ public:
+  DbusObjectProxyWithUma(dbus::ObjectProxy* proxy) : proxy_(proxy) {}
+
+  void CallMethod(dbus::MethodCall* method_call,
+                  int timeout_ms,
+                  dbus::ObjectProxy::ResponseCallback callback) {
+    std::string metric_name =
+        kCryptohomeClientUmaPrefix + method_call->GetMember();
+    base::Time start_time = base::Time::Now();
+
+    proxy_->CallMethod(method_call, timeout_ms,
+                       base::BindOnce(&UmaCallbackWraper, metric_name,
+                                      start_time, std::move(callback)));
+  }
+
+  void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
+    proxy_->WaitForServiceToBeAvailable(std::move(callback));
+  }
+
+  void ConnectToSignal(
+      const std::string& interface_name,
+      const std::string& signal_name,
+      dbus::ObjectProxy::SignalCallback signal_callback,
+      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) {
+    proxy_->ConnectToSignal(interface_name, signal_name,
+                            std::move(signal_callback),
+                            std::move(on_connected_callback));
+  }
+
+ private:
+  dbus::ObjectProxy* proxy_;
+};
+
 // The CryptohomeClient implementation.
 class CryptohomeClientImpl : public CryptohomeClient {
  public:
@@ -190,8 +236,14 @@
     dbus::MessageWriter writer(&method_call);
     writer.AppendString(id.account_id());
 
-    std::unique_ptr<dbus::Response> response =
-        blocking_method_caller_->CallMethodAndBlock(&method_call);
+    base::Time start_time = base::Time::Now();
+
+    std::unique_ptr<dbus::Response> response(
+        blocking_method_caller_->CallMethodAndBlock(&method_call));
+
+    UmaHistogramMediumTimes(
+        kCryptohomeClientUmaPrefix + method_call.GetMember(),
+        base::Time::Now() - start_time);
 
     std::string sanitized_username;
     if (response) {
@@ -298,8 +350,16 @@
   bool CallTpmClearStoredPasswordAndBlock() override {
     dbus::MethodCall method_call(cryptohome::kCryptohomeInterface,
                                  cryptohome::kCryptohomeTpmClearStoredPassword);
+
+    base::Time start_time = base::Time::Now();
+
     std::unique_ptr<dbus::Response> response(
         blocking_method_caller_->CallMethodAndBlock(&method_call));
+
+    UmaHistogramMediumTimes(
+        kCryptohomeClientUmaPrefix + method_call.GetMember(),
+        base::Time::Now() - start_time);
+
     return response.get() != NULL;
   }
 
@@ -344,8 +404,16 @@
                                  cryptohome::kCryptohomeInstallAttributesGet);
     dbus::MessageWriter writer(&method_call);
     writer.AppendString(name);
+
+    base::Time start_time = base::Time::Now();
+
     std::unique_ptr<dbus::Response> response(
         blocking_method_caller_->CallMethodAndBlock(&method_call));
+
+    UmaHistogramMediumTimes(
+        kCryptohomeClientUmaPrefix + method_call.GetMember(),
+        base::Time::Now() - start_time);
+
     if (!response.get())
       return false;
     dbus::MessageReader reader(response.get());
@@ -940,11 +1008,12 @@
 
  protected:
   void Init(dbus::Bus* bus) override {
-    proxy_ = bus->GetObjectProxy(
+    dbus::ObjectProxy* proxy = bus->GetObjectProxy(
         cryptohome::kCryptohomeServiceName,
         dbus::ObjectPath(cryptohome::kCryptohomeServicePath));
+    proxy_ = std::make_unique<DbusObjectProxyWithUma>(proxy);
 
-    blocking_method_caller_.reset(new BlockingMethodCaller(bus, proxy_));
+    blocking_method_caller_.reset(new BlockingMethodCaller(bus, proxy));
 
     proxy_->ConnectToSignal(
         cryptohome::kCryptohomeInterface, cryptohome::kSignalAsyncCallStatus,
@@ -1025,8 +1094,15 @@
   // Calls a method with a bool value reult and block.
   bool CallBoolMethodAndBlock(dbus::MethodCall* method_call,
                               bool* result) {
+    base::Time start_time = base::Time::Now();
+
     std::unique_ptr<dbus::Response> response(
         blocking_method_caller_->CallMethodAndBlock(method_call));
+
+    UmaHistogramMediumTimes(
+        kCryptohomeClientUmaPrefix + method_call->GetMember(),
+        base::Time::Now() - start_time);
+
     if (!response.get())
       return false;
     dbus::MessageReader reader(response.get());
@@ -1260,7 +1336,7 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
-  dbus::ObjectProxy* proxy_ = nullptr;
+  std::unique_ptr<DbusObjectProxyWithUma> proxy_ = nullptr;
   base::ObserverList<Observer>::Unchecked observer_list_;
   std::unique_ptr<BlockingMethodCaller> blocking_method_caller_;
 
diff --git a/chromeos/dbus/debug_daemon_client.cc b/chromeos/dbus/debug_daemon_client.cc
index b27c93c..4410813 100644
--- a/chromeos/dbus/debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon_client.cc
@@ -203,7 +203,7 @@
   void GetPerfOutput(base::TimeDelta duration,
                      const std::vector<std::string>& perf_args,
                      int file_descriptor,
-                     VoidDBusMethodCallback callback) override {
+                     DBusMethodCallback<uint64_t> callback) override {
     DCHECK(file_descriptor);
     dbus::MethodCall method_call(debugd::kDebugdInterface,
                                  debugd::kGetPerfOutputFd);
@@ -214,7 +214,7 @@
 
     debugdaemon_proxy_->CallMethod(
         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::BindOnce(&DebugDaemonClientImpl::OnVoidMethod,
+        base::BindOnce(&DebugDaemonClientImpl::OnUint64Method,
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
@@ -619,6 +619,22 @@
     std::move(callback).Run(response);
   }
 
+  void OnUint64Method(DBusMethodCallback<uint64_t> callback,
+                      dbus::Response* response) {
+    if (!response) {
+      std::move(callback).Run(0);
+      return;
+    }
+
+    dbus::MessageReader reader(response);
+    uint64_t result;
+    if (!reader.PopUint64(&result)) {
+      result = 0;
+    }
+
+    std::move(callback).Run(std::move(result));
+  }
+
   // Called when D-Bus method call which returns a string is completed or on
   // its error.
   void OnStringMethod(DBusMethodCallback<std::string> callback,
diff --git a/chromeos/dbus/debug_daemon_client.h b/chromeos/dbus/debug_daemon_client.h
index 77b259e..33b5ea2 100644
--- a/chromeos/dbus/debug_daemon_client.h
+++ b/chromeos/dbus/debug_daemon_client.h
@@ -79,7 +79,7 @@
   virtual void GetPerfOutput(base::TimeDelta duration,
                              const std::vector<std::string>& perf_args,
                              int file_descriptor,
-                             VoidDBusMethodCallback callback) = 0;
+                             DBusMethodCallback<uint64_t> callback) = 0;
 
   // Callback type for GetScrubbedLogs(), GetAllLogs() or GetUserLogFiles().
   using GetLogsCallback =
diff --git a/chromeos/dbus/fake_debug_daemon_client.cc b/chromeos/dbus/fake_debug_daemon_client.cc
index 25caecd..61395f6 100644
--- a/chromeos/dbus/fake_debug_daemon_client.cc
+++ b/chromeos/dbus/fake_debug_daemon_client.cc
@@ -112,7 +112,7 @@
     base::TimeDelta duration,
     const std::vector<std::string>& perf_args,
     int file_descriptor,
-    VoidDBusMethodCallback error_callback) {}
+    DBusMethodCallback<uint64_t> error_callback) {}
 
 void FakeDebugDaemonClient::GetScrubbedLogs(const GetLogsCallback& callback) {
   std::map<std::string, std::string> sample;
diff --git a/chromeos/dbus/fake_debug_daemon_client.h b/chromeos/dbus/fake_debug_daemon_client.h
index a404fb4e..24879d04 100644
--- a/chromeos/dbus/fake_debug_daemon_client.h
+++ b/chromeos/dbus/fake_debug_daemon_client.h
@@ -52,7 +52,7 @@
   void GetPerfOutput(base::TimeDelta duration,
                      const std::vector<std::string>& perf_args,
                      int file_descriptor,
-                     VoidDBusMethodCallback callback) override;
+                     DBusMethodCallback<uint64_t> callback) override;
   void GetScrubbedLogs(const GetLogsCallback& callback) override;
   void GetScrubbedBigLogs(const GetLogsCallback& callback) override;
   void GetAllLogs(const GetLogsCallback& callback) override;
diff --git a/chromeos/geolocation/simple_geolocation_request.cc b/chromeos/geolocation/simple_geolocation_request.cc
index 79a929b..5e60aaad 100644
--- a/chromeos/geolocation/simple_geolocation_request.cc
+++ b/chromeos/geolocation/simple_geolocation_request.cc
@@ -195,8 +195,8 @@
   // Parse the response, ignoring comments.
   std::string error_msg;
   std::unique_ptr<base::Value> response_value =
-      base::JSONReader::ReadAndReturnError(response_body, base::JSON_PARSE_RFC,
-                                           NULL, &error_msg);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          response_body, base::JSON_PARSE_RFC, NULL, &error_msg);
   if (response_value == NULL) {
     PrintGeolocationError(
         server_url, "JSONReader failed: " + error_msg, position);
diff --git a/chromeos/network/auto_connect_handler_unittest.cc b/chromeos/network/auto_connect_handler_unittest.cc
index 034f6568..4c5f192 100644
--- a/chromeos/network/auto_connect_handler_unittest.cc
+++ b/chromeos/network/auto_connect_handler_unittest.cc
@@ -227,9 +227,9 @@
     if (!network_configs_json.empty()) {
       std::string error;
       std::unique_ptr<base::Value> network_configs_value =
-          base::JSONReader::ReadAndReturnError(network_configs_json,
-                                               base::JSON_ALLOW_TRAILING_COMMAS,
-                                               nullptr, &error);
+          base::JSONReader::ReadAndReturnErrorDeprecated(
+              network_configs_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+              &error);
       ASSERT_TRUE(network_configs_value) << error;
       base::ListValue* network_configs_list = nullptr;
       ASSERT_TRUE(network_configs_value->GetAsList(&network_configs_list));
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc
index 886db73..768cce8a 100644
--- a/chromeos/network/client_cert_resolver.cc
+++ b/chromeos/network/client_cert_resolver.cc
@@ -10,6 +10,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -275,19 +276,20 @@
   return pem_encoded_issuer;
 }
 
-std::vector<CertAndIssuer> CreateSortedCertAndIssuerList(
-    net::ScopedCERTCertificateList certs,
-    base::Time now) {
+void CreateSortedCertAndIssuerList(
+    const NetworkCertLoader::NetworkCertList& network_certs,
+    base::Time now,
+    std::vector<CertAndIssuer>* all_cert_and_issuers,
+    std::vector<CertAndIssuer>* device_wide_cert_and_issuers) {
   // Filter all client certs and determines each certificate's issuer, which is
   // required for the pattern matching.
-  // TODO(crbug.com/781693): Consider moving the filtering of client certs into
-  // NetworkCertLoader. It should not be in ClientCertResolver's responsibility
-  // to decide if a certificate is a valid client certificate or not. Other
-  // consumers of NetworkCertLoader could also use a pre-filtered list (e.g.
-  // NetworkCertMigrator).
-  std::vector<CertAndIssuer> client_certs;
-  for (net::ScopedCERTCertificate& scoped_cert : certs) {
-    CERTCertificate* cert = scoped_cert.get();
+  for (const NetworkCertLoader::NetworkCert& network_cert : network_certs) {
+    // If the caller is interested in device-wide certificates only, skip
+    // user-specific certificates.
+    if (!all_cert_and_issuers && !network_cert.is_device_wide())
+      continue;
+
+    CERTCertificate* cert = network_cert.cert();
     base::Time not_after;
     if (!net::x509_util::GetValidityTimes(cert, nullptr, &not_after) ||
         now > not_after ||
@@ -303,31 +305,42 @@
       continue;
     }
     std::string pem_encoded_issuer = GetPEMEncodedIssuer(cert);
-    client_certs.push_back(CertAndIssuer(std::move(scoped_cert),
-                                         pem_encoded_issuer,
-                                         private_key_nickname.value()));
+    if (all_cert_and_issuers) {
+      all_cert_and_issuers->push_back(
+          CertAndIssuer(net::x509_util::DupCERTCertificate(cert),
+                        pem_encoded_issuer, private_key_nickname.value()));
+    }
+    if (device_wide_cert_and_issuers && network_cert.is_device_wide()) {
+      device_wide_cert_and_issuers->push_back(
+          CertAndIssuer(net::x509_util::DupCERTCertificate(cert),
+                        pem_encoded_issuer, private_key_nickname.value()));
+    }
   }
 
-  std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration);
-  return client_certs;
+  if (all_cert_and_issuers) {
+    std::sort(all_cert_and_issuers->begin(), all_cert_and_issuers->end(),
+              &CompareCertExpiration);
+  }
+  if (device_wide_cert_and_issuers) {
+    std::sort(device_wide_cert_and_issuers->begin(),
+              device_wide_cert_and_issuers->end(), &CompareCertExpiration);
+  }
 }
 
-// Searches for matches between |networks| and |all_certs| (for networks
-// configured in user policy) / |system_token_client_certs| (for networks
-// configured in device policy). Returns the matches that were found. Because
-// this calls NSS functions and is potentially slow, it must be run on a worker
-// thread.
+// Searches for matches between |networks| and |network_certs|. Returns the
+// matches that were found. Because this calls NSS functions and is potentially
+// slow, it must be run on a worker thread.
 std::vector<NetworkAndMatchingCert> FindCertificateMatches(
-    net::ScopedCERTCertificateList all_certs,
-    net::ScopedCERTCertificateList system_token_client_certs,
+    NetworkCertLoader::NetworkCertList network_certs,
     const std::vector<NetworkAndCertConfig>& networks,
     base::Time now) {
   std::vector<NetworkAndMatchingCert> matches;
 
-  std::vector<CertAndIssuer> all_client_certs(
-      CreateSortedCertAndIssuerList(std::move(all_certs), now));
-  std::vector<CertAndIssuer> system_client_certs(
-      CreateSortedCertAndIssuerList(std::move(system_token_client_certs), now));
+  std::vector<CertAndIssuer> all_client_cert_and_issuers;
+  std::vector<CertAndIssuer> device_wide_client_cert_and_issuers;
+  CreateSortedCertAndIssuerList(network_certs, now,
+                                &all_client_cert_and_issuers,
+                                &device_wide_client_cert_and_issuers);
 
   for (const NetworkAndCertConfig& network_and_cert_config : networks) {
     // Use only certs from the system token if the source of the client cert
@@ -335,8 +348,8 @@
     std::vector<CertAndIssuer>* client_certs =
         network_and_cert_config.cert_config.onc_source ==
                 ::onc::ONC_SOURCE_DEVICE_POLICY
-            ? &system_client_certs
-            : &all_client_certs;
+            ? &device_wide_client_cert_and_issuers
+            : &all_client_cert_and_issuers;
     auto cert_it = std::find_if(
         client_certs->begin(), client_certs->end(),
         MatchCertWithCertConfig(network_and_cert_config.cert_config));
@@ -456,25 +469,25 @@
 
   // Prepare and sort the list of known client certs. Use only certs from the
   // system token if the source of the client cert config is device policy.
-  std::vector<CertAndIssuer> client_certs;
+  std::vector<CertAndIssuer> client_cert_and_issuers;
   if (client_cert_config.onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY) {
-    client_certs = CreateSortedCertAndIssuerList(
-        net::x509_util::DupCERTCertificateList(
-            NetworkCertLoader::Get()->system_token_client_certs()),
-        base::Time::Now());
+    CreateSortedCertAndIssuerList(
+        NetworkCertLoader::Get()->client_certs(), base::Time::Now(),
+        nullptr /* all_cert_and_issuers */,
+        &client_cert_and_issuers /* device_wide_cert_and_issuers */);
   } else {
-    client_certs = CreateSortedCertAndIssuerList(
-        net::x509_util::DupCERTCertificateList(
-            NetworkCertLoader::Get()->all_certs()),
-        base::Time::Now());
+    CreateSortedCertAndIssuerList(
+        NetworkCertLoader::Get()->client_certs(), base::Time::Now(),
+        &client_cert_and_issuers /* all_cert_and_issuers */,
+        nullptr /* device_wide_cert_and_issuers */);
   }
 
   // Search for a certificate matching the pattern or reference.
-  std::vector<CertAndIssuer>::iterator cert_it =
-      std::find_if(client_certs.begin(), client_certs.end(),
-                   MatchCertWithCertConfig(client_cert_config));
+  std::vector<CertAndIssuer>::iterator cert_it = std::find_if(
+      client_cert_and_issuers.begin(), client_cert_and_issuers.end(),
+      MatchCertWithCertConfig(client_cert_config));
 
-  if (cert_it == client_certs.end()) {
+  if (cert_it == client_cert_and_issuers.end()) {
     VLOG(1) << "Couldn't find a matching client cert";
     client_cert::SetEmptyShillProperties(client_cert_type, shill_properties);
     return false;
@@ -547,8 +560,7 @@
   }
 }
 
-void ClientCertResolver::OnCertificatesLoaded(
-    const net::ScopedCERTCertificateList& cert_list) {
+void ClientCertResolver::OnCertificatesLoaded() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(2) << "OnCertificatesLoaded.";
   if (!ClientCertificatesLoaded())
@@ -652,10 +664,8 @@
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
       base::BindOnce(&FindCertificateMatches,
-                     net::x509_util::DupCERTCertificateList(
-                         NetworkCertLoader::Get()->all_certs()),
-                     net::x509_util::DupCERTCertificateList(
-                         NetworkCertLoader::Get()->system_token_client_certs()),
+                     NetworkCertLoader::CloneNetworkCertList(
+                         NetworkCertLoader::Get()->client_certs()),
                      networks_to_resolve, Now()),
       base::BindOnce(&ClientCertResolver::ConfigureCertificates,
                      weak_ptr_factory_.GetWeakPtr()));
diff --git a/chromeos/network/client_cert_resolver.h b/chromeos/network/client_cert_resolver.h
index 9b08195a..3988a2a 100644
--- a/chromeos/network/client_cert_resolver.h
+++ b/chromeos/network/client_cert_resolver.h
@@ -95,8 +95,7 @@
   void NetworkConnectionStateChanged(const NetworkState* network) override;
 
   // NetworkCertLoader::Observer overrides
-  void OnCertificatesLoaded(
-      const net::ScopedCERTCertificateList& cert_list) override;
+  void OnCertificatesLoaded() override;
 
   // NetworkPolicyObserver overrides
   void PolicyAppliedToNetwork(const std::string& service_path) override;
diff --git a/chromeos/network/client_cert_resolver_unittest.cc b/chromeos/network/client_cert_resolver_unittest.cc
index 61d30a02..a3f917c2 100644
--- a/chromeos/network/client_cert_resolver_unittest.cc
+++ b/chromeos/network/client_cert_resolver_unittest.cc
@@ -99,11 +99,19 @@
   void SetUp() override {
     ASSERT_TRUE(test_nssdb_.is_open());
     ASSERT_TRUE(test_system_nssdb_.is_open());
-
-    // Use the same DB for public and private slot.
-    test_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
+    // Use the same slot as public and private slot for the user's
+    // NSSCertDatabse for testing.
+    test_nsscertdb_ = std::make_unique<net::NSSCertDatabaseChromeOS>(
         crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())),
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))));
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())));
+    // Create a NSSCertDatabase for the system slot. While NetworkCertLoader
+    // does not care about the public slot in this database, NSSCertDatabase
+    // requires a public slot. Pass the system slot there for testing.
+    test_system_nsscertdb_ = std::make_unique<net::NSSCertDatabaseChromeOS>(
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot())),
+        crypto::ScopedPK11Slot() /* private_slot */);
+    test_system_nsscertdb_->SetSystemSlot(
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot())));
 
     DBusThreadManager::Initialize();
     service_test_ =
@@ -138,6 +146,7 @@
  protected:
   void StartNetworkCertLoader() {
     network_cert_loader_->SetUserNSSDB(test_nsscertdb_.get());
+    network_cert_loader_->SetSystemNSSDB(test_system_nsscertdb_.get());
     if (test_client_cert_.get()) {
       int slot_id = 0;
       const std::string pkcs11_id =
@@ -206,9 +215,6 @@
   }
 
   void SetupTestCertInSystemToken(const std::string& prefix) {
-    test_nsscertdb_->SetSystemSlot(
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot())));
-
     net::ImportClientCertAndKeyFromFile(
         net::GetTestCertsDirectory(), prefix + ".pem", prefix + ".pk8",
         test_system_nssdb_.slot(), &test_client_cert_);
@@ -322,9 +328,9 @@
         })";
     std::string error;
     std::unique_ptr<base::Value> onc_pattern_value =
-        base::JSONReader::ReadAndReturnError(test_onc_pattern,
-                                             base::JSON_ALLOW_TRAILING_COMMAS,
-                                             nullptr, &error);
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            test_onc_pattern, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+            &error);
     ASSERT_TRUE(onc_pattern_value) << error;
 
     base::DictionaryValue* onc_pattern_dict;
@@ -366,7 +372,7 @@
                                base::StringPiece policy_json) {
     std::string error;
     std::unique_ptr<base::Value> policy_value =
-        base::JSONReader::ReadAndReturnError(
+        base::JSONReader::ReadAndReturnErrorDeprecated(
             policy_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
     ASSERT_TRUE(policy_value) << error;
 
@@ -414,6 +420,7 @@
   std::unique_ptr<ClientCertResolver> client_cert_resolver_;
   NetworkCertLoader* network_cert_loader_ = nullptr;
   std::unique_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_;
+  std::unique_ptr<net::NSSCertDatabaseChromeOS> test_system_nsscertdb_;
 
  private:
   // ClientCertResolver::Observer:
@@ -631,7 +638,8 @@
 
   StartNetworkCertLoader();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_EQ(1U, network_cert_loader_->system_token_client_certs().size());
+  ASSERT_EQ(1U, network_cert_loader_->client_certs().size());
+  EXPECT_TRUE(network_cert_loader_->client_certs()[0].is_device_wide());
 
   // Verify that the resolver positively matched the pattern in the policy with
   // the test client cert and configured the network.
@@ -670,7 +678,8 @@
 
   StartNetworkCertLoader();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_EQ(1U, network_cert_loader_->system_token_client_certs().size());
+  ASSERT_EQ(1U, network_cert_loader_->client_certs().size());
+  EXPECT_TRUE(network_cert_loader_->client_certs()[0].is_device_wide());
 
   // Verify that the resolver positively matched the pattern in the policy with
   // the test client cert and configured the network.
@@ -710,7 +719,8 @@
   network_properties_changed_count_ = 0;
   StartNetworkCertLoader();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_EQ(0U, network_cert_loader_->system_token_client_certs().size());
+  ASSERT_EQ(1U, network_cert_loader_->client_certs().size());
+  EXPECT_FALSE(network_cert_loader_->client_certs()[0].is_device_wide());
 
   // Verify that no client certificate was configured.
   std::string pkcs11_id;
@@ -806,7 +816,7 @@
   // Pretend that certificates have changed. One resolving task should still be
   // queued.
   static_cast<NetworkCertLoader::Observer*>(client_cert_resolver_.get())
-      ->OnCertificatesLoaded(NetworkCertLoader::Get()->all_certs());
+      ->OnCertificatesLoaded();
   EXPECT_TRUE(client_cert_resolver_->IsAnyResolveTaskRunning());
 
   scoped_task_environment_.RunUntilIdle();
diff --git a/chromeos/network/network_cert_loader.cc b/chromeos/network/network_cert_loader.cc
index 53088d1..12ad5aca 100644
--- a/chromeos/network/network_cert_loader.cc
+++ b/chromeos/network/network_cert_loader.cc
@@ -5,15 +5,19 @@
 #include "chromeos/network/network_cert_loader.h"
 
 #include <algorithm>
+#include <initializer_list>
 #include <memory>
+#include <set>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/flat_set.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
+#include "chromeos/network/certificate_helper.h"
 #include "crypto/nss_util.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/cert/cert_database.h"
@@ -23,10 +27,73 @@
 
 namespace chromeos {
 
-// Caches certificates from a NSSCertDatabase. Handles reloading of certificates
-// on update notifications and provides status flags (loading / loaded).
-// NetworkCertLoader can use multiple CertCaches to combine certificates from
-// multiple sources.
+namespace {
+
+enum class NetworkCertType {
+  kAuthorityCertificate,
+  kClientCertificate,
+  kOther
+};
+
+NetworkCertType GetNetworkCertType(CERTCertificate* cert) {
+  net::CertType type = certificate::GetCertType(cert);
+  if (type == net::USER_CERT)
+    return NetworkCertType::kClientCertificate;
+  if (type == net::CA_CERT)
+    return NetworkCertType::kAuthorityCertificate;
+  VLOG(2) << "Ignoring cert type: " << type;
+  return NetworkCertType::kOther;
+}
+
+// Returns all authority certificats provided by |policy_certificate_provider|
+// as a list of NetworkCerts.
+NetworkCertLoader::NetworkCertList GetPolicyProvidedAuthorities(
+    const PolicyCertificateProvider* policy_certificate_provider,
+    bool device_wide) {
+  NetworkCertLoader::NetworkCertList result;
+  if (!policy_certificate_provider)
+    return result;
+  for (const auto& certificate :
+       policy_certificate_provider->GetAllAuthorityCertificates()) {
+    net::ScopedCERTCertificate x509_cert =
+        net::x509_util::CreateCERTCertificateFromX509Certificate(
+            certificate.get());
+    if (!x509_cert) {
+      LOG(ERROR) << "Unable to create CERTCertificate";
+      continue;
+    }
+    result.push_back(
+        NetworkCertLoader::NetworkCert(std::move(x509_cert), device_wide));
+  }
+  return result;
+}
+
+// Combines all NetworkCerts from all |network_cert_lists| to a resulting list,
+// avoiding duplicates.
+NetworkCertLoader::NetworkCertList CombineNetworkCertLists(
+    std::initializer_list<const NetworkCertLoader::NetworkCertList*>
+        network_cert_lists) {
+  size_t total_size = 0;
+  for (const NetworkCertLoader::NetworkCertList* list : network_cert_lists)
+    total_size += list->size();
+  NetworkCertLoader::NetworkCertList result;
+  result.reserve(total_size);
+  std::set<const CERTCertificate*> already_added_certs;
+  for (const NetworkCertLoader::NetworkCertList* list : network_cert_lists) {
+    for (const NetworkCertLoader::NetworkCert& network_cert : *list) {
+      if (already_added_certs.insert(network_cert.cert()).second)
+        result.push_back(network_cert.Clone());
+    }
+  }
+  return result;
+}
+
+}  // namespace
+
+// Caches certificates from a single slot of a NSSCertDatabase. Handles
+// reloading of certificates on update notifications and provides status flags
+// (loading / loaded). NetworkCertLoader can use multiple CertCaches to combine
+// certificates from multiple sources.
 class NetworkCertLoader::CertCache : public net::CertDatabase::Observer {
  public:
   explicit CertCache(base::RepeatingClosure certificates_updated_callback)
@@ -37,9 +104,14 @@
     net::CertDatabase::GetInstance()->RemoveObserver(this);
   }
 
-  void SetNSSDB(net::NSSCertDatabase* nss_database) {
+  void SetNSSDBAndSlot(net::NSSCertDatabase* nss_database,
+                       crypto::ScopedPK11Slot slot,
+                       bool is_slot_device_wide) {
     CHECK(!nss_database_);
+    CHECK(slot);
     nss_database_ = nss_database;
+    slot_ = std::move(slot);
+    is_slot_device_wide_ = is_slot_device_wide;
 
     // Start observing cert database for changes.
     // Observing net::CertDatabase is preferred over observing |nss_database_|
@@ -61,17 +133,21 @@
     LoadCertificates();
   }
 
-  const net::ScopedCERTCertificateList& cert_list() const { return cert_list_; }
+  const NetworkCertList& authority_certs() const { return authority_certs_; }
+
+  const NetworkCertList& client_certs() const { return client_certs_; }
+
+  bool is_initialized() const { return nss_database_; }
 
   bool initial_load_running() const {
     return nss_database_ && !initial_load_finished_;
   }
 
-  bool initial_load_finished() const { return initial_load_finished_; }
+  bool certificates_update_running() const {
+    return certificates_update_running_;
+  }
 
-  // Returns true if the underlying NSSCertDatabase has access to the system
-  // slot.
-  bool has_system_certificates() const { return has_system_certificates_; }
+  bool initial_load_finished() const { return initial_load_finished_; }
 
  private:
   // Trigger a certificate load. If a certificate loading task is already in
@@ -80,6 +156,9 @@
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
     VLOG(1) << "LoadCertificates: " << certificates_update_running_;
 
+    if (!nss_database_)
+      return;
+
     if (certificates_update_running_) {
       certificates_update_required_ = true;
       return;
@@ -88,12 +167,10 @@
     certificates_update_running_ = true;
     certificates_update_required_ = false;
 
-    if (nss_database_) {
-      has_system_certificates_ =
-          static_cast<bool>(nss_database_->GetSystemSlot());
-      nss_database_->ListCerts(base::BindOnce(&CertCache::UpdateCertificates,
-                                              weak_factory_.GetWeakPtr()));
-    }
+    nss_database_->ListCertsInSlot(
+        base::BindOnce(&CertCache::UpdateCertificates,
+                       weak_factory_.GetWeakPtr()),
+        slot_.get());
   }
 
   // Called if a certificate load task is finished.
@@ -102,13 +179,23 @@
     DCHECK(certificates_update_running_);
     VLOG(1) << "UpdateCertificates: " << cert_list.size();
 
-    // Ignore any existing certificates.
-    cert_list_ = std::move(cert_list);
+    authority_certs_.clear();
+    client_certs_.clear();
+    for (auto& cert : cert_list) {
+      NetworkCertType type = GetNetworkCertType(cert.get());
+      if (type == NetworkCertType::kAuthorityCertificate) {
+        authority_certs_.push_back(
+            NetworkCert(std::move(cert), is_slot_device_wide_));
+      } else if (type == NetworkCertType::kClientCertificate) {
+        client_certs_.push_back(
+            NetworkCert(std::move(cert), is_slot_device_wide_));
+      }
+    }
 
     initial_load_finished_ = true;
+    certificates_update_running_ = false;
     certificates_updated_callback_.Run();
 
-    certificates_update_running_ = false;
     if (certificates_update_required_)
       LoadCertificates();
   }
@@ -116,8 +203,6 @@
   // To be called when certificates have been updated.
   base::RepeatingClosure certificates_updated_callback_;
 
-  bool has_system_certificates_ = false;
-
   // This is true after certificates have been loaded initially.
   bool initial_load_finished_ = false;
   // This is true if a notification about certificate DB changes arrived while
@@ -130,8 +215,18 @@
   // The NSS certificate database from which the certificates should be loaded.
   net::NSSCertDatabase* nss_database_ = nullptr;
 
-  // Cached Certificates loaded from the database.
-  net::ScopedCERTCertificateList cert_list_;
+  // The slot from which certificates are listed.
+  crypto::ScopedPK11Slot slot_;
+
+  // true if |slot_| is available device-wide, so certificates listed from it
+  // can be used for shared networks.
+  bool is_slot_device_wide_ = false;
+
+  // Authority Certificates loaded from the database.
+  NetworkCertList authority_certs_;
+
+  // Client Certificates loaded from the database.
+  NetworkCertList client_certs_;
 
   THREAD_CHECKER(thread_checker_);
 
@@ -140,47 +235,22 @@
   DISALLOW_COPY_AND_ASSIGN(CertCache);
 };
 
-namespace {
+NetworkCertLoader::NetworkCert::NetworkCert(net::ScopedCERTCertificate cert,
+                                            bool device_wide)
+    : cert_(std::move(cert)), device_wide_(device_wide) {}
 
-// Goes through all certificates in |certs| and copies those certificates
-// which are on the system slot to a new list.
-net::ScopedCERTCertificateList FilterSystemTokenCertificates(
-    net::ScopedCERTCertificateList certs,
-    const net::NSSCertDatabase* cert_db) {
-  VLOG(1) << "FilterSystemTokenCertificates";
+NetworkCertLoader::NetworkCert::NetworkCert(NetworkCert&& other) = default;
 
-  // Only keep certificates which are on the system slot.
-  certs.erase(
-      std::remove_if(certs.begin(), certs.end(),
-                     [cert_db](const net::ScopedCERTCertificate& cert) {
-                       return !cert_db->IsCertificateOnSystemSlot(cert.get());
-                     }),
-      certs.end());
-  return certs;
+NetworkCertLoader::NetworkCert::~NetworkCert() = default;
+
+NetworkCertLoader::NetworkCert& NetworkCertLoader::NetworkCert::operator=(
+    NetworkCert&& other) = default;
+
+NetworkCertLoader::NetworkCert NetworkCertLoader::NetworkCert::Clone() const {
+  return NetworkCert(net::x509_util::DupCERTCertificate(cert_.get()),
+                     device_wide_);
 }
 
-void AddPolicyProvidedAuthorities(
-    const PolicyCertificateProvider* policy_certificate_provider,
-    net::ScopedCERTCertificateList* out_certs) {
-  DCHECK(out_certs);
-  if (!policy_certificate_provider)
-    return;
-  for (const auto& certificate :
-       policy_certificate_provider->GetAllAuthorityCertificates()) {
-    net::ScopedCERTCertificate x509_cert =
-        net::x509_util::CreateCERTCertificateFromX509Certificate(
-            certificate.get());
-    if (!x509_cert) {
-      LOG(ERROR) << "Unable to create CERTCertificate";
-      continue;
-    }
-
-    out_certs->push_back(std::move(x509_cert));
-  }
-}
-
-}  // namespace
-
 static NetworkCertLoader* g_cert_loader = nullptr;
 static bool g_force_hardware_backed_for_test = false;
 
@@ -209,40 +279,60 @@
 }
 
 NetworkCertLoader::NetworkCertLoader() : weak_factory_(this) {
-  system_cert_cache_ = std::make_unique<CertCache>(base::BindRepeating(
+  system_slot_cert_cache_ = std::make_unique<CertCache>(base::BindRepeating(
       &NetworkCertLoader::OnCertCacheUpdated, base::Unretained(this)));
-  user_cert_cache_ = std::make_unique<CertCache>(base::BindRepeating(
-      &NetworkCertLoader::OnCertCacheUpdated, base::Unretained(this)));
+  user_private_slot_cert_cache_ =
+      std::make_unique<CertCache>(base::BindRepeating(
+          &NetworkCertLoader::OnCertCacheUpdated, base::Unretained(this)));
+  user_public_slot_cert_cache_ =
+      std::make_unique<CertCache>(base::BindRepeating(
+          &NetworkCertLoader::OnCertCacheUpdated, base::Unretained(this)));
 }
 
 NetworkCertLoader::~NetworkCertLoader() {
-  DCHECK(policy_certificate_providers_.empty());
+  DCHECK(!device_policy_certificate_provider_);
+  DCHECK(!user_policy_certificate_provider_);
 }
 
 void NetworkCertLoader::SetSystemNSSDB(
     net::NSSCertDatabase* system_slot_database) {
-  system_cert_cache_->SetNSSDB(system_slot_database);
+  system_slot_cert_cache_->SetNSSDBAndSlot(
+      system_slot_database, system_slot_database->GetSystemSlot(),
+      true /* is_slot_device_wide */);
 }
 
 void NetworkCertLoader::SetUserNSSDB(net::NSSCertDatabase* user_database) {
-  user_cert_cache_->SetNSSDB(user_database);
+  // The private slot can be absent.
+  crypto::ScopedPK11Slot private_slot = user_database->GetPrivateSlot();
+  if (private_slot) {
+    user_private_slot_cert_cache_->SetNSSDBAndSlot(
+        user_database, std::move(private_slot),
+        false /* is_slot_device_wide */);
+  }
+  user_public_slot_cert_cache_->SetNSSDBAndSlot(
+      user_database, user_database->GetPublicSlot(),
+      false /* is_slot_device_wide */);
 }
 
-void NetworkCertLoader::AddPolicyCertificateProvider(
-    PolicyCertificateProvider* policy_certificate_provider) {
-  policy_certificate_provider->AddPolicyProvidedCertsObserver(this);
-  policy_certificate_providers_.push_back(policy_certificate_provider);
+void NetworkCertLoader::SetDevicePolicyCertificateProvider(
+    PolicyCertificateProvider* device_policy_certificate_provider) {
+  if (device_policy_certificate_provider_) {
+    device_policy_certificate_provider_->RemovePolicyProvidedCertsObserver(
+        this);
+  }
+  device_policy_certificate_provider_ = device_policy_certificate_provider;
+  if (device_policy_certificate_provider_)
+    device_policy_certificate_provider_->AddPolicyProvidedCertsObserver(this);
   UpdateCertificates();
 }
 
-void NetworkCertLoader::RemovePolicyCertificateProvider(
-    PolicyCertificateProvider* policy_certificate_provider) {
-  auto iter = std::find(policy_certificate_providers_.begin(),
-                        policy_certificate_providers_.end(),
-                        policy_certificate_provider);
-  DCHECK(iter != policy_certificate_providers_.end());
-  policy_certificate_providers_.erase(iter);
-  policy_certificate_provider->RemovePolicyProvidedCertsObserver(this);
+void NetworkCertLoader::SetUserPolicyCertificateProvider(
+    PolicyCertificateProvider* user_policy_certificate_provider) {
+  if (user_policy_certificate_provider_)
+    user_policy_certificate_provider_->RemovePolicyProvidedCertsObserver(this);
+  user_policy_certificate_provider_ = user_policy_certificate_provider;
+  if (user_policy_certificate_provider_)
+    user_policy_certificate_provider_->AddPolicyProvidedCertsObserver(this);
   UpdateCertificates();
 }
 
@@ -263,17 +353,51 @@
 }
 
 bool NetworkCertLoader::initial_load_of_any_database_running() const {
-  return system_cert_cache_->initial_load_running() ||
-         user_cert_cache_->initial_load_running();
+  return system_slot_cert_cache_->initial_load_running() ||
+         user_private_slot_cert_cache_->initial_load_running() ||
+         user_public_slot_cert_cache_->initial_load_running();
 }
 
 bool NetworkCertLoader::initial_load_finished() const {
-  return system_cert_cache_->initial_load_finished() ||
-         user_cert_cache_->initial_load_finished();
+  return system_slot_cert_cache_->initial_load_finished() ||
+         user_cert_database_load_finished();
 }
 
 bool NetworkCertLoader::user_cert_database_load_finished() const {
-  return user_cert_cache_->initial_load_finished();
+  if (!user_public_slot_cert_cache_->is_initialized())
+    return false;
+
+  // The private slot is optional, so it's possible that the private slot cert
+  // cache is not initialized. In this case, only care about the public slot
+  // cert cache's state.
+  if (!user_private_slot_cert_cache_->is_initialized())
+    return user_public_slot_cert_cache_->initial_load_finished();
+
+  return user_private_slot_cert_cache_->initial_load_finished() &&
+         user_public_slot_cert_cache_->initial_load_finished();
+}
+
+// static
+net::ScopedCERTCertificateList
+NetworkCertLoader::GetAllCertsFromNetworkCertList(
+    const NetworkCertList& network_cert_list) {
+  net::ScopedCERTCertificateList result;
+  result.reserve(network_cert_list.size());
+  for (const NetworkCert& network_cert : network_cert_list) {
+    result.push_back(net::x509_util::DupCERTCertificate(network_cert.cert()));
+  }
+  return result;
+}
+
+// static
+NetworkCertLoader::NetworkCertList NetworkCertLoader::CloneNetworkCertList(
+    const NetworkCertList& network_cert_list) {
+  NetworkCertList result;
+  result.reserve(network_cert_list.size());
+  for (const NetworkCert& network_cert : network_cert_list) {
+    result.push_back(network_cert.Clone());
+  }
+  return result;
 }
 
 // static
@@ -319,54 +443,14 @@
   if (is_shutting_down_)
     return;
 
-  // If user_cert_cache_ has access to system certificates and it has already
-  // finished its initial load, it will contain system certificates which we can
-  // filter.
-  if (user_cert_cache_->initial_load_finished() &&
-      user_cert_cache_->has_system_certificates()) {
-    base::PostTaskWithTraitsAndReplyWithResult(
-        FROM_HERE,
-        {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-        base::BindOnce(&FilterSystemTokenCertificates,
-                       net::x509_util::DupCERTCertificateList(
-                           user_cert_cache_->cert_list()),
-                       user_cert_cache_->nss_database()),
-        base::BindOnce(&NetworkCertLoader::StoreCertsFromCache,
-                       weak_factory_.GetWeakPtr(),
-                       net::x509_util::DupCERTCertificateList(
-                           user_cert_cache_->cert_list())));
-  } else {
-    // The user's cert cache does not contain system certificates.
-    net::ScopedCERTCertificateList system_token_client_certs =
-        net::x509_util::DupCERTCertificateList(system_cert_cache_->cert_list());
-    net::ScopedCERTCertificateList all_certs_from_cache =
-        net::x509_util::DupCERTCertificateList(user_cert_cache_->cert_list());
-    all_certs_from_cache.reserve(all_certs_from_cache.size() +
-                                 system_token_client_certs.size());
-    for (const net::ScopedCERTCertificate& cert : system_token_client_certs) {
-      all_certs_from_cache.push_back(
-          net::x509_util::DupCERTCertificate(cert.get()));
-    }
-    StoreCertsFromCache(std::move(all_certs_from_cache),
-                        std::move(system_token_client_certs));
+  if (system_slot_cert_cache_->certificates_update_running() ||
+      user_private_slot_cert_cache_->certificates_update_running() ||
+      user_public_slot_cert_cache_->certificates_update_running()) {
+    // Don't spam the observers - wait for the pending updates to be triggered.
+    return;
   }
-}
-
-void NetworkCertLoader::StoreCertsFromCache(
-    net::ScopedCERTCertificateList all_certs_from_cache,
-    net::ScopedCERTCertificateList system_token_client_certs) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  VLOG(1) << "StoreCertsFromCache: " << all_certs_from_cache.size() << " ("
-          << system_token_client_certs.size()
-          << " client certs on system slot)";
-
-  // Ignore any existing certificates.
-  all_certs_from_cache_ = std::move(all_certs_from_cache);
-  system_token_client_certs_ = std::move(system_token_client_certs);
 
   certs_from_cache_loaded_ = true;
-
   UpdateCertificates();
 }
 
@@ -379,40 +463,37 @@
   // Only trigger a notification to observers if one of the |CertCache|s has
   // already loaded certificates. Don't trigger notifications if policy-provided
   // certificates change before that.
-  // TODO(https://crbug.com/888451): When we handle client and authority
+  // TODO(https://crbug.com/888451): Now that we handle client and authority
   // certificates separately in NetworkCertLoader, we could fire different
   // notifications for policy-provided cert changes instead of holding back
-  // notifications. Note that it is possible that only |system_cert_cache_| has
-  // loaded certificates (e.g. on the ChromeOS sign-in screen), and it is also
-  // possible that only |user_cert_cache_| has loaded certificates (e.g. if the
-  // system slot is not available for some reason, but a primary user has signed
-  // in).
+  // notifications.
   if (!certs_from_cache_loaded_)
     return;
 
-  // Copy |all_certs_from_cache_| into |all_certs_|, ignoring any existing
-  // certificates.
-  all_certs_.clear();
-  all_certs_.reserve(all_certs_from_cache_.size());
-  for (const net::ScopedCERTCertificate& cert : all_certs_from_cache_)
-    all_certs_.push_back(net::x509_util::DupCERTCertificate(cert.get()));
+  NetworkCertList user_policy_authorities = GetPolicyProvidedAuthorities(
+      user_policy_certificate_provider_, false /* device_wide */);
+  NetworkCertList device_policy_authorities = GetPolicyProvidedAuthorities(
+      device_policy_certificate_provider_, true /* device_wide */);
+  all_authority_certs_ = CombineNetworkCertLists(
+      {&system_slot_cert_cache_->authority_certs(),
+       &user_public_slot_cert_cache_->authority_certs(),
+       &user_private_slot_cert_cache_->authority_certs(),
+       &user_policy_authorities, &device_policy_authorities});
 
-  // Add policy-provided certificates.
-  // TODO(https://crbug.com/888451): Instead of putting authorities and client
-  // certs into |all_certs_| and then filtering in NetworkCertificateHandler, we
-  // should separate the two categories here in |NetworkCertLoader| already
-  // (pmarko@).
-  for (const PolicyCertificateProvider* policy_certificate_provider :
-       policy_certificate_providers_) {
-    AddPolicyProvidedAuthorities(policy_certificate_provider, &all_certs_);
-  }
+  all_client_certs_ =
+      CombineNetworkCertLists({&system_slot_cert_cache_->client_certs(),
+                               &user_public_slot_cert_cache_->client_certs(),
+                               &user_private_slot_cert_cache_->client_certs()});
 
+  VLOG(1) << "OnCertCacheUpdated (all_authority_certs="
+          << all_authority_certs_.size()
+          << ", all_client_certs=" << all_client_certs_.size() << ")";
   NotifyCertificatesLoaded();
 }
 
 void NetworkCertLoader::NotifyCertificatesLoaded() {
   for (auto& observer : observers_)
-    observer.OnCertificatesLoaded(all_certs_);
+    observer.OnCertificatesLoaded();
 }
 
 void NetworkCertLoader::OnPolicyProvidedCertsChanged(
diff --git a/chromeos/network/network_cert_loader.h b/chromeos/network/network_cert_loader.h
index e0b6afb4..ab7ba9fe 100644
--- a/chromeos/network/network_cert_loader.h
+++ b/chromeos/network/network_cert_loader.h
@@ -40,15 +40,38 @@
  public:
   class Observer {
    public:
-    // Called when the certificates, passed for convenience as |all_certs|,
-    // have completed loading.
-    virtual void OnCertificatesLoaded(
-        const net::ScopedCERTCertificateList& all_certs) = 0;
+    // Called when the certificates have completed loading or have been updated.
+    virtual void OnCertificatesLoaded() = 0;
 
    protected:
     virtual ~Observer() {}
   };
 
+  // Holds a certificate that can be used in network configs along with
+  // additional information.
+  class NetworkCert final {
+   public:
+    NetworkCert(net::ScopedCERTCertificate cert, bool device_wide);
+    NetworkCert(NetworkCert&& other);
+    ~NetworkCert();
+    NetworkCert& operator=(NetworkCert&& other);
+
+    CERTCertificate* cert() const { return cert_.get(); }
+    // Returns true if this certificate is available device-wide (so it can be
+    // used in shared network configs).
+    bool is_device_wide() const { return device_wide_; }
+    NetworkCert Clone() const;
+
+   private:
+    net::ScopedCERTCertificate cert_;
+    bool device_wide_;
+
+    DISALLOW_COPY_AND_ASSIGN(NetworkCert);
+  };
+
+  // A list of NetworkCerts.
+  using NetworkCertList = std::vector<NetworkCert>;
+
   // Sets the global instance. Must be called before any calls to Get().
   static void Initialize();
 
@@ -92,19 +115,17 @@
   // (system and user) databases.
   void SetUserNSSDB(net::NSSCertDatabase* user_database);
 
-  // Adds the passed |PolicyCertificateProvider| and starts using the authority
-  // certificates provided by it. NetworkCertLoader registers itself as Observer
-  // on |policy_certificate_provider|, so the caller must ensure to call
-  // |RemovePolicyCertificateProvider| before |policy_certificate_provider| is
-  // destroyed or before |NetworkCertLoader| is shut down.
-  void AddPolicyCertificateProvider(
-      PolicyCertificateProvider* policy_certificate_provider);
+  // Sets the PolicyCertificateProvider for device policy (its authority
+  // certificates will be available device-wide). Call with nullptr to remove it
+  // again.
+  void SetDevicePolicyCertificateProvider(
+      PolicyCertificateProvider* device_policy_certificate_provider);
 
-  // Removes the passed |PolicyCertificateProvider| and stops using authority
-  // certificates provided by it. |policy_certificate_provider| must have been
-  // added using |AddPolicyCertificateProvider| before.
-  void RemovePolicyCertificateProvider(
-      PolicyCertificateProvider* policy_certificate_provider);
+  // Sets the PolicyCertificateProvider for user policy (its authority
+  // certificates will not be available device-wide). Call with nullptr to
+  // remove it again.
+  void SetUserPolicyCertificateProvider(
+      PolicyCertificateProvider* device_user_certificate_provider);
 
   void AddObserver(NetworkCertLoader::Observer* observer);
   void RemoveObserver(NetworkCertLoader::Observer* observer);
@@ -133,20 +154,29 @@
   // Returns true if certificates from a user NSS database have been loaded.
   bool user_cert_database_load_finished() const;
 
-  // Returns all certificates. This will be empty until certificates_loaded() is
-  // true.
-  const net::ScopedCERTCertificateList& all_certs() const {
+  // Returns authority certificates usable for network configurations. This will
+  // be empty until certificates_loaded() is true.
+  const NetworkCertList& authority_certs() const {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return all_certs_;
+    return all_authority_certs_;
   }
 
-  // Returns certificates from the system token. This will be empty until
-  // certificates_loaded() is true.
-  const net::ScopedCERTCertificateList& system_token_client_certs() const {
+  // Returns client certificates usable for network configuration. This will be
+  // empty until certificates_loaded() is true.
+  const NetworkCertList& client_certs() const {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return system_token_client_certs_;
+    return all_client_certs_;
   }
 
+  // Returns all certificates from |network_cert_list|, ignoring if they're
+  // device-wide or not.
+  static net::ScopedCERTCertificateList GetAllCertsFromNetworkCertList(
+      const NetworkCertList& network_cert_list);
+
+  // Clones a vector of |NetworkCert|s.
+  static NetworkCertList CloneNetworkCertList(
+      const NetworkCertList& network_cert_list);
+
   // Called in tests if |IsCertificateHardwareBacked()| should always return
   // true.
   static void ForceHardwareBackedForTesting();
@@ -161,13 +191,6 @@
   // potentially changed.
   void OnCertCacheUpdated();
 
-  // Called as a result of |OnCertCacheUpdated|. This is a separate function,
-  // because |OnCertCacheUpdated| may trigger a background task for filtering
-  // certificates.
-  void StoreCertsFromCache(
-      net::ScopedCERTCertificateList all_certs,
-      net::ScopedCERTCertificateList system_token_client_certs);
-
   // Called when policy-provided certificates or cache-based certificates (see
   // |all_certs_from_cache_|) have potentially changed.
   void UpdateCertificates();
@@ -186,24 +209,26 @@
   base::ObserverList<Observer>::Unchecked observers_;
 
   // Cache for certificates from the system-token NSSCertDatabase.
-  std::unique_ptr<CertCache> system_cert_cache_;
-  // Cache for certificates from the user-specific NSSCertDatabase.
-  std::unique_ptr<CertCache> user_cert_cache_;
+  std::unique_ptr<CertCache> system_slot_cert_cache_;
+  // Cache for certificates from the user-specific NSSCertDatabase, listing
+  // certificates from the private slot.
+  std::unique_ptr<CertCache> user_private_slot_cert_cache_;
+  // Cache for certificates from the user-specific NSSCertDatabase, listing
+  // certificates from the public slot.
+  std::unique_ptr<CertCache> user_public_slot_cert_cache_;
 
-  // Cached certificates loaded from the database(s) and policy-pushed Authority
-  // certificates.
-  net::ScopedCERTCertificateList all_certs_;
+  // Client certificates.
+  NetworkCertList all_client_certs_;
 
-  // Cached certificates loaded from the database(s).
-  net::ScopedCERTCertificateList all_certs_from_cache_;
-
-  // Cached certificates from system token.
-  net::ScopedCERTCertificateList system_token_client_certs_;
+  // Authority certs from |cached_certs_| extended by authority certs provided
+  // by the policy certificate providers.
+  NetworkCertList all_authority_certs_;
 
   // True if |StoreCertsFromCache()| was called before.
   bool certs_from_cache_loaded_ = false;
 
-  std::vector<const PolicyCertificateProvider*> policy_certificate_providers_;
+  PolicyCertificateProvider* device_policy_certificate_provider_ = nullptr;
+  PolicyCertificateProvider* user_policy_certificate_provider_ = nullptr;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/chromeos/network/network_cert_loader_unittest.cc b/chromeos/network/network_cert_loader_unittest.cc
index 45daaf49..065caf7 100644
--- a/chromeos/network/network_cert_loader_unittest.cc
+++ b/chromeos/network/network_cert_loader_unittest.cc
@@ -79,31 +79,38 @@
   net::CertificateList authority_certificates_;
 };
 
-bool IsCertInCertificateList(CERTCertificate* cert,
-                             const net::ScopedCERTCertificateList& cert_list) {
-  for (const auto& cert_list_element : cert_list) {
-    if (net::x509_util::IsSameCertificate(cert_list_element.get(), cert))
+bool IsCertInCertificateList(
+    CERTCertificate* cert,
+    bool device_wide,
+    const std::vector<NetworkCertLoader::NetworkCert>& network_cert_list) {
+  for (const auto& network_cert : network_cert_list) {
+    if (device_wide == network_cert.is_device_wide() &&
+        net::x509_util::IsSameCertificate(network_cert.cert(), cert)) {
       return true;
+    }
   }
   return false;
 }
 
-bool IsCertInCertificateList(const net::X509Certificate* cert,
-                             const net::ScopedCERTCertificateList& cert_list) {
-  for (const auto& cert_list_element : cert_list) {
-    if (net::x509_util::IsSameCertificate(cert_list_element.get(), cert))
+bool IsCertInCertificateList(
+    const net::X509Certificate* cert,
+    bool device_wide,
+    const std::vector<NetworkCertLoader::NetworkCert>& network_cert_list) {
+  for (const auto& network_cert : network_cert_list) {
+    if (device_wide == network_cert.is_device_wide() &&
+        net::x509_util::IsSameCertificate(network_cert.cert(), cert)) {
       return true;
+    }
   }
   return false;
 }
 
 size_t CountCertOccurencesInCertificateList(
     CERTCertificate* cert,
-    const net::ScopedCERTCertificateList& cert_list) {
+    const std::vector<NetworkCertLoader::NetworkCert>& network_cert_list) {
   size_t count = 0;
-  for (net::ScopedCERTCertificateList::const_iterator it = cert_list.begin();
-       it != cert_list.end(); ++it) {
-    if (net::x509_util::IsSameCertificate(it->get(), cert))
+  for (const auto& network_cert : network_cert_list) {
+    if (net::x509_util::IsSameCertificate(network_cert.cert(), cert))
       ++count;
   }
   return count;
@@ -144,7 +151,8 @@
   ~NetworkCertLoaderTest() override = default;
 
   void SetUp() override {
-    ASSERT_TRUE(primary_db_.is_open());
+    ASSERT_TRUE(primary_public_slot_db_.is_open());
+    ASSERT_TRUE(primary_private_slot_db_.is_open());
 
     NetworkCertLoader::Initialize();
     cert_loader_ = NetworkCertLoader::Get();
@@ -157,19 +165,12 @@
   }
 
  protected:
+  // Initializes |primary_certdb_| as a NSSCertDatabse based on
+  // |primary_public_slot_db| and |primary_private_slot_db| and starts the
+  // NetworkCertLoader with it.
   void StartCertLoaderWithPrimaryDB() {
-    CreateCertDatabase(&primary_db_, &primary_certdb_);
-    cert_loader_->SetUserNSSDB(primary_certdb_.get());
-
-    scoped_task_environment_.RunUntilIdle();
-    GetAndResetCertificatesLoadedEventsCount();
-  }
-
-  // Starts the cert loader with a primary cert database which has access to the
-  // system token.
-  void StartCertLoaderWithPrimaryDBAndSystemToken() {
-    CreateCertDatabase(&primary_db_, &primary_certdb_);
-    AddSystemToken(primary_certdb_.get());
+    CreateCertDatabase(&primary_public_slot_db_, &primary_private_slot_db_,
+                       &primary_certdb_);
     cert_loader_->SetUserNSSDB(primary_certdb_.get());
 
     scoped_task_environment_.RunUntilIdle();
@@ -178,8 +179,7 @@
 
   // NetworkCertLoader::Observer:
   // The test keeps count of times the observer method was called.
-  void OnCertificatesLoaded(
-      const net::ScopedCERTCertificateList& cert_list) override {
+  void OnCertificatesLoaded() override {
     EXPECT_TRUE(certificates_loaded_events_count_ == 0);
     certificates_loaded_events_count_++;
   }
@@ -192,13 +192,24 @@
     return result;
   }
 
-  void CreateCertDatabase(crypto::ScopedTestNSSDB* db,
+  // Creates a TestNSSCertDatabase in *|certdb|, using the (mandatory)
+  // |public_slot_db| for the public slot and the (optional) |private_slot_db|
+  // as the private slot.
+  void CreateCertDatabase(crypto::ScopedTestNSSDB* public_slot_db,
+                          crypto::ScopedTestNSSDB* private_slot_db,
                           std::unique_ptr<TestNSSCertDatabase>* certdb) {
-    ASSERT_TRUE(db->is_open());
+    ASSERT_TRUE(public_slot_db && public_slot_db->is_open());
 
-    certdb->reset(new TestNSSCertDatabase(
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(db->slot())),
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(db->slot()))));
+    crypto::ScopedPK11Slot scoped_public_slot(
+        PK11_ReferenceSlot(public_slot_db->slot()));
+    crypto::ScopedPK11Slot scoped_private_slot;
+    if (private_slot_db) {
+      ASSERT_TRUE(private_slot_db->is_open());
+      scoped_private_slot =
+          crypto::ScopedPK11Slot(PK11_ReferenceSlot(private_slot_db->slot()));
+    }
+    *certdb = std::make_unique<TestNSSCertDatabase>(
+        std::move(scoped_public_slot), std::move(scoped_private_slot));
   }
 
   void ImportCACert(const std::string& cert_file,
@@ -261,10 +272,10 @@
 
   NetworkCertLoader* cert_loader_;
 
-  // The user is primary as the one whose certificates NetworkCertLoader
-  // handles, it has nothing to do with crypto::InitializeNSSForChromeOSUser
-  // is_primary_user parameter (which is irrelevant for these tests).
-  crypto::ScopedTestNSSDB primary_db_;
+  // The NSSCertDatabse and underlying slots for the primary user (because
+  // NetworkCertLoader uses device-wide certs and primary user's certs).
+  crypto::ScopedTestNSSDB primary_private_slot_db_;
+  crypto::ScopedTestNSSDB primary_public_slot_db_;
   std::unique_ptr<TestNSSCertDatabase> primary_certdb_;
 
   // Additional NSS DB simulating the system token.
@@ -285,14 +296,19 @@
   EXPECT_FALSE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
 
-  CreateCertDatabase(&primary_db_, &primary_certdb_);
+  CreateCertDatabase(&primary_public_slot_db_, &primary_private_slot_db_,
+                     &primary_certdb_);
+  net::ScopedCERTCertificateList certs;
+  ImportCACert("root_ca_cert.pem", primary_certdb_.get(), &certs);
+  scoped_task_environment_.RunUntilIdle();
+
   cert_loader_->SetUserNSSDB(primary_certdb_.get());
 
   EXPECT_FALSE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_TRUE(cert_loader_->initial_load_of_any_database_running());
-  EXPECT_TRUE(cert_loader_->all_certs().empty());
-  EXPECT_TRUE(cert_loader_->system_token_client_certs().empty());
+  EXPECT_TRUE(cert_loader_->authority_certs().empty());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
@@ -302,9 +318,10 @@
   EXPECT_TRUE(cert_loader_->user_cert_database_load_finished());
   EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
 
-  // Default CA cert roots should get loaded.
-  EXPECT_FALSE(cert_loader_->all_certs().empty());
-  EXPECT_TRUE(cert_loader_->system_token_client_certs().empty());
+  // Default CA cert roots should get loaded but not be available in
+  // NetworkCertLoader.
+  EXPECT_EQ(1U, cert_loader_->authority_certs().size());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 }
 
 TEST_F(NetworkCertLoaderTest, BasicOnlySystemDB) {
@@ -312,13 +329,19 @@
   EXPECT_FALSE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
 
-  CreateCertDatabase(&system_db_, &system_certdb_);
+  CreateCertDatabase(&system_db_, nullptr /* private_slot_db */,
+                     &system_certdb_);
+  AddSystemToken(system_certdb_.get());
+  net::ScopedCERTCertificateList certs;
+  ImportCACert("root_ca_cert.pem", system_certdb_.get(), &certs);
+  scoped_task_environment_.RunUntilIdle();
+
   cert_loader_->SetSystemNSSDB(system_certdb_.get());
 
   EXPECT_FALSE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
-  EXPECT_TRUE(cert_loader_->initial_load_of_any_database_running());
-  EXPECT_TRUE(cert_loader_->all_certs().empty());
+  EXPECT_TRUE(cert_loader_->authority_certs().empty());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
@@ -328,21 +351,27 @@
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
 
-  // Default CA cert roots should get loaded.
-  EXPECT_FALSE(cert_loader_->all_certs().empty());
+  // Default CA cert roots should get loaded, but not be exposed through
+  // NetworkCertLoader.
+  EXPECT_EQ(1U, cert_loader_->authority_certs().size());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 }
 
 // Tests the NetworkCertLoader with a system DB and then with an additional user
 // DB which does not have access to the system token.
 TEST_F(NetworkCertLoaderTest, SystemAndUnaffiliatedUserDB) {
-  CreateCertDatabase(&system_db_, &system_certdb_);
+  CreateCertDatabase(&system_db_, nullptr /* private_slot_db */,
+                     &system_certdb_);
+  AddSystemToken(system_certdb_.get());
   net::ScopedCERTCertificate system_token_cert(ImportClientCertAndKey(
       system_certdb_.get(), system_db_.slot(), TEST_CLIENT_CERT_1));
   ASSERT_TRUE(system_token_cert);
 
-  CreateCertDatabase(&primary_db_, &primary_certdb_);
+  CreateCertDatabase(&primary_public_slot_db_, &primary_private_slot_db_,
+                     &primary_certdb_);
   net::ScopedCERTCertificate user_token_cert(ImportClientCertAndKey(
-      primary_certdb_.get(), primary_db_.slot(), TEST_CLIENT_CERT_2));
+      primary_certdb_.get(), primary_private_slot_db_.slot(),
+      TEST_CLIENT_CERT_2));
   ASSERT_TRUE(user_token_cert);
 
   scoped_task_environment_.RunUntilIdle();
@@ -356,8 +385,7 @@
   EXPECT_FALSE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_TRUE(cert_loader_->initial_load_of_any_database_running());
-  EXPECT_TRUE(cert_loader_->all_certs().empty());
-  EXPECT_TRUE(cert_loader_->system_token_client_certs().empty());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
@@ -366,19 +394,17 @@
   EXPECT_TRUE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
+  EXPECT_EQ(1U, cert_loader_->client_certs().size());
 
-  EXPECT_TRUE(IsCertInCertificateList(
-      system_token_cert.get(), cert_loader_->system_token_client_certs()));
   EXPECT_TRUE(IsCertInCertificateList(system_token_cert.get(),
-                                      cert_loader_->all_certs()));
+                                      true /* device_wide */,
+                                      cert_loader_->client_certs()));
 
   cert_loader_->SetUserNSSDB(primary_certdb_.get());
 
   EXPECT_TRUE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_TRUE(cert_loader_->initial_load_of_any_database_running());
-  EXPECT_FALSE(cert_loader_->all_certs().empty());
-  EXPECT_FALSE(cert_loader_->system_token_client_certs().empty());
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
@@ -387,24 +413,31 @@
   EXPECT_TRUE(cert_loader_->initial_load_finished());
   EXPECT_TRUE(cert_loader_->user_cert_database_load_finished());
   EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
+  EXPECT_EQ(2U, cert_loader_->client_certs().size());
 
-  EXPECT_FALSE(IsCertInCertificateList(
-      user_token_cert.get(), cert_loader_->system_token_client_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(user_token_cert.get(),
+                                       true /* device_wide */,
+                                       cert_loader_->client_certs()));
   EXPECT_TRUE(IsCertInCertificateList(user_token_cert.get(),
-                                      cert_loader_->all_certs()));
+                                      false /* device_wide */,
+                                      cert_loader_->client_certs()));
 }
 
 // Tests the NetworkCertLoader with a system DB and then with an additional user
 // DB which has access to the system token.
 TEST_F(NetworkCertLoaderTest, SystemAndAffiliatedUserDB) {
-  CreateCertDatabase(&system_db_, &system_certdb_);
+  CreateCertDatabase(&system_db_, nullptr /* private_slot_db */,
+                     &system_certdb_);
+  AddSystemToken(system_certdb_.get());
   net::ScopedCERTCertificate system_token_cert(ImportClientCertAndKey(
       system_certdb_.get(), system_db_.slot(), TEST_CLIENT_CERT_1));
   ASSERT_TRUE(system_token_cert);
 
-  CreateCertDatabase(&primary_db_, &primary_certdb_);
+  CreateCertDatabase(&primary_public_slot_db_, &primary_private_slot_db_,
+                     &primary_certdb_);
   net::ScopedCERTCertificate user_token_cert(ImportClientCertAndKey(
-      primary_certdb_.get(), primary_db_.slot(), TEST_CLIENT_CERT_2));
+      primary_certdb_.get(), primary_private_slot_db_.slot(),
+      TEST_CLIENT_CERT_2));
   ASSERT_TRUE(user_token_cert);
 
   AddSystemToken(primary_certdb_.get());
@@ -419,8 +452,7 @@
   EXPECT_FALSE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_TRUE(cert_loader_->initial_load_of_any_database_running());
-  EXPECT_TRUE(cert_loader_->all_certs().empty());
-  EXPECT_TRUE(cert_loader_->system_token_client_certs().empty());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
@@ -429,19 +461,17 @@
   EXPECT_TRUE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
+  EXPECT_EQ(1U, cert_loader_->client_certs().size());
 
-  EXPECT_TRUE(IsCertInCertificateList(
-      system_token_cert.get(), cert_loader_->system_token_client_certs()));
   EXPECT_TRUE(IsCertInCertificateList(system_token_cert.get(),
-                                      cert_loader_->all_certs()));
+                                      true /* device_wide */,
+                                      cert_loader_->client_certs()));
 
   cert_loader_->SetUserNSSDB(primary_certdb_.get());
 
   EXPECT_TRUE(cert_loader_->initial_load_finished());
   EXPECT_FALSE(cert_loader_->user_cert_database_load_finished());
   EXPECT_TRUE(cert_loader_->initial_load_of_any_database_running());
-  EXPECT_FALSE(cert_loader_->all_certs().empty());
-  EXPECT_FALSE(cert_loader_->system_token_client_certs().empty());
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
@@ -450,11 +480,41 @@
   EXPECT_TRUE(cert_loader_->initial_load_finished());
   EXPECT_TRUE(cert_loader_->user_cert_database_load_finished());
   EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
+  EXPECT_EQ(2U, cert_loader_->client_certs().size());
 
-  EXPECT_FALSE(IsCertInCertificateList(
-      user_token_cert.get(), cert_loader_->system_token_client_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(user_token_cert.get(),
+                                       true /* device_wide */,
+                                       cert_loader_->client_certs()));
+  EXPECT_TRUE(IsCertInCertificateList(user_token_cert.get(),
+                                      false /* device_wide */,
+                                      cert_loader_->client_certs()));
   EXPECT_EQ(1U, CountCertOccurencesInCertificateList(
-                    user_token_cert.get(), cert_loader_->all_certs()));
+                    user_token_cert.get(), cert_loader_->client_certs()));
+}
+
+// Tests that NetworkCertLoader does not list certs twice if they appear on
+// multiple slots.
+TEST_F(NetworkCertLoaderTest, DeduplicatesCerts) {
+  // Use the same slot as public and private slot.
+  crypto::ScopedTestNSSDB* single_slot_db = &primary_public_slot_db_;
+  CreateCertDatabase(single_slot_db /* public_slot_db */,
+                     single_slot_db /* private_slot_db */, &primary_certdb_);
+  net::ScopedCERTCertificateList certs;
+  ImportCACert("root_ca_cert.pem", primary_certdb_.get(), &certs);
+  scoped_task_environment_.RunUntilIdle();
+
+  cert_loader_->SetUserNSSDB(primary_certdb_.get());
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
+
+  EXPECT_TRUE(cert_loader_->initial_load_finished());
+  EXPECT_TRUE(cert_loader_->user_cert_database_load_finished());
+  EXPECT_FALSE(cert_loader_->initial_load_of_any_database_running());
+
+  // Default CA cert roots should get loaded but not be available in
+  // NetworkCertLoader.
+  EXPECT_EQ(1U, cert_loader_->authority_certs().size());
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
 }
 
 TEST_F(NetworkCertLoaderTest, UpdateCertListOnNewCert) {
@@ -465,16 +525,16 @@
 
   // Certs are loaded asynchronously, so the new cert should not yet be in the
   // cert list.
-  EXPECT_FALSE(
-      IsCertInCertificateList(certs[0].get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(certs[0].get(), false /* device_wide */,
+                                       cert_loader_->client_certs()));
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 
   // The certificate list should be updated now, as the message loop's been run.
-  EXPECT_TRUE(
-      IsCertInCertificateList(certs[0].get(), cert_loader_->all_certs()));
+  EXPECT_TRUE(IsCertInCertificateList(certs[0].get(), false /* device_wide */,
+                                      cert_loader_->authority_certs()));
 
   EXPECT_FALSE(cert_loader_->IsCertificateHardwareBacked(certs[0].get()));
 }
@@ -484,15 +544,18 @@
   std::unique_ptr<TestNSSCertDatabase> secondary_certdb;
 
   StartCertLoaderWithPrimaryDB();
-  CreateCertDatabase(&secondary_db, &secondary_certdb);
+  CreateCertDatabase(&secondary_db /* public_slot_db */,
+                     &secondary_db /* private_slot_db */, &secondary_certdb);
 
   net::ScopedCERTCertificateList certs;
   ImportCACert("root_ca_cert.pem", secondary_certdb.get(), &certs);
 
   scoped_task_environment_.RunUntilIdle();
 
-  EXPECT_FALSE(
-      IsCertInCertificateList(certs[0].get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(certs[0].get(), false /* device_wide */,
+                                       cert_loader_->client_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(certs[0].get(), true /* device_wide */,
+                                       cert_loader_->client_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, ClientLoaderUpdateOnNewClientCert) {
@@ -506,25 +569,32 @@
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 
-  EXPECT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_TRUE(IsCertInCertificateList(cert.get(), false /* device_wide */,
+                                      cert_loader_->client_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, ClientLoaderUpdateOnNewClientCertInSystemToken) {
-  StartCertLoaderWithPrimaryDBAndSystemToken();
+  CreateCertDatabase(&system_db_ /* public_slot_db */,
+                     nullptr /* private_slot_db */, &system_certdb_);
+  AddSystemToken(system_certdb_.get());
+  scoped_task_environment_.RunUntilIdle();
 
-  EXPECT_TRUE(cert_loader_->system_token_client_certs().empty());
+  cert_loader_->SetSystemNSSDB(system_certdb_.get());
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
+
+  EXPECT_TRUE(cert_loader_->client_certs().empty());
   net::ScopedCERTCertificate cert(ImportClientCertAndKey(
-      primary_certdb_.get(), primary_certdb_->GetSystemSlot().get()));
+      system_certdb_.get(), system_certdb_->GetSystemSlot().get()));
   ASSERT_TRUE(cert);
 
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 
-  EXPECT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
-  EXPECT_EQ(1U, cert_loader_->system_token_client_certs().size());
-  EXPECT_TRUE(IsCertInCertificateList(
-      cert.get(), cert_loader_->system_token_client_certs()));
+  EXPECT_EQ(1U, cert_loader_->client_certs().size());
+  EXPECT_TRUE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                      cert_loader_->client_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, NoUpdateOnNewClientCertInSecondaryDb) {
@@ -532,7 +602,8 @@
   std::unique_ptr<TestNSSCertDatabase> secondary_certdb;
 
   StartCertLoaderWithPrimaryDB();
-  CreateCertDatabase(&secondary_db, &secondary_certdb);
+  CreateCertDatabase(&secondary_db /* public_slot_db */,
+                     &secondary_db /* private_slot_db */, &secondary_certdb);
 
   net::ScopedCERTCertificate cert(
       ImportClientCertAndKey(secondary_certdb.get()));
@@ -540,7 +611,10 @@
 
   scoped_task_environment_.RunUntilIdle();
 
-  EXPECT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(cert.get(), false /* device_wide */,
+                                       cert_loader_->client_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                       cert_loader_->client_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, UpdatedOnCertRemoval) {
@@ -553,7 +627,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
-  ASSERT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  ASSERT_TRUE(IsCertInCertificateList(cert.get(), false /* device_wide */,
+                                      cert_loader_->client_certs()));
 
   primary_certdb_->DeleteCertAndKey(cert.get());
 
@@ -561,7 +636,8 @@
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 
-  ASSERT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  ASSERT_FALSE(IsCertInCertificateList(cert.get(), false /* device_wide */,
+                                       cert_loader_->client_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, UpdatedOnCACertTrustChange) {
@@ -572,8 +648,8 @@
 
   scoped_task_environment_.RunUntilIdle();
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
-  ASSERT_TRUE(
-      IsCertInCertificateList(certs[0].get(), cert_loader_->all_certs()));
+  ASSERT_TRUE(IsCertInCertificateList(certs[0].get(), false /* device_wide */,
+                                      cert_loader_->authority_certs()));
 
   // The value that should have been set by |ImportCACert|.
   ASSERT_EQ(net::NSSCertDatabase::TRUST_DEFAULT,
@@ -597,20 +673,24 @@
   FakePolicyCertificateProvider device_policy_certs_provider;
 
   // Setting the cert provider triggers an update.
-  cert_loader_->AddPolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(
+      &device_policy_certs_provider);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 
   // When policy changes, an update is triggered too.
-  EXPECT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                       cert_loader_->authority_certs()));
   device_policy_certs_provider.SetAuthorityCertificates({cert});
   device_policy_certs_provider.NotifyObservers();
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
-  EXPECT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_TRUE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                      cert_loader_->authority_certs()));
 
   // Removing the cert provider triggers an update.
-  cert_loader_->RemovePolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(nullptr);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
-  EXPECT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                       cert_loader_->authority_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, UpdateOnTwoPolicyCertificateProviders) {
@@ -631,27 +711,32 @@
   FakePolicyCertificateProvider user_policy_certs_provider;
   user_policy_certs_provider.SetAuthorityCertificates({user_policy_cert});
 
-  // Adding a first policy certificate provider triggers an update. In this test
-  // case, the device policy certs provider already contains a cert.
-  cert_loader_->AddPolicyCertificateProvider(&device_policy_certs_provider);
+  // Adding a device policy certificate provider triggers an update. In this
+  // test case, the device policy certs provider already contains a cert.
+  cert_loader_->SetDevicePolicyCertificateProvider(
+      &device_policy_certs_provider);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
   EXPECT_TRUE(IsCertInCertificateList(device_policy_cert.get(),
-                                      cert_loader_->all_certs()));
+                                      true /* device_wide */,
+                                      cert_loader_->authority_certs()));
   EXPECT_FALSE(IsCertInCertificateList(user_policy_cert.get(),
-                                       cert_loader_->all_certs()));
+                                       false /* device_wide */,
+                                       cert_loader_->authority_certs()));
 
-  // Adding a second policy certificate provider triggers an update. In this
+  // Adding a user policy certificate provider triggers an update. In this
   // test case, the user policy certs provider already contains a cert.
-  cert_loader_->AddPolicyCertificateProvider(&user_policy_certs_provider);
+  cert_loader_->SetUserPolicyCertificateProvider(&user_policy_certs_provider);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
   EXPECT_TRUE(IsCertInCertificateList(device_policy_cert.get(),
-                                      cert_loader_->all_certs()));
+                                      true /* device_wide */,
+                                      cert_loader_->authority_certs()));
   EXPECT_TRUE(IsCertInCertificateList(user_policy_cert.get(),
-                                      cert_loader_->all_certs()));
+                                      false /* device_wide */,
+                                      cert_loader_->authority_certs()));
 
-  cert_loader_->RemovePolicyCertificateProvider(&user_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(nullptr);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
-  cert_loader_->RemovePolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetUserPolicyCertificateProvider(nullptr);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 }
 
@@ -666,23 +751,27 @@
 
   // Setting the cert provider does not trigger an update yet, because the
   // NetworkCertLoader has not been set to use a system or user NSS Database.
-  cert_loader_->AddPolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(
+      &device_policy_certs_provider);
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
 
   // Same when the policy changes.
-  EXPECT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                       cert_loader_->authority_certs()));
   device_policy_certs_provider.SetAuthorityCertificates({cert});
   device_policy_certs_provider.NotifyObservers();
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
 
   // After starting the NetworkCertLoader, the policy-provided cert is there.
   StartCertLoaderWithPrimaryDB();
-  EXPECT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_TRUE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                      cert_loader_->authority_certs()));
 
   // Removing the cert provider triggers an update.
-  cert_loader_->RemovePolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(nullptr);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
-  EXPECT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->all_certs()));
+  EXPECT_FALSE(IsCertInCertificateList(cert.get(), true /* device_wide */,
+                                       cert_loader_->authority_certs()));
 }
 
 TEST_F(NetworkCertLoaderTest, NoUpdateWhenShuttingDown) {
@@ -691,13 +780,14 @@
   FakePolicyCertificateProvider device_policy_certs_provider;
 
   // Setting the cert provider triggers an update.
-  cert_loader_->AddPolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(
+      &device_policy_certs_provider);
   ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
 
   // Removing the cert provider does not trigger an update if the shutdown
   // procedure has started.
   cert_loader_->set_is_shutting_down();
-  cert_loader_->RemovePolicyCertificateProvider(&device_policy_certs_provider);
+  cert_loader_->SetDevicePolicyCertificateProvider(nullptr);
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
 }
 
diff --git a/chromeos/network/network_cert_migrator.cc b/chromeos/network/network_cert_migrator.cc
index 4af79fc..be3ea49 100644
--- a/chromeos/network/network_cert_migrator.cc
+++ b/chromeos/network/network_cert_migrator.cc
@@ -6,6 +6,7 @@
 
 #include <cert.h>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -37,10 +38,9 @@
 class NetworkCertMigrator::MigrationTask
     : public base::RefCounted<MigrationTask> {
  public:
-  MigrationTask(const net::ScopedCERTCertificateList& certs,
+  MigrationTask(net::ScopedCERTCertificateList certs,
                 const base::WeakPtr<NetworkCertMigrator>& cert_migrator)
-      : certs_(net::x509_util::DupCERTCertificateList(certs)),
-        cert_migrator_(cert_migrator) {}
+      : certs_(std::move(certs)), cert_migrator_(cert_migrator) {}
 
   void Run(const NetworkStateHandler::NetworkStateList& networks) {
     // Request properties for each network that could be configured with a
@@ -203,8 +203,10 @@
   // Run the migration process to fix missing or incorrect slot ids of client
   // certificates.
   VLOG(2) << "Start certificate migration of network configurations.";
-  scoped_refptr<MigrationTask> helper(new MigrationTask(
-      NetworkCertLoader::Get()->all_certs(), weak_ptr_factory_.GetWeakPtr()));
+  scoped_refptr<MigrationTask> helper(base::MakeRefCounted<MigrationTask>(
+      NetworkCertLoader::GetAllCertsFromNetworkCertList(
+          NetworkCertLoader::Get()->client_certs()),
+      weak_ptr_factory_.GetWeakPtr()));
   NetworkStateHandler::NetworkStateList networks;
   network_state_handler_->GetNetworkListByType(
       NetworkTypePattern::Default(),
@@ -215,8 +217,7 @@
   helper->Run(networks);
 }
 
-void NetworkCertMigrator::OnCertificatesLoaded(
-    const net::ScopedCERTCertificateList& cert_list) {
+void NetworkCertMigrator::OnCertificatesLoaded() {
   NetworkListChanged();
 }
 
diff --git a/chromeos/network/network_cert_migrator.h b/chromeos/network/network_cert_migrator.h
index c766327a..cb28411 100644
--- a/chromeos/network/network_cert_migrator.h
+++ b/chromeos/network/network_cert_migrator.h
@@ -35,8 +35,7 @@
   void NetworkListChanged() override;
 
   // NetworkCertLoader::Observer overrides
-  void OnCertificatesLoaded(
-      const net::ScopedCERTCertificateList& cert_list) override;
+  void OnCertificatesLoaded() override;
 
   // Unowned associated NetworkStateHandler* (global or test instance).
   NetworkStateHandler* network_state_handler_;
diff --git a/chromeos/network/network_cert_migrator_unittest.cc b/chromeos/network/network_cert_migrator_unittest.cc
index 8d9a45da..e433e0dd 100644
--- a/chromeos/network/network_cert_migrator_unittest.cc
+++ b/chromeos/network/network_cert_migrator_unittest.cc
@@ -50,13 +50,19 @@
   void SetUp() override {
     ASSERT_TRUE(test_system_nssdb_.is_open());
     ASSERT_TRUE(test_user_nssdb_.is_open());
-    // Use the same DB for public and private slot.
-    test_system_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot())),
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot()))));
-    test_user_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
+    // Use the same slot as public and private slot for the user's
+    // NSSCertDatabse for testing.
+    test_user_nsscertdb_ = std::make_unique<net::NSSCertDatabaseChromeOS>(
         crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_user_nssdb_.slot())),
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_user_nssdb_.slot()))));
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_user_nssdb_.slot())));
+    // Create a NSSCertDatabase for the system slot. While NetworkCertLoader
+    // does not care about the public slot in this database, NSSCertDatabase
+    // requires a public slot. Pass the system slot there for testing.
+    test_system_nsscertdb_ = std::make_unique<net::NSSCertDatabaseChromeOS>(
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot())),
+        crypto::ScopedPK11Slot() /* private_slot */);
+    test_system_nsscertdb_->SetSystemSlot(
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_system_nssdb_.slot())));
 
     DBusThreadManager::Initialize();
     service_test_ =
diff --git a/chromeos/network/network_certificate_handler.cc b/chromeos/network/network_certificate_handler.cc
index 3c41196..1a483e9 100644
--- a/chromeos/network/network_certificate_handler.cc
+++ b/chromeos/network/network_certificate_handler.cc
@@ -14,11 +14,9 @@
 
 namespace {
 
-// Root CA certificates that are built into Chrome use this token name.
-const char kRootCertificateTokenName[] = "Builtin Object Token";
-
 NetworkCertificateHandler::Certificate GetCertificate(CERTCertificate* cert,
-                                                      net::CertType type) {
+                                                      net::CertType type,
+                                                      bool is_device_wide) {
   NetworkCertificateHandler::Certificate result;
 
   result.hash =
@@ -44,6 +42,8 @@
 
   result.hardware_backed = NetworkCertLoader::IsCertificateHardwareBacked(cert);
 
+  // TODO(https://crbug.com/904362): Forward is_device_wide to the UI.
+
   return result;
 }
 
@@ -59,7 +59,7 @@
 NetworkCertificateHandler::NetworkCertificateHandler() {
   NetworkCertLoader::Get()->AddObserver(this);
   if (NetworkCertLoader::Get()->initial_load_finished())
-    OnCertificatesLoaded(NetworkCertLoader::Get()->all_certs());
+    OnCertificatesLoaded();
 }
 
 NetworkCertificateHandler::~NetworkCertificateHandler() {
@@ -76,50 +76,37 @@
   observer_list_.RemoveObserver(observer);
 }
 
-void NetworkCertificateHandler::OnCertificatesLoaded(
-    const net::ScopedCERTCertificateList& cert_list) {
-  ProcessCertificates(cert_list);
-}
-
-void NetworkCertificateHandler::ProcessCertificates(
-    const net::ScopedCERTCertificateList& cert_list) {
-  user_certificates_.clear();
-  server_ca_certificates_.clear();
-
-  // Add certificates to the appropriate list.
-  for (const auto& cert_ref : cert_list) {
-    CERTCertificate* cert = cert_ref.get();
-    net::CertType type = certificate::GetCertType(cert);
-    switch (type) {
-      case net::USER_CERT:
-        user_certificates_.push_back(GetCertificate(cert, type));
-        break;
-      case net::CA_CERT: {
-        // Exclude root CA certificates that are built into Chrome.
-        std::string token_name = certificate::GetCertTokenName(cert);
-        if (token_name != kRootCertificateTokenName)
-          server_ca_certificates_.push_back(GetCertificate(cert, type));
-        else
-          VLOG(2) << "Ignoring root cert";
-        break;
-      }
-      default:
-        // Ignore other certificates.
-        VLOG(2) << "Ignoring cert type: " << type;
-        break;
-    }
-  }
-
+void NetworkCertificateHandler::AddAuthorityCertificateForTest(
+    const std::string& issued_to) {
+  Certificate cert;
+  cert.issued_to = issued_to;
+  cert.issued_to_ascii = issued_to;
+  server_ca_certificates_.push_back(cert);
   for (auto& observer : observer_list_)
     observer.OnCertificatesChanged();
 }
 
-void NetworkCertificateHandler::SetCertificatesForTest(
-    const net::ScopedCERTCertificateList& cert_list) {
-  ProcessCertificates(cert_list);
+void NetworkCertificateHandler::OnCertificatesLoaded() {
+  ProcessCertificates(NetworkCertLoader::Get()->authority_certs(),
+                      NetworkCertLoader::Get()->client_certs());
 }
 
-void NetworkCertificateHandler::NotifyCertificatsChangedForTest() {
+void NetworkCertificateHandler::ProcessCertificates(
+    const NetworkCertLoader::NetworkCertList& authority_certs,
+    const NetworkCertLoader::NetworkCertList& client_certs) {
+  client_certificates_.clear();
+  server_ca_certificates_.clear();
+
+  // Add certificates to the appropriate list.
+  for (const auto& network_cert : authority_certs) {
+    server_ca_certificates_.push_back(GetCertificate(
+        network_cert.cert(), net::CA_CERT, network_cert.is_device_wide()));
+  }
+  for (const auto& network_cert : client_certs) {
+    client_certificates_.push_back(GetCertificate(
+        network_cert.cert(), net::USER_CERT, network_cert.is_device_wide()));
+  }
+
   for (auto& observer : observer_list_)
     observer.OnCertificatesChanged();
 }
diff --git a/chromeos/network/network_certificate_handler.h b/chromeos/network/network_certificate_handler.h
index 730f7e6..bc47f2e4 100644
--- a/chromeos/network/network_certificate_handler.h
+++ b/chromeos/network/network_certificate_handler.h
@@ -6,6 +6,7 @@
 #define CHROMEOS_NETWORK_NETWORK_CERTIFICATE_HANDLER_H_
 
 #include <string>
+#include <vector>
 
 #include "base/component_export.h"
 #include "base/macros.h"
@@ -69,25 +70,27 @@
   const std::vector<Certificate>& server_ca_certificates() const {
     return server_ca_certificates_;
   }
-  const std::vector<Certificate>& user_certificates() const {
-    return user_certificates_;
+  const std::vector<Certificate>& client_certificates() const {
+    return client_certificates_;
   }
 
-  void SetCertificatesForTest(const net::ScopedCERTCertificateList& cert_list);
-  void NotifyCertificatsChangedForTest();
+  // Adds a testing certificate to the list of authority ceritificates and
+  // notifies observers that certificates have been updated.
+  void AddAuthorityCertificateForTest(const std::string& issued_to);
 
  private:
   // NetworkCertLoader::Observer
-  void OnCertificatesLoaded(
-      const net::ScopedCERTCertificateList& cert_list) override;
+  void OnCertificatesLoaded() override;
 
-  void ProcessCertificates(const net::ScopedCERTCertificateList& cert_list);
+  void ProcessCertificates(
+      const NetworkCertLoader::NetworkCertList& authority_certs,
+      const NetworkCertLoader::NetworkCertList& client_certs);
 
   base::ObserverList<NetworkCertificateHandler::Observer>::Unchecked
       observer_list_;
 
   std::vector<Certificate> server_ca_certificates_;
-  std::vector<Certificate> user_certificates_;
+  std::vector<Certificate> client_certificates_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkCertificateHandler);
 };
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc
index 2b1074a..9d3921e 100644
--- a/chromeos/network/network_connection_handler_impl.cc
+++ b/chromeos/network/network_connection_handler_impl.cc
@@ -214,8 +214,7 @@
   logged_in_time_ = base::TimeTicks::Now();
 }
 
-void NetworkConnectionHandlerImpl::OnCertificatesLoaded(
-    const net::ScopedCERTCertificateList& cert_list) {
+void NetworkConnectionHandlerImpl::OnCertificatesLoaded() {
   certificates_loaded_ = true;
   NET_LOG_EVENT("Certificates Loaded", "");
   if (queued_connect_)
diff --git a/chromeos/network/network_connection_handler_impl.h b/chromeos/network/network_connection_handler_impl.h
index cc9f600..e07b1b09 100644
--- a/chromeos/network/network_connection_handler_impl.h
+++ b/chromeos/network/network_connection_handler_impl.h
@@ -44,8 +44,7 @@
   void LoggedInStateChanged() override;
 
   // NetworkCertLoader::Observer
-  void OnCertificatesLoaded(
-      const net::ScopedCERTCertificateList& cert_list) override;
+  void OnCertificatesLoaded() override;
 
  protected:
   void Init(NetworkStateHandler* network_state_handler,
diff --git a/chromeos/network/network_connection_handler_impl_unittest.cc b/chromeos/network/network_connection_handler_impl_unittest.cc
index 967d8ad..3f89f76 100644
--- a/chromeos/network/network_connection_handler_impl_unittest.cc
+++ b/chromeos/network/network_connection_handler_impl_unittest.cc
@@ -269,9 +269,9 @@
                    bool user_policy) {
     std::string error;
     std::unique_ptr<base::Value> network_configs_value =
-        base::JSONReader::ReadAndReturnError(network_configs_json,
-                                             base::JSON_ALLOW_TRAILING_COMMAS,
-                                             nullptr, &error);
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            network_configs_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+            &error);
     ASSERT_TRUE(network_configs_value) << error;
 
     base::ListValue* network_configs = nullptr;
diff --git a/chromeos/network/onc/onc_certificate_pattern_unittest.cc b/chromeos/network/onc/onc_certificate_pattern_unittest.cc
index aefd1d0..6fe5586 100644
--- a/chromeos/network/onc/onc_certificate_pattern_unittest.cc
+++ b/chromeos/network/onc/onc_certificate_pattern_unittest.cc
@@ -67,7 +67,7 @@
     })";
   std::string error;
   std::unique_ptr<base::Value> pattern_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(pattern_value) << error;
 
@@ -100,7 +100,7 @@
     })";
   std::string error;
   std::unique_ptr<base::Value> pattern_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(pattern_value) << error;
 
@@ -136,7 +136,7 @@
     })";
   std::string error;
   std::unique_ptr<base::Value> pattern_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(pattern_value) << error;
 
@@ -167,7 +167,7 @@
     })";
   std::string error;
   std::unique_ptr<base::Value> pattern_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(pattern_value) << error;
 
diff --git a/chromeos/network/onc/onc_parsed_certificates_unittest.cc b/chromeos/network/onc/onc_parsed_certificates_unittest.cc
index bb9ea22..9d5f426 100644
--- a/chromeos/network/onc/onc_parsed_certificates_unittest.cc
+++ b/chromeos/network/onc/onc_parsed_certificates_unittest.cc
@@ -26,7 +26,7 @@
       base::StringPiece onc_certificates_json,
       std::unique_ptr<OncParsedCertificates>* out_onc_parsed_certificates) {
     std::unique_ptr<base::Value> onc_certificates =
-        base::JSONReader::Read(onc_certificates_json);
+        base::JSONReader::ReadDeprecated(onc_certificates_json);
     if (!onc_certificates)
       return false;
     *out_onc_parsed_certificates =
@@ -333,7 +333,7 @@
       ])";
 
   std::unique_ptr<base::Value> onc_certificates =
-      base::JSONReader::Read(onc_certificates_json);
+      base::JSONReader::ReadDeprecated(onc_certificates_json);
   ASSERT_TRUE(onc_certificates);
 
   OncParsedCertificates master(*onc_certificates);
diff --git a/chromeos/network/onc/onc_translator_shill_to_onc.cc b/chromeos/network/onc/onc_translator_shill_to_onc.cc
index bd182c1..fbfe865 100644
--- a/chromeos/network/onc/onc_translator_shill_to_onc.cc
+++ b/chromeos/network/onc/onc_translator_shill_to_onc.cc
@@ -36,7 +36,7 @@
   if (type == base::Value::Type::STRING) {
     value.reset(new base::Value(str));
   } else {
-    value = base::JSONReader::Read(str);
+    value = base::JSONReader::ReadDeprecated(str);
   }
   if (value && value->type() != type)
     return nullptr;
diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
index b64a420..bfcb059 100644
--- a/chromeos/network/onc/onc_utils.cc
+++ b/chromeos/network/onc/onc_utils.cc
@@ -659,8 +659,9 @@
 
 std::unique_ptr<base::Value> ReadDictionaryFromJson(const std::string& json) {
   std::string error;
-  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
+  std::unique_ptr<base::Value> root =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   if (!root || !root->is_dict()) {
     NET_LOG(ERROR) << "Invalid JSON Dictionary: " << error;
     return nullptr;
diff --git a/chromeos/network/proxy/ui_proxy_config_service_unittest.cc b/chromeos/network/proxy/ui_proxy_config_service_unittest.cc
index 28c8c76..836a01f 100644
--- a/chromeos/network/proxy/ui_proxy_config_service_unittest.cc
+++ b/chromeos/network/proxy/ui_proxy_config_service_unittest.cc
@@ -195,7 +195,8 @@
       {DevicePolicyOncValue(R"("PAC")"),
        DevicePolicyOncValue(R"("http://pac/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -238,7 +239,7 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUnconfiguredWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(user_onc_config));
+                             base::JSONReader::ReadDeprecated(user_onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_FALSE(
@@ -263,7 +264,8 @@
       {UserPolicyOncValue(R"("PAC")"),
        UserPolicyOncValue(R"("http://pac/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -281,7 +283,8 @@
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -299,7 +302,8 @@
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("Direct")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -332,7 +336,8 @@
        UserPolicyOncValue(R"("proxy4")"), UserPolicyOncValue("81"),
        UserPolicyOncValue(R"(["localhost"])")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -364,7 +369,8 @@
        UserPolicyOncValue("83"), UserPolicyOncValue(R"("")"),
        UserPolicyOncValue("0"), UserPolicyOncValue("[]")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -383,7 +389,8 @@
       {UserSettingOncValue(R"("PAC")"),
        UserSettingOncValue(R"("http://pac/test.script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> config = base::JSONReader::Read(config_json);
+  std::unique_ptr<base::Value> config =
+      base::JSONReader::ReadDeprecated(config_json);
   ASSERT_TRUE(config) << config_json;
 
   EXPECT_TRUE(
@@ -405,7 +412,8 @@
        UserSettingOncValue(R"("http://pac/test.script.pac")"),
        UserPolicyOncValue(R"(["localhost"])")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, *config);
 }
@@ -427,7 +435,8 @@
       {ExtensionControlledOncValue(R"("PAC")"),
        ExtensionControlledOncValue(R"("http://pac/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -446,7 +455,8 @@
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {ExtensionControlledOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -464,7 +474,8 @@
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {ExtensionControlledOncValue(R"("Direct")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -503,7 +514,8 @@
        ExtensionControlledOncValue(R"("proxy4")"),
        ExtensionControlledOncValue(R"(["localhost"])")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -522,7 +534,8 @@
       {UserSettingOncValue(R"("PAC")"),
        UserSettingOncValue(R"("http://default/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> config = base::JSONReader::Read(config_json);
+  std::unique_ptr<base::Value> config =
+      base::JSONReader::ReadDeprecated(config_json);
   ASSERT_TRUE(config) << config_json;
 
   EXPECT_TRUE(
@@ -535,7 +548,8 @@
            R"("http://extension/script.pac")",
            R"("http://default/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, *config);
 }
@@ -563,7 +577,8 @@
       {UserPolicyOncValue(R"("PAC")"),
        UserPolicyOncValue(R"("http://managed/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -581,7 +596,8 @@
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -600,7 +616,8 @@
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {ExtensionControlledOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -613,7 +630,7 @@
            "PAC": "http://onc/script.pac"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -623,7 +640,8 @@
       {UserPolicyOncValue(R"("PAC")"),
        UserPolicyOncValue(R"("http://onc/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -635,14 +653,15 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -656,14 +675,15 @@
       R"([{"GUID": "$1", "Type": "WiFi", "AutoConnect": false}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("Direct")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -676,14 +696,15 @@
            "ProxySettings": {"Type": "Direct"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("Direct")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -702,7 +723,7 @@
              "SOCKS": {"Host": "proxy4", "Port": 83}}}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -723,7 +744,8 @@
        UserPolicyOncValue("83"), UserPolicyOncValue(R"("proxy4")"),
        UserPolicyOncValue(R"(["foo.test", "localhost"])")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -739,7 +761,7 @@
              "SOCKS": {"Host": "proxy4", "Port": 84}}}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -759,7 +781,8 @@
        UserPolicyOncValue("84"), UserPolicyOncValue(R"("")"),
        UserPolicyOncValue("0"), UserPolicyOncValue(R"([])")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -772,7 +795,7 @@
            "PAC": "http://onc/script.pac"}}])",
       {kTestUserWifiGuid}, nullptr);
   local_state_.SetManagedPref(::onc::prefs::kDeviceOpenNetworkConfiguration,
-                              base::JSONReader::Read(onc_config));
+                              base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -782,7 +805,8 @@
       {DevicePolicyOncValue(R"("PAC")"),
        DevicePolicyOncValue(R"("http://onc/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -794,14 +818,15 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestSharedWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(onc_config));
+                             base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestSharedWifiGuid, &config));
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -814,7 +839,7 @@
            "PAC": "http://onc/script.pac"}}])",
       {kTestSharedWifiGuid}, nullptr);
   local_state_.SetManagedPref(::onc::prefs::kDeviceOpenNetworkConfiguration,
-                              base::JSONReader::Read(onc_config));
+                              base::JSONReader::ReadDeprecated(onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestSharedWifiGuid, &config));
@@ -824,7 +849,8 @@
       {DevicePolicyOncValue(R"("PAC")"),
        DevicePolicyOncValue(R"("http://onc/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -836,21 +862,23 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(user_onc_config));
+                             base::JSONReader::ReadDeprecated(user_onc_config));
 
   const std::string device_onc_config = base::ReplaceStringPlaceholders(
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "PAC",
            "PAC": "http://onc/script.pac"}}])",
       {kTestUserWifiGuid}, nullptr);
-  local_state_.SetManagedPref(::onc::prefs::kDeviceOpenNetworkConfiguration,
-                              base::JSONReader::Read(device_onc_config));
+  local_state_.SetManagedPref(
+      ::onc::prefs::kDeviceOpenNetworkConfiguration,
+      base::JSONReader::ReadDeprecated(device_onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
 
   std::string expected_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1})", {UserPolicyOncValue(R"("WPAD")")}, nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -862,14 +890,15 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(user_onc_config));
+                             base::JSONReader::ReadDeprecated(user_onc_config));
 
   const std::string device_onc_config = base::ReplaceStringPlaceholders(
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "PAC",
            "PAC": "http://onc/script.pac"}}])",
       {kTestUserWifiGuid}, nullptr);
-  local_state_.SetManagedPref(::onc::prefs::kDeviceOpenNetworkConfiguration,
-                              base::JSONReader::Read(device_onc_config));
+  local_state_.SetManagedPref(
+      ::onc::prefs::kDeviceOpenNetworkConfiguration,
+      base::JSONReader::ReadDeprecated(device_onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -879,7 +908,8 @@
       {DevicePolicyOncValue(R"("PAC")"),
        DevicePolicyOncValue(R"("http://onc/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -891,14 +921,15 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(user_onc_config));
+                             base::JSONReader::ReadDeprecated(user_onc_config));
 
   std::string config_json = base::ReplaceStringPlaceholders(
       R"({"Type": $1, "PAC": $2})",
       {UserSettingOncValue(R"("PAC")"),
        UserSettingOncValue(R"("http://pac/test.script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> config = base::JSONReader::Read(config_json);
+  std::unique_ptr<base::Value> config =
+      base::JSONReader::ReadDeprecated(config_json);
   ASSERT_TRUE(config) << config_json;
 
   EXPECT_TRUE(
@@ -909,7 +940,8 @@
       {UserPolicyAndUserSettingOncValue(R"("WPAD")", R"("PAC")"),
        UserSettingOncValue(R"("http://pac/test.script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, *config);
 }
@@ -927,7 +959,7 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(user_onc_config));
+                             base::JSONReader::ReadDeprecated(user_onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -937,7 +969,8 @@
       {UserPolicyOncValue(R"("PAC")"),
        UserPolicyOncValue(R"("http://pac/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
@@ -955,7 +988,7 @@
       R"([{"GUID": "$1", "Type": "WiFi", "ProxySettings": {"Type": "WPAD"}}])",
       {kTestUserWifiGuid}, nullptr);
   user_prefs_.SetManagedPref(::onc::prefs::kOpenNetworkConfiguration,
-                             base::JSONReader::Read(user_onc_config));
+                             base::JSONReader::ReadDeprecated(user_onc_config));
 
   base::Value config(base::Value::Type::DICTIONARY);
   EXPECT_TRUE(service->MergeEnforcedProxyConfig(kTestUserWifiGuid, &config));
@@ -965,7 +998,8 @@
       {ExtensionControlledOncValue(R"("PAC")"),
        ExtensionControlledOncValue(R"("http://pac/script.pac")")},
       nullptr);
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(expected_json);
   ASSERT_TRUE(expected) << expected_json;
   EXPECT_EQ(*expected, config);
 }
diff --git a/chromeos/printing/ppd_provider.cc b/chromeos/printing/ppd_provider.cc
index 09df3a1..35739956 100644
--- a/chromeos/printing/ppd_provider.cc
+++ b/chromeos/printing/ppd_provider.cc
@@ -838,7 +838,8 @@
       FailQueuedMetadataResolutions(PpdProvider::SERVER_ERROR);
       return;
     }
-    auto top_list = base::ListValue::From(base::JSONReader::Read(contents));
+    auto top_list =
+        base::ListValue::From(base::JSONReader::ReadDeprecated(contents));
 
     if (top_list.get() == nullptr) {
       // We got something malformed back.
@@ -1051,7 +1052,8 @@
       //  [0x5926, "some othercanonical name"]
       // ]
       // So we scan through the response looking for our desired device id.
-      auto top_list = base::ListValue::From(base::JSONReader::Read(buffer));
+      auto top_list =
+          base::ListValue::From(base::JSONReader::ReadDeprecated(buffer));
 
       if (top_list.get() == nullptr) {
         // We got something malformed back.
@@ -1257,7 +1259,8 @@
       return fetch_result;
     }
 
-    auto ret_list = base::ListValue::From(base::JSONReader::Read(buffer));
+    auto ret_list =
+        base::ListValue::From(base::JSONReader::ReadDeprecated(buffer));
     if (ret_list == nullptr) {
       return PpdProvider::INTERNAL_ERROR;
     }
diff --git a/chromeos/services/ime/input_engine.cc b/chromeos/services/ime/input_engine.cc
index 008f412..f62c7ec4 100644
--- a/chromeos/services/ime/input_engine.cc
+++ b/chromeos/services/ime/input_engine.cc
@@ -95,8 +95,8 @@
   int error_code;
   std::string error_string;
   std::unique_ptr<base::Value> message_value =
-      base::JSONReader::ReadAndReturnError(message, base::JSON_PARSE_RFC,
-                                           &error_code, &error_string);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          message, base::JSON_PARSE_RFC, &error_code, &error_string);
   if (!message_value) {
     LOG(ERROR) << "Read message error: " << error_code << "; " << error_string;
     return kFalseResponse;
diff --git a/chromeos/services/secure_channel/wire_message.cc b/chromeos/services/secure_channel/wire_message.cc
index fb9683e..89463a97 100644
--- a/chromeos/services/secure_channel/wire_message.cc
+++ b/chromeos/services/secure_channel/wire_message.cc
@@ -98,8 +98,8 @@
   if (!ParseHeader(serialized_message, is_incomplete_message))
     return nullptr;
 
-  std::unique_ptr<base::Value> body_value =
-      base::JSONReader::Read(serialized_message.substr(kHeaderLength));
+  std::unique_ptr<base::Value> body_value = base::JSONReader::ReadDeprecated(
+      serialized_message.substr(kHeaderLength));
   if (!body_value || !body_value->is_dict()) {
     PA_LOG(WARNING) << "Error: Unable to parse message as JSON.";
     return nullptr;
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc
index 073091f..22b7f822 100644
--- a/chromeos/settings/cros_settings_names.cc
+++ b/chromeos/settings/cros_settings_names.cc
@@ -364,9 +364,8 @@
 // A string pref that specifies PluginVm license key for this device.
 const char kPluginVmLicenseKey[] = "cros.device.plugin_vm_license_key";
 
-// An enum pref specifying the case when device needs to reboot after user sign
+// An enum pref specifying the case when device needs to reboot on user sign
 // out.
-const char kDeviceRebootAfterUserSignout[] =
-    "cros.device.reboot_after_user_signout";
+const char kDeviceRebootOnUserSignout[] = "cros.device.reboot_on_user_signout";
 
 }  // namespace chromeos
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h
index fe1220c5..9d7b685 100644
--- a/chromeos/settings/cros_settings_names.h
+++ b/chromeos/settings/cros_settings_names.h
@@ -209,7 +209,7 @@
 COMPONENT_EXPORT(CHROMEOS_SETTINGS) extern const char kPluginVmLicenseKey[];
 
 COMPONENT_EXPORT(CHROMEOS_SETTINGS)
-extern const char kDeviceRebootAfterUserSignout[];
+extern const char kDeviceRebootOnUserSignout[];
 
 }  // namespace chromeos
 
diff --git a/chromeos/timezone/timezone_request.cc b/chromeos/timezone/timezone_request.cc
index b967545..4120376 100644
--- a/chromeos/timezone/timezone_request.cc
+++ b/chromeos/timezone/timezone_request.cc
@@ -183,8 +183,8 @@
   // Parse the response, ignoring comments.
   std::string error_msg;
   std::unique_ptr<base::Value> response_value =
-      base::JSONReader::ReadAndReturnError(response_body, base::JSON_PARSE_RFC,
-                                           NULL, &error_msg);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          response_body, base::JSON_PARSE_RFC, NULL, &error_msg);
   if (response_value == NULL) {
     PrintTimeZoneError(server_url, "JSONReader failed: " + error_msg, timezone);
     RecordUmaEvent(TIMEZONE_REQUEST_EVENT_RESPONSE_MALFORMED);
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 7b061bb..d1bb9ff 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -215,6 +215,7 @@
       "//components/cast_certificate:unit_tests",
       "//components/cast_channel:unit_tests",
       "//components/certificate_transparency:unit_tests",
+      "//components/content_capture/browser:unit_tests",
       "//components/contextual_search/core:unit_tests",
       "//components/crash/content/app:unit_tests",
       "//components/crash/content/browser:unit_tests",
diff --git a/components/account_id/account_id.cc b/components/account_id/account_id.cc
index 8b5eb0a..859cd4a 100644
--- a/components/account_id/account_id.cc
+++ b/components/account_id/account_id.cc
@@ -241,7 +241,7 @@
 bool AccountId::Deserialize(const std::string& serialized,
                             AccountId* account_id) {
   base::JSONReader reader;
-  std::unique_ptr<const base::Value> value(reader.Read(serialized));
+  std::unique_ptr<const base::Value> value(reader.ReadDeprecated(serialized));
   const base::DictionaryValue* dictionary_value = nullptr;
 
   if (!value || !value->GetAsDictionary(&dictionary_value))
diff --git a/components/arc/arc_features_parser.cc b/components/arc/arc_features_parser.cc
index 6cfde59..11021cc 100644
--- a/components/arc/arc_features_parser.cc
+++ b/components/arc/arc_features_parser.cc
@@ -29,8 +29,8 @@
   int error_code;
   std::string error_msg;
   std::unique_ptr<base::Value> json_value =
-      base::JSONReader::ReadAndReturnError(input_json, base::JSON_PARSE_RFC,
-                                           &error_code, &error_msg);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          input_json, base::JSON_PARSE_RFC, &error_code, &error_msg);
   if (!json_value || !json_value->is_dict()) {
     LOG(ERROR) << "Error parsing feature JSON: " << error_msg;
     return base::nullopt;
diff --git a/components/autofill/core/browser/credit_card_save_manager.h b/components/autofill/core/browser/credit_card_save_manager.h
index f20e539..b50c149 100644
--- a/components/autofill/core/browser/credit_card_save_manager.h
+++ b/components/autofill/core/browser/credit_card_save_manager.h
@@ -127,6 +127,7 @@
   friend class LocalCardMigrationBrowserTest;
   friend class TestCreditCardSaveManager;
   friend class SaveCardBubbleViewsFullFormBrowserTest;
+  friend class SaveCardInfobarEGTestHelper;
 
   // Returns the CreditCardSaveStrikeDatabase for |client_|.
   CreditCardSaveStrikeDatabase* GetCreditCardSaveStrikeDatabase();
diff --git a/components/autofill/core/browser/legal_message_line_unittest.cc b/components/autofill/core/browser/legal_message_line_unittest.cc
index c913503..6a5c5ba 100644
--- a/components/autofill/core/browser/legal_message_line_unittest.cc
+++ b/components/autofill/core/browser/legal_message_line_unittest.cc
@@ -104,7 +104,7 @@
 // Verifies that legal message parsing is correct.
 TEST_P(LegalMessageLineTest, Parsing) {
   std::unique_ptr<base::Value> value(
-      base::JSONReader::Read(GetParam().message_json));
+      base::JSONReader::ReadDeprecated(GetParam().message_json));
   ASSERT_TRUE(value);
   base::DictionaryValue* dictionary = nullptr;
   EXPECT_TRUE(value->GetAsDictionary(&dictionary));
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc
index 174783c..bca87d3 100644
--- a/components/autofill/core/browser/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
@@ -125,10 +126,7 @@
   auto card_is_selected = [&selected_card_guids](MigratableCreditCard& card) {
     return !base::ContainsValue(selected_card_guids, card.credit_card().guid());
   };
-  migratable_credit_cards_.erase(
-      std::remove_if(migratable_credit_cards_.begin(),
-                     migratable_credit_cards_.end(), card_is_selected),
-      migratable_credit_cards_.end());
+  base::EraseIf(migratable_credit_cards_, card_is_selected);
   // Populating risk data and offering migration two-round pop-ups occur
   // asynchronously. If |migration_risk_data_| has already been loaded, send the
   // migrate local cards request. Otherwise, continue to wait and let
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index e1b119c6..fe22763 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -879,7 +879,8 @@
     // Valid response.
     case net::HTTP_OK: {
       std::string error_code;
-      std::unique_ptr<base::Value> message_value = base::JSONReader::Read(data);
+      std::unique_ptr<base::Value> message_value =
+          base::JSONReader::ReadDeprecated(data);
       if (message_value.get() && message_value->is_dict()) {
         response_dict =
             base::Value::FromUniquePtrValue(std::move(message_value));
diff --git a/components/autofill/core/browser/strike_database.cc b/components/autofill/core/browser/strike_database.cc
index 0e247e7d..1f4e4aa 100644
--- a/components/autofill/core/browser/strike_database.cc
+++ b/components/autofill/core/browser/strike_database.cc
@@ -72,6 +72,17 @@
   ClearAllProtoStrikesForKey(key, base::DoNothing());
 }
 
+void StrikeDatabase::ClearAllStrikes(const std::string& project_prefix) {
+  std::vector<std::string> keys_to_delete;
+  for (std::pair<std::string, StrikeData> entry : strike_map_cache_) {
+    if (entry.first.find(project_prefix) == 0) {
+      keys_to_delete.push_back(entry.first);
+    }
+  }
+  for (std::string key : keys_to_delete)
+    ClearStrikes(key);
+}
+
 StrikeDatabase::StrikeDatabase()
     : db_(nullptr),
       database_dir_(base::FilePath(nullptr)),
diff --git a/components/autofill/core/browser/strike_database.h b/components/autofill/core/browser/strike_database.h
index bea6da0..479a549 100644
--- a/components/autofill/core/browser/strike_database.h
+++ b/components/autofill/core/browser/strike_database.h
@@ -16,6 +16,11 @@
 #include "components/leveldb_proto/public/proto_database.h"
 
 namespace autofill {
+
+namespace {
+const char kKeyDeliminator[] = "__";
+}  // namespace
+
 class StrikeData;
 
 // Manages data on whether different Autofill opportunities should be offered to
@@ -62,6 +67,10 @@
   // ProtoDatabase.
   void ClearStrikes(const std::string key);
 
+  // Removes all database entries from in-memory cache and underlying
+  // ProtoDatabase for the whole project.
+  void ClearAllStrikes(const std::string& project_prefix);
+
  protected:
   friend class StrikeDatabaseIntegratorBase;
   // Constructor for testing that does not initialize a ProtoDatabase.
@@ -92,6 +101,7 @@
                            GetIdForCreditCardSaveTest);
   FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest,
                            RemoveExpiredStrikesOnLoadTest);
+  friend class SaveCardInfobarEGTestHelper;
   friend class StrikeDatabaseTest;
   friend class StrikeDatabaseTester;
 
diff --git a/components/autofill/core/browser/strike_database_integrator_base.cc b/components/autofill/core/browser/strike_database_integrator_base.cc
index b4f544e..ed4ac89 100644
--- a/components/autofill/core/browser/strike_database_integrator_base.cc
+++ b/components/autofill/core/browser/strike_database_integrator_base.cc
@@ -20,10 +20,6 @@
 
 namespace autofill {
 
-namespace {
-const char kKeyDeliminator[] = "__";
-}  // namespace
-
 StrikeDatabaseIntegratorBase::StrikeDatabaseIntegratorBase(
     StrikeDatabase* strike_database)
     : strike_database_(strike_database) {}
@@ -72,6 +68,10 @@
   strike_database_->ClearStrikes(GetKey(id));
 }
 
+void StrikeDatabaseIntegratorBase::ClearAllStrikes() {
+  strike_database_->ClearAllStrikes(GetProjectPrefix());
+}
+
 void StrikeDatabaseIntegratorBase::RemoveExpiredStrikes() {
   std::vector<std::string> expired_keys;
   for (auto entry : strike_database_->strike_map_cache_) {
diff --git a/components/autofill/core/browser/strike_database_integrator_base.h b/components/autofill/core/browser/strike_database_integrator_base.h
index 7996986..81a48f91 100644
--- a/components/autofill/core/browser/strike_database_integrator_base.h
+++ b/components/autofill/core/browser/strike_database_integrator_base.h
@@ -48,6 +48,10 @@
   // ProtoDatabase.
   void ClearStrikes(const std::string id = kSharedId);
 
+  // Removes all database entries from in-memory cache and underlying
+  // ProtoDatabase for the whole project.
+  void ClearAllStrikes();
+
  protected:
   // Removes all strikes in which it has been longer than GetExpiryTimeMicros()
   // past |last_update_timestamp|.
@@ -62,6 +66,7 @@
                            GetKeyForStrikeDatabaseIntegratorUniqueIdTest);
   FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
                            RemoveExpiredStrikesUniqueIdTest);
+  friend class SaveCardInfobarEGTestHelper;
   friend class StrikeDatabaseTest;
   friend class StrikeDatabaseTester;
 
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
index d183b93b..dee8a266 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
@@ -166,6 +166,22 @@
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+       StrikeDatabaseIntegratorUniqueIdTestClearAllStrikes) {
+  strike_database_.SetUniqueIdsRequired(true);
+  const std::string unique_id_1 = "1234";
+  const std::string unique_id_2 = "9876";
+  // 1 strike added for |unique_id_1|.
+  strike_database_.AddStrike(unique_id_1);
+  // 3 strikes added for |unique_id_2|.
+  strike_database_.AddStrikes(3, unique_id_2);
+  EXPECT_EQ(1, strike_database_.GetStrikes(unique_id_1));
+  EXPECT_EQ(3, strike_database_.GetStrikes(unique_id_2));
+  strike_database_.ClearAllStrikes();
+  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_1));
+  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_2));
+}
+
+TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        AddStrikeForZeroAndNonZeroStrikesUniqueIdTest) {
   strike_database_.SetUniqueIdsRequired(true);
   const std::string unique_id = "1234";
diff --git a/components/autofill/core/common/autofill_prefs_unittest.cc b/components/autofill/core/common/autofill_prefs_unittest.cc
index 1a9e4e0..9ce7a56 100644
--- a/components/autofill/core/common/autofill_prefs_unittest.cc
+++ b/components/autofill/core/common/autofill_prefs_unittest.cc
@@ -195,7 +195,8 @@
   std::string output_js;
   EXPECT_TRUE(base::JSONWriter::Write(*dictionary, &output_js));
   EXPECT_TRUE(dictionary->Equals(
-      base::DictionaryValue::From(base::JSONReader::Read(output_js)).get()));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(output_js))
+          .get()));
 }
 
 }  // namespace prefs
diff --git a/components/autofill/ios/browser/autofill_util.mm b/components/autofill/ios/browser/autofill_util.mm
index 673b520..208e29c 100644
--- a/components/autofill/ios/browser/autofill_util.mm
+++ b/components/autofill/ios/browser/autofill_util.mm
@@ -54,9 +54,10 @@
   // Convert JSON string to JSON object |JSONValue|.
   int error_code = 0;
   std::string error_message;
-  std::unique_ptr<base::Value> json_value(base::JSONReader::ReadAndReturnError(
-      base::SysNSStringToUTF8(json_string), base::JSON_PARSE_RFC, &error_code,
-      &error_message));
+  std::unique_ptr<base::Value> json_value(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          base::SysNSStringToUTF8(json_string), base::JSON_PARSE_RFC,
+          &error_code, &error_message));
   if (error_code)
     return nullptr;
 
diff --git a/components/autofill_assistant/browser/devtools/devtools_client.cc b/components/autofill_assistant/browser/devtools/devtools_client.cc
index 4660e5567..4627fb6 100644
--- a/components/autofill_assistant/browser/devtools/devtools_client.cc
+++ b/components/autofill_assistant/browser/devtools/devtools_client.cc
@@ -102,7 +102,7 @@
   DCHECK_EQ(agent_host, agent_host_.get());
 
   std::unique_ptr<base::Value> message =
-      base::JSONReader::Read(json_message, base::JSON_PARSE_RFC);
+      base::JSONReader::ReadDeprecated(json_message, base::JSON_PARSE_RFC);
   DCHECK(message && message->is_dict());
 
   const base::DictionaryValue* message_dict;
diff --git a/components/cast_channel/cast_message_handler_unittest.cc b/components/cast_channel/cast_message_handler_unittest.cc
index 4b91ae48..89f67e7 100644
--- a/components/cast_channel/cast_message_handler_unittest.cc
+++ b/components/cast_channel/cast_message_handler_unittest.cc
@@ -44,7 +44,7 @@
   if (!message.has_payload_utf8())
     return nullptr;
 
-  return base::JSONReader::Read(message.payload_utf8());
+  return base::JSONReader::ReadDeprecated(message.payload_utf8());
 }
 
 CastMessageType GetMessageType(const CastMessage& message) {
diff --git a/components/cloud_devices/common/cloud_device_description.cc b/components/cloud_devices/common/cloud_device_description.cc
index a8d8f87a..513a24f 100644
--- a/components/cloud_devices/common/cloud_device_description.cc
+++ b/components/cloud_devices/common/cloud_device_description.cc
@@ -22,7 +22,7 @@
 CloudDeviceDescription::~CloudDeviceDescription() = default;
 
 bool CloudDeviceDescription::InitFromString(const std::string& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   if (!value)
     return false;
 
diff --git a/components/cloud_devices/common/printer_description_unittest.cc b/components/cloud_devices/common/printer_description_unittest.cc
index 734cbe2..30b62ad 100644
--- a/components/cloud_devices/common/printer_description_unittest.cc
+++ b/components/cloud_devices/common/printer_description_unittest.cc
@@ -22,7 +22,7 @@
 std::string NormalizeJson(const std::string& json) {
   std::string result = json;
   base::ReplaceChars(result, "'", "\"", &result);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(result);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(result);
   base::JSONWriter::Write(*value, &result);
   return result;
 }
@@ -899,7 +899,7 @@
 TEST(PrinterDescriptionTest, CddGetRangeVendorCapability) {
   for (const auto& capacity : kTestRangeCapabilities) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(NormalizeJson(capacity.json_name));
+        base::JSONReader::ReadDeprecated(NormalizeJson(capacity.json_name));
     ASSERT_TRUE(value);
     base::Value description = base::Value::FromUniquePtrValue(std::move(value));
     RangeVendorCapability range_capability;
@@ -914,7 +914,7 @@
       kInvalidDefaultValueRangeVendorCapabilityJson};
   for (const char* invalid_json_name : kInvalidJsonNames) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(NormalizeJson(invalid_json_name));
+        base::JSONReader::ReadDeprecated(NormalizeJson(invalid_json_name));
     ASSERT_TRUE(value);
     base::Value description = base::Value::FromUniquePtrValue(std::move(value));
     RangeVendorCapability range_capability;
@@ -937,8 +937,8 @@
 
 TEST(PrinterDescriptionTest, CddGetSelectVendorCapability) {
   {
-    std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(NormalizeJson(kSelectVendorCapabilityJson));
+    std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+        NormalizeJson(kSelectVendorCapabilityJson));
     ASSERT_TRUE(value);
     base::Value description = base::Value::FromUniquePtrValue(std::move(value));
     SelectVendorCapability select_capability;
@@ -960,7 +960,7 @@
       kSeveralDefaultsSelectVendorCapabilityJson};
   for (const char* invalid_json_name : kInvalidJsonNames) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(NormalizeJson(invalid_json_name));
+        base::JSONReader::ReadDeprecated(NormalizeJson(invalid_json_name));
     ASSERT_TRUE(value);
     base::Value description = base::Value::FromUniquePtrValue(std::move(value));
     SelectVendorCapability select_capability;
@@ -987,7 +987,7 @@
 TEST(PrinterDescriptionTest, CddGetTypedValueVendorCapability) {
   for (const auto& capacity : kTestTypedValueCapabilities) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(NormalizeJson(capacity.json_name));
+        base::JSONReader::ReadDeprecated(NormalizeJson(capacity.json_name));
     ASSERT_TRUE(value);
     base::Value description = base::Value::FromUniquePtrValue(std::move(value));
     TypedValueVendorCapability typed_value_capability;
@@ -1002,7 +1002,7 @@
       kInvalidIntegerTypedValueVendorCapabilityJson};
   for (const char* invalid_json_name : kInvalidJsonNames) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(NormalizeJson(invalid_json_name));
+        base::JSONReader::ReadDeprecated(NormalizeJson(invalid_json_name));
     ASSERT_TRUE(value);
     base::Value description = base::Value::FromUniquePtrValue(std::move(value));
     TypedValueVendorCapability typed_value_capability;
diff --git a/components/content_capture/browser/BUILD.gn b/components/content_capture/browser/BUILD.gn
new file mode 100644
index 0000000..455f1c4
--- /dev/null
+++ b/components/content_capture/browser/BUILD.gn
@@ -0,0 +1,38 @@
+# 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.
+
+source_set("browser") {
+  sources = [
+    "content_capture_receiver.cc",
+    "content_capture_receiver.h",
+    "content_capture_receiver_manager.cc",
+    "content_capture_receiver_manager.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//components/content_capture/common",
+    "//components/content_capture/common:mojo_interfaces",
+    "//content/public/browser",
+    "//ui/gfx/geometry",
+  ]
+
+  deps = []
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "content_capture_receiver_test.cc",
+  ]
+
+  deps = [
+    ":browser",
+    "//base",
+    "//base/test:test_support",
+    "//content/test:test_support",
+    "//mojo/public/cpp/bindings",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/content_capture/browser/DEPS b/components/content_capture/browser/DEPS
new file mode 100644
index 0000000..d79a7d0
--- /dev/null
+++ b/components/content_capture/browser/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+content/public/browser",
+  "+content/public/test",
+]
diff --git a/components/content_capture/browser/content_capture_receiver.cc b/components/content_capture/browser/content_capture_receiver.cc
new file mode 100644
index 0000000..394869b
--- /dev/null
+++ b/components/content_capture/browser/content_capture_receiver.cc
@@ -0,0 +1,59 @@
+// 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/content_capture/browser/content_capture_receiver.h"
+
+#include <utility>
+
+#include "components/content_capture/browser/content_capture_receiver_manager.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content_capture {
+
+ContentCaptureReceiver::ContentCaptureReceiver(content::RenderFrameHost* rfh)
+    : bindings_(this), rfh_(rfh), id_(GetIdFrom(rfh)) {}
+
+ContentCaptureReceiver::~ContentCaptureReceiver() = default;
+
+int64_t ContentCaptureReceiver::GetIdFrom(content::RenderFrameHost* rfh) {
+  return static_cast<int64_t>(rfh->GetProcess()->GetID()) << 32 |
+         (rfh->GetRoutingID() & 0xFFFFFFFF);
+}
+
+void ContentCaptureReceiver::BindRequest(
+    mojom::ContentCaptureReceiverAssociatedRequest request) {
+  bindings_.Bind(std::move(request));
+}
+
+void ContentCaptureReceiver::DidCaptureContent(const ContentCaptureData& data,
+                                               bool first_data) {
+  auto* manager = ContentCaptureReceiverManager::FromWebContents(
+      content::WebContents::FromRenderFrameHost(rfh_));
+
+  if (first_data) {
+    // The session id of this frame isn't changed for new document navigation,
+    // so the previous session should be terminated.
+    if (frame_content_capture_data_.id != 0)
+      manager->DidRemoveSession(this);
+
+    frame_content_capture_data_.id = id_;
+    // Copies everything except id and children.
+    frame_content_capture_data_.value = data.value;
+    frame_content_capture_data_.bounds = data.bounds;
+  }
+  // We can't avoid copy the data here, because id need to be overriden.
+  ContentCaptureData content(data);
+  content.id = id_;
+  manager->DidCaptureContent(this, content);
+}
+
+void ContentCaptureReceiver::DidRemoveContent(
+    const std::vector<int64_t>& data) {
+  auto* manager = ContentCaptureReceiverManager::FromWebContents(
+      content::WebContents::FromRenderFrameHost(rfh_));
+  manager->DidRemoveContent(this, data);
+}
+
+}  // namespace content_capture
diff --git a/components/content_capture/browser/content_capture_receiver.h b/components/content_capture/browser/content_capture_receiver.h
new file mode 100644
index 0000000..d745b07
--- /dev/null
+++ b/components/content_capture/browser/content_capture_receiver.h
@@ -0,0 +1,62 @@
+// 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_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_RECEIVER_H_
+#define COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_RECEIVER_H_
+
+#include <vector>
+
+#include "components/content_capture/common/content_capture.mojom.h"
+#include "components/content_capture/common/content_capture_data.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace content_capture {
+
+// This class has an instance per RenderFrameHost, it receives messages from
+// renderer and forward them to ContentCaptureReceiverManager for further
+// processing.
+class ContentCaptureReceiver : public mojom::ContentCaptureReceiver {
+ public:
+  static int64_t GetIdFrom(content::RenderFrameHost* rfh);
+  explicit ContentCaptureReceiver(content::RenderFrameHost* rfh);
+  ~ContentCaptureReceiver() override;
+
+  // Binds to mojom.
+  void BindRequest(mojom::ContentCaptureReceiverAssociatedRequest request);
+
+  // mojom::ContentCaptureReceiver
+  void DidCaptureContent(const ContentCaptureData& data,
+                         bool first_data) override;
+  void DidRemoveContent(const std::vector<int64_t>& data) override;
+
+  content::RenderFrameHost* rfh() const { return rfh_; }
+
+  // Return ContentCaptureData of the associated frame.
+  const ContentCaptureData& frame_content_capture_data() const {
+    return frame_content_capture_data_;
+  }
+
+ private:
+  mojo::AssociatedBinding<mojom::ContentCaptureReceiver> bindings_;
+  content::RenderFrameHost* rfh_;
+  ContentCaptureData frame_content_capture_data_;
+
+  // The content id of the associated frame, it is composed of RenderProcessHost
+  // unique ID and frame routing ID, and is unique in a WebContents.
+  // The ID is always generated in receiver because neither does the parent
+  // frame always have content, nor is its content always captured before child
+  // frame's; if the Id is generated in sender, the
+  // ContentCaptureReceiverManager can't get parent frame id in both cases.
+  int64_t id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentCaptureReceiver);
+};
+
+}  // namespace content_capture
+
+#endif  // COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_RECEIVER_H_
diff --git a/components/content_capture/browser/content_capture_receiver_manager.cc b/components/content_capture/browser/content_capture_receiver_manager.cc
new file mode 100644
index 0000000..57e7702
--- /dev/null
+++ b/components/content_capture/browser/content_capture_receiver_manager.cc
@@ -0,0 +1,134 @@
+// 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/content_capture/browser/content_capture_receiver_manager.h"
+
+#include <utility>
+
+#include "components/content_capture/browser/content_capture_receiver.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content_capture {
+namespace {
+
+const void* const kUserDataKey = &kUserDataKey;
+
+}  // namespace
+
+ContentCaptureReceiverManager::ContentCaptureReceiverManager(
+    content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents) {
+  const std::vector<content::RenderFrameHost*> frames =
+      web_contents->GetAllFrames();
+  for (content::RenderFrameHost* frame : frames)
+    RenderFrameCreated(frame);
+
+  web_contents->SetUserData(
+      kUserDataKey, std::unique_ptr<ContentCaptureReceiverManager>(this));
+}
+
+ContentCaptureReceiverManager::~ContentCaptureReceiverManager() = default;
+
+ContentCaptureReceiverManager* ContentCaptureReceiverManager::FromWebContents(
+    content::WebContents* contents) {
+  return static_cast<ContentCaptureReceiverManager*>(
+      contents->GetUserData(kUserDataKey));
+}
+
+void ContentCaptureReceiverManager::BindContentCaptureReceiver(
+    mojom::ContentCaptureReceiverAssociatedRequest request,
+    content::RenderFrameHost* render_frame_host) {
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(render_frame_host);
+
+  if (!web_contents)
+    return;
+
+  ContentCaptureReceiverManager* manager =
+      ContentCaptureReceiverManager::FromWebContents(web_contents);
+  if (!manager)
+    return;
+
+  auto* receiver = manager->ContentCaptureReceiverForFrame(render_frame_host);
+  if (receiver)
+    receiver->BindRequest(std::move(request));
+}
+
+ContentCaptureReceiver*
+ContentCaptureReceiverManager::ContentCaptureReceiverForFrame(
+    content::RenderFrameHost* render_frame_host) {
+  auto mapping = frame_map_.find(render_frame_host);
+  return mapping == frame_map_.end() ? nullptr : mapping->second.get();
+}
+
+void ContentCaptureReceiverManager::RenderFrameCreated(
+    content::RenderFrameHost* render_frame_host) {
+  // The frame might not have content, but it could be parent of other frame. we
+  // always create the ContentCaptureReceiver for ContentCaptureSession
+  // purpose.
+  if (ContentCaptureReceiverForFrame(render_frame_host))
+    return;
+  frame_map_.insert(std::make_pair(
+      render_frame_host,
+      std::make_unique<ContentCaptureReceiver>(render_frame_host)));
+}
+
+void ContentCaptureReceiverManager::RenderFrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+  frame_map_.erase(render_frame_host);
+}
+
+void ContentCaptureReceiverManager::DidCaptureContent(
+    ContentCaptureReceiver* content_capture_receiver,
+    const ContentCaptureData& data) {
+  // The root of |data| is frame, we need get its ancestor only.
+  ContentCaptureSession parent_session;
+  BuildContentCaptureSession(*content_capture_receiver,
+                             true /* ancestor_only */, &parent_session);
+  DidCaptureContent(parent_session, data);
+}
+
+void ContentCaptureReceiverManager::DidRemoveContent(
+    ContentCaptureReceiver* content_capture_receiver,
+    const std::vector<int64_t>& data) {
+  ContentCaptureSession session;
+  // The |data| is a list of text content id, the session should include
+  // |content_capture_receiver| associated frame.
+  BuildContentCaptureSession(*content_capture_receiver,
+                             false /* ancestor_only */, &session);
+  DidRemoveContent(session, data);
+}
+
+void ContentCaptureReceiverManager::DidRemoveSession(
+    ContentCaptureReceiver* content_capture_receiver) {
+  ContentCaptureSession session;
+  // The session should include the removed frame that the
+  // |content_capture_receiver| associated with.
+  BuildContentCaptureSession(*content_capture_receiver,
+                             false /* ancestor_only */, &session);
+  DidRemoveSession(session);
+}
+
+void ContentCaptureReceiverManager::BuildContentCaptureSession(
+    const ContentCaptureReceiver& content_capture_receiver,
+    bool ancestor_only,
+    ContentCaptureSession* session) {
+  if (!ancestor_only)
+    session->push_back(content_capture_receiver.frame_content_capture_data());
+
+  content::RenderFrameHost* rfh = content_capture_receiver.rfh()->GetParent();
+  while (rfh) {
+    ContentCaptureReceiver* receiver = ContentCaptureReceiverForFrame(rfh);
+    // TODO(michaelbai): Only creates ContentCaptureReceiver here, clean up the
+    // code in RenderFrameCreated().
+    if (!receiver) {
+      RenderFrameCreated(rfh);
+      receiver = ContentCaptureReceiverForFrame(rfh);
+    }
+    session->push_back(receiver->frame_content_capture_data());
+    rfh = receiver->rfh()->GetParent();
+  }
+}
+
+}  // namespace content_capture
diff --git a/components/content_capture/browser/content_capture_receiver_manager.h b/components/content_capture/browser/content_capture_receiver_manager.h
new file mode 100644
index 0000000..4ddbc8b1
--- /dev/null
+++ b/components/content_capture/browser/content_capture_receiver_manager.h
@@ -0,0 +1,89 @@
+// 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_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_RECEIVER_MANAGER_H_
+#define COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_RECEIVER_MANAGER_H_
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "base/supports_user_data.h"
+#include "components/content_capture/common/content_capture.mojom.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace content_capture {
+
+class ContentCaptureReceiver;
+
+// This class has an instance per WebContents, it is the base class of
+// ContentCaptureReceiverManager implementation which shall overrides the pure
+// virtual methods to get the messages from each receivers, this class creates
+// the ContentCaptureReceiver and associates it with RenderFrameHost, it also
+// binds ContentCaptureReceiver with its peer ContentCaptureSender in renderer.
+// The ContentSession here is used to specify which frame the message came from.
+class ContentCaptureReceiverManager : public content::WebContentsObserver,
+                                      public base::SupportsUserData::Data {
+ public:
+  ~ContentCaptureReceiverManager() override;
+  static ContentCaptureReceiverManager* FromWebContents(
+      content::WebContents* contents);
+
+  // Binds the |request| with the |render_frame_host| associated
+  // ContentCaptureReceiver.
+  static void BindContentCaptureReceiver(
+      mojom::ContentCaptureReceiverAssociatedRequest request,
+      content::RenderFrameHost* render_frame_host);
+
+  // The methods called by ContentCaptureReceiver.
+  void DidCaptureContent(ContentCaptureReceiver* content_capture_receiver,
+                         const ContentCaptureData& data);
+  void DidRemoveContent(ContentCaptureReceiver* content_capture_receiver,
+                        const std::vector<int64_t>& data);
+  void DidRemoveSession(ContentCaptureReceiver* content_capture_receiver);
+
+  // content::WebContentsObserver:
+  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
+  size_t GetFrameMapSizeForTesting() const { return frame_map_.size(); }
+
+ protected:
+  ContentCaptureReceiverManager(content::WebContents* web_contents);
+
+  // Invoked when the captured content |data| from the |parent_session| was
+  // received.
+  virtual void DidCaptureContent(const ContentCaptureSession& parent_session,
+                                 const ContentCaptureData& data) = 0;
+  // Invoked when the list of content |ids| of the given |session| was removed.
+  virtual void DidRemoveContent(const ContentCaptureSession& session,
+                                const std::vector<int64_t>& ids) = 0;
+  // Invoked when the given |session| was removed.
+  virtual void DidRemoveSession(const ContentCaptureSession& session) = 0;
+
+ private:
+  friend class ContentCaptureReceiverManagerHelper;
+
+  // Builds ContentCaptureSession and returns in |session|, |ancestor_only|
+  // specifies if only ancestor should be returned in |session|.
+  void BuildContentCaptureSession(
+      const ContentCaptureReceiver& content_capture_receiver,
+      bool ancestor_only,
+      ContentCaptureSession* session);
+
+  ContentCaptureReceiver* ContentCaptureReceiverForFrame(
+      content::RenderFrameHost* render_frame_host);
+
+  std::unordered_map<content::RenderFrameHost*,
+                     std::unique_ptr<ContentCaptureReceiver>>
+      frame_map_;
+};
+
+}  // namespace content_capture
+
+#endif  // COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_RECEIVER_MANAGER_H_
diff --git a/components/content_capture/browser/content_capture_receiver_test.cc b/components/content_capture/browser/content_capture_receiver_test.cc
new file mode 100644
index 0000000..f01eed7
--- /dev/null
+++ b/components/content_capture/browser/content_capture_receiver_test.cc
@@ -0,0 +1,356 @@
+// 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/content_capture/browser/content_capture_receiver.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "components/content_capture/browser/content_capture_receiver_manager.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content_capture {
+namespace {
+
+// Fake ContentCaptureSender to call ContentCaptureReceiver mojom interface.
+class FakeContentCaptureSender {
+ public:
+  FakeContentCaptureSender() {}
+
+  void DidCaptureContent(const ContentCaptureData& captured_content,
+                         bool first_data) {
+    content_capture_receiver_->DidCaptureContent(captured_content, first_data);
+  }
+
+  void DidRemoveContent(const std::vector<int64_t>& data) {
+    content_capture_receiver_->DidRemoveContent(data);
+  }
+
+  mojom::ContentCaptureReceiverAssociatedRequest GetAssociatedRequest() {
+    return mojo::MakeRequestAssociatedWithDedicatedPipe(
+        &content_capture_receiver_);
+  }
+
+ private:
+  mojom::ContentCaptureReceiverAssociatedPtr content_capture_receiver_ =
+      nullptr;
+};
+
+// The helper class implements ContentCaptureReceiverManager and keeps the
+// result for verification.
+class ContentCaptureReceiverManagerHelper
+    : public ContentCaptureReceiverManager {
+ public:
+  static void Create(content::WebContents* web_contents) {
+    new ContentCaptureReceiverManagerHelper(web_contents);
+  }
+
+  ContentCaptureReceiverManagerHelper(content::WebContents* web_contents)
+      : ContentCaptureReceiverManager(web_contents) {}
+
+  void DidCaptureContent(const ContentCaptureSession& parent_session,
+                         const ContentCaptureData& data) override {
+    parent_session_ = parent_session;
+    captured_data_ = data;
+  }
+
+  void DidRemoveContent(const ContentCaptureSession& session,
+                        const std::vector<int64_t>& ids) override {
+    session_ = session;
+    removed_ids_ = ids;
+  }
+
+  void DidRemoveSession(const ContentCaptureSession& data) override {
+    removed_session_ = data;
+  }
+
+  const ContentCaptureSession& parent_session() const {
+    return parent_session_;
+  }
+
+  const ContentCaptureSession& session() const { return session_; }
+
+  const ContentCaptureData& captured_data() const { return captured_data_; }
+
+  const ContentCaptureSession& removed_session() const {
+    return removed_session_;
+  }
+
+  const std::vector<int64_t>& removed_ids() const { return removed_ids_; }
+
+ private:
+  ContentCaptureSession parent_session_;
+  ContentCaptureSession session_;
+  ContentCaptureData captured_data_;
+  std::vector<int64_t> removed_ids_;
+  ContentCaptureSession removed_session_;
+};
+
+class ContentCaptureReceiverTest : public content::RenderViewHostTestHarness {
+ public:
+  void SetUp() override {
+    content::RenderViewHostTestHarness::SetUp();
+    ContentCaptureReceiverManagerHelper::Create(web_contents());
+    content_capture_receiver_manager_helper_ =
+        static_cast<ContentCaptureReceiverManagerHelper*>(
+            ContentCaptureReceiverManager::FromWebContents(web_contents()));
+    // This needed to keep the WebContentsObserverSanityChecker checks happy for
+    // when AppendChild is called.
+    NavigateAndCommit(GURL("about:blank"));
+    content_capture_sender_ = std::make_unique<FakeContentCaptureSender>();
+    main_frame_ = web_contents()->GetMainFrame();
+    // Binds sender with receiver.
+    ContentCaptureReceiverManager::BindContentCaptureReceiver(
+        content_capture_sender_->GetAssociatedRequest(), main_frame_);
+
+    ContentCaptureData child;
+    // Have the unique id for text content.
+    child.id = 2;
+    child.value = base::ASCIIToUTF16("Hello");
+    child.bounds = gfx::Rect(5, 5, 5, 5);
+    // No need to set id in sender.
+    test_data_.value = base::ASCIIToUTF16("http://foo.com/bar");
+    test_data_.bounds = gfx::Rect(10, 10);
+    test_data_.children.push_back(child);
+    test_data2_.value = base::ASCIIToUTF16("http://foo.org/bar");
+    test_data2_.bounds = gfx::Rect(10, 10);
+    test_data2_.children.push_back(child);
+  }
+
+  void TearDown() override { content::RenderViewHostTestHarness::TearDown(); }
+
+  void SetupChildFrame() {
+    child_content_capture_sender_ =
+        std::make_unique<FakeContentCaptureSender>();
+    child_frame_ =
+        content::RenderFrameHostTester::For(main_frame_)->AppendChild("child");
+    // Binds sender with receiver for child frame.
+    ContentCaptureReceiverManager::BindContentCaptureReceiver(
+        child_content_capture_sender_->GetAssociatedRequest(), child_frame_);
+  }
+
+  FakeContentCaptureSender* content_capture_sender() {
+    return content_capture_sender_.get();
+  }
+
+  FakeContentCaptureSender* child_content_capture_sender() {
+    return child_content_capture_sender_.get();
+  }
+
+  const ContentCaptureData& test_data() const { return test_data_; }
+  const ContentCaptureData& test_data2() const { return test_data2_; }
+  const std::vector<int64_t>& expected_removed_ids() const {
+    return expected_removed_ids_;
+  }
+
+  ContentCaptureData GetExpectedTestData(bool main_frame) const {
+    ContentCaptureData expected(test_data_);
+    // Replaces the id with expected id.
+    expected.id = ContentCaptureReceiver::GetIdFrom(main_frame ? main_frame_
+                                                               : child_frame_);
+    return expected;
+  }
+
+  ContentCaptureData GetExpectedTestData2(bool main_frame) const {
+    ContentCaptureData expected(test_data2_);
+    // Replaces the id with expected id.
+    expected.id = ContentCaptureReceiver::GetIdFrom(main_frame ? main_frame_
+                                                               : child_frame_);
+    return expected;
+  }
+
+  ContentCaptureReceiverManagerHelper* content_capture_receiver_manager_helper()
+      const {
+    return content_capture_receiver_manager_helper_;
+  }
+
+  void VerifySession(const ContentCaptureSession& expected,
+                     const ContentCaptureSession& result) const {
+    EXPECT_EQ(expected.size(), result.size());
+    for (size_t i = 0; i < expected.size(); i++) {
+      EXPECT_EQ(expected[i].id, result[i].id);
+      EXPECT_EQ(expected[i].value, result[i].value);
+      EXPECT_EQ(expected[i].bounds, result[i].bounds);
+    }
+  }
+
+  void DidCaptureContent(const ContentCaptureData& captured_content,
+                         bool first_data) {
+    base::RunLoop run_loop;
+    content_capture_sender()->DidCaptureContent(captured_content, first_data);
+    run_loop.RunUntilIdle();
+  }
+
+  void DidCaptureContentForChildFrame(
+      const ContentCaptureData& captured_content,
+      bool first_data) {
+    base::RunLoop run_loop;
+    child_content_capture_sender()->DidCaptureContent(captured_content,
+                                                      first_data);
+    run_loop.RunUntilIdle();
+  }
+
+  void DidRemoveContent(const std::vector<int64_t>& data) {
+    base::RunLoop run_loop;
+    content_capture_sender()->DidRemoveContent(data);
+    run_loop.RunUntilIdle();
+  }
+
+ protected:
+  ContentCaptureReceiverManagerHelper*
+      content_capture_receiver_manager_helper_ = nullptr;
+
+ private:
+  // The sender for main frame.
+  std::unique_ptr<FakeContentCaptureSender> content_capture_sender_;
+  // The sender for child frame.
+  std::unique_ptr<FakeContentCaptureSender> child_content_capture_sender_;
+  content::RenderFrameHost* main_frame_ = nullptr;
+  content::RenderFrameHost* child_frame_ = nullptr;
+  ContentCaptureData test_data_;
+  ContentCaptureData test_data2_;
+  // Expected removed Ids.
+  std::vector<int64_t> expected_removed_ids_{2};
+};
+
+TEST_F(ContentCaptureReceiverTest, DidCaptureContent) {
+  DidCaptureContent(test_data(), true /* first_data */);
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+}
+
+TEST_F(ContentCaptureReceiverTest, DidCaptureContentWithUpdate) {
+  DidCaptureContent(test_data(), true /* first_data */);
+  // Verifies to get test_data() with correct frame content id.
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+  // Simulates to update the content within the same document.
+  DidCaptureContent(test_data2(), false /* first_data */);
+  // Verifies to get test_data2() with correct frame content id.
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  // Verifies that the sesssion isn't removed.
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  EXPECT_EQ(GetExpectedTestData2(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+}
+
+TEST_F(ContentCaptureReceiverTest, DidRemoveSession) {
+  DidCaptureContent(test_data(), true /* first_data */);
+  // Verifies to get test_data() with correct frame content id.
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+  // Simulates to navigate other document.
+  DidCaptureContent(test_data2(), true /* first_data */);
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  // Verifies that the previous session was removed.
+  EXPECT_EQ(
+      1u, content_capture_receiver_manager_helper()->removed_session().size());
+  std::vector<ContentCaptureData> expected{
+      GetExpectedTestData(true /* main_frame */)};
+  VerifySession(expected,
+                content_capture_receiver_manager_helper()->removed_session());
+  // Verifies that we get the test_data2() from the new document.
+  EXPECT_EQ(GetExpectedTestData2(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+}
+
+TEST_F(ContentCaptureReceiverTest, DidRemoveContent) {
+  DidCaptureContent(test_data(), true /* first_data */);
+  // Verifies to get test_data() with correct frame content id.
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+  // Simulates to remove the content.
+  DidRemoveContent(expected_removed_ids());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  // Verifies that the removed_ids() was removed from the correct session.
+  EXPECT_EQ(expected_removed_ids(),
+            content_capture_receiver_manager_helper()->removed_ids());
+  std::vector<ContentCaptureData> expected{
+      GetExpectedTestData(true /* main_frame */)};
+  VerifySession(expected, content_capture_receiver_manager_helper()->session());
+}
+
+TEST_F(ContentCaptureReceiverTest, ChildFrameDidCaptureContent) {
+  // Simulate add child frame.
+  SetupChildFrame();
+  // Simulate to capture the content from main frame.
+  DidCaptureContent(test_data(), true /* first_data */);
+  // Verifies to get test_data() with correct frame content id.
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+  // Simulate to capture the content from child frame.
+  DidCaptureContentForChildFrame(test_data2(), true /* first_data */);
+  // Verifies that the parent_session was set correctly.
+  EXPECT_FALSE(
+      content_capture_receiver_manager_helper()->parent_session().empty());
+  std::vector<ContentCaptureData> expected{
+      GetExpectedTestData(true /* main_frame */)};
+  VerifySession(expected,
+                content_capture_receiver_manager_helper()->parent_session());
+  EXPECT_TRUE(
+      content_capture_receiver_manager_helper()->removed_session().empty());
+  // Verifies that we receive the correct content from child frame.
+  EXPECT_EQ(GetExpectedTestData2(false /* main_frame */),
+            content_capture_receiver_manager_helper()->captured_data());
+}
+
+class ContentCaptureReceiverMultipleFrameTest
+    : public ContentCaptureReceiverTest {
+ public:
+  void SetUp() override {
+    // Setup multiple frames before creates ContentCaptureReceiverManager.
+    content::RenderViewHostTestHarness::SetUp();
+    // This needed to keep the WebContentsObserverSanityChecker checks happy for
+    // when AppendChild is called.
+    NavigateAndCommit(GURL("about:blank"));
+    content::RenderFrameHostTester::For(web_contents()->GetMainFrame())
+        ->AppendChild("child");
+    ContentCaptureReceiverManagerHelper::Create(web_contents());
+    content_capture_receiver_manager_helper_ =
+        static_cast<ContentCaptureReceiverManagerHelper*>(
+            ContentCaptureReceiverManager::FromWebContents(web_contents()));
+  }
+
+  void TearDown() override { content::RenderViewHostTestHarness::TearDown(); }
+};
+
+TEST_F(ContentCaptureReceiverMultipleFrameTest,
+       ReceiverCreatedForExistingFrame) {
+  EXPECT_EQ(
+      2u,
+      content_capture_receiver_manager_helper()->GetFrameMapSizeForTesting());
+}
+}  // namespace
+}  // namespace content_capture
diff --git a/components/content_settings/core/browser/content_settings_policy_provider.cc b/components/content_settings/core/browser/content_settings_policy_provider.cc
index 99b0c54..b3784368 100644
--- a/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -322,7 +322,7 @@
       continue;
     }
 
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(
+    std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
         pattern_filter_json, base::JSON_ALLOW_TRAILING_COMMAS);
     if (!value || !value->is_dict()) {
       VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:"
diff --git a/components/cronet/native/perftest/perf_test.cc b/components/cronet/native/perftest/perf_test.cc
index c502772f..e15aa69b 100644
--- a/components/cronet/native/perftest/perf_test.cc
+++ b/components/cronet/native/perftest/perf_test.cc
@@ -405,7 +405,7 @@
   // Parse benchmark options into |g_options|.
   std::string benchmark_options = json_args;
   std::unique_ptr<base::Value> options_value =
-      base::JSONReader::Read(benchmark_options);
+      base::JSONReader::ReadDeprecated(benchmark_options);
   CHECK(options_value) << "Parsing benchmark options failed: "
                        << benchmark_options;
   g_options = base::DictionaryValue::From(std::move(options_value));
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 5cd76c44..9bb914b 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -293,7 +293,7 @@
 
   DVLOG(1) << "Experimental Options:" << experimental_options;
   std::unique_ptr<base::Value> options =
-      base::JSONReader::Read(experimental_options);
+      base::JSONReader::ReadDeprecated(experimental_options);
 
   if (!options) {
     DCHECK(false) << "Parsing experimental options failed: "
diff --git a/components/dom_distiller/core/page_features.cc b/components/dom_distiller/core/page_features.cc
index a222bd3f..6de750f 100644
--- a/components/dom_distiller/core/page_features.cc
+++ b/components/dom_distiller/core/page_features.cc
@@ -152,7 +152,8 @@
     return std::vector<double>();
   }
 
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(stringified);
+  std::unique_ptr<base::Value> json =
+      base::JSONReader::ReadDeprecated(stringified);
   if (!json) {
     return std::vector<double>();
   }
diff --git a/components/dom_distiller/core/page_features_unittest.cc b/components/dom_distiller/core/page_features_unittest.cc
index 93795c3..4efa8dd4 100644
--- a/components/dom_distiller/core/page_features_unittest.cc
+++ b/components/dom_distiller/core/page_features_unittest.cc
@@ -38,11 +38,12 @@
           "components/test/data/dom_distiller/derived_features.json"),
       &expected_output_data));
 
-  std::unique_ptr<base::Value> input_json = base::JSONReader::Read(input_data);
+  std::unique_ptr<base::Value> input_json =
+      base::JSONReader::ReadDeprecated(input_data);
   ASSERT_TRUE(input_json);
 
   std::unique_ptr<base::Value> expected_output_json =
-      base::JSONReader::Read(expected_output_data);
+      base::JSONReader::ReadDeprecated(expected_output_data);
   ASSERT_TRUE(expected_output_json);
 
   base::ListValue* input_entries;
diff --git a/components/domain_reliability/config.cc b/components/domain_reliability/config.cc
index 5f5ba2e2..5c03e83 100644
--- a/components/domain_reliability/config.cc
+++ b/components/domain_reliability/config.cc
@@ -50,7 +50,7 @@
 // static
 std::unique_ptr<const DomainReliabilityConfig>
 DomainReliabilityConfig::FromJSON(const base::StringPiece& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   base::JSONValueConverter<DomainReliabilityConfig> converter;
   std::unique_ptr<DomainReliabilityConfig> config(
       new DomainReliabilityConfig());
diff --git a/components/domain_reliability/context_unittest.cc b/components/domain_reliability/context_unittest.cc
index 62f5dae7..b5b3c09 100644
--- a/components/domain_reliability/context_unittest.cc
+++ b/components/domain_reliability/context_unittest.cc
@@ -301,7 +301,8 @@
   EXPECT_EQ(0, upload_max_depth());
   EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(upload_report());
+  std::unique_ptr<Value> value =
+      base::JSONReader::ReadDeprecated(upload_report());
   const DictionaryValue* entry;
   ASSERT_TRUE(GetEntryFromReport(value.get(), 0, &entry));
   EXPECT_TRUE(HasStringValue(*entry, "failure_data.custom_error",
@@ -358,7 +359,8 @@
   EXPECT_EQ(0, upload_max_depth());
   EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(upload_report());
+  std::unique_ptr<Value> value =
+      base::JSONReader::ReadDeprecated(upload_report());
   const DictionaryValue* entry;
   ASSERT_TRUE(GetEntryFromReport(value.get(), 0, &entry));
   EXPECT_TRUE(HasBooleanValue(*entry, "network_changed", true));
@@ -388,7 +390,8 @@
   EXPECT_EQ(0, upload_max_depth());
   EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(upload_report());
+  std::unique_ptr<Value> value =
+      base::JSONReader::ReadDeprecated(upload_report());
   const DictionaryValue* entry;
   ASSERT_TRUE(GetEntryFromReport(value.get(), 0, &entry));
 
@@ -421,7 +424,8 @@
   EXPECT_EQ(0, upload_max_depth());
   EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(upload_report());
+  std::unique_ptr<Value> value =
+      base::JSONReader::ReadDeprecated(upload_report());
   const DictionaryValue* entry;
   ASSERT_TRUE(GetEntryFromReport(value.get(), 0, &entry));
 
@@ -455,7 +459,8 @@
   EXPECT_EQ(0, upload_max_depth());
   EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(upload_report());
+  std::unique_ptr<Value> value =
+      base::JSONReader::ReadDeprecated(upload_report());
   const DictionaryValue* entry;
   ASSERT_TRUE(GetEntryFromReport(value.get(), 0, &entry));
   EXPECT_TRUE(HasBooleanValue(*entry, "quic_broken", true));
@@ -500,7 +505,8 @@
   EXPECT_EQ(0, upload_max_depth());
   EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(upload_report());
+  std::unique_ptr<Value> value =
+      base::JSONReader::ReadDeprecated(upload_report());
   const DictionaryValue* entry;
   ASSERT_TRUE(GetEntryFromReport(value.get(), 0, &entry));
   EXPECT_TRUE(HasDoubleValue(*entry, "sample_rate", 0.5));
diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc
index 13a89fb1..58653ee 100644
--- a/components/download/content/internal/download_driver_impl.cc
+++ b/components/download/content/internal/download_driver_impl.cc
@@ -5,11 +5,13 @@
 #include "components/download/content/internal/download_driver_impl.h"
 
 #include <set>
+#include <string>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/download/internal/background_service/driver_entry.h"
@@ -99,6 +101,13 @@
         !item->GetETag().empty() || !item->GetLastModifiedTime().empty();
   }
   entry.url_chain = item->GetUrlChain();
+
+  if (item->GetState() == DownloadItem::DownloadState::COMPLETE) {
+    std::string hash = item->GetHash();
+    if (!hash.empty())
+      entry.hash256 = base::HexEncode(hash.data(), hash.size());
+  }
+
   return entry;
 }
 
diff --git a/components/download/content/internal/download_driver_impl_unittest.cc b/components/download/content/internal/download_driver_impl_unittest.cc
index 3e8bbd1..8cbe2b4 100644
--- a/components/download/content/internal/download_driver_impl_unittest.cc
+++ b/components/download/content/internal/download_driver_impl_unittest.cc
@@ -39,9 +39,12 @@
 // driver entry.
 MATCHER_P(DriverEntryEqual, entry, "") {
   return entry.guid == arg.guid && entry.state == arg.state &&
-         entry.done == arg.done &&
+         entry.done == arg.done && entry.can_resume == arg.can_resume &&
          entry.bytes_downloaded == arg.bytes_downloaded &&
-         entry.current_file_path.value() == arg.current_file_path.value();
+         entry.expected_total_size == arg.expected_total_size &&
+         entry.current_file_path.value() == arg.current_file_path.value() &&
+         entry.completion_time == arg.completion_time &&
+         entry.hash256 == arg.hash256;
 }
 
 }  // namespace
@@ -162,6 +165,7 @@
 
   fake_item.SetReceivedBytes(1024);
   fake_item.SetState(DownloadState::COMPLETE);
+  fake_item.SetHash("01234567ABCDEF");
   entry = DownloadDriverImpl::CreateDriverEntry(&fake_item);
   EXPECT_CALL(mock_client_, OnDownloadSucceeded(DriverEntryEqual(entry)))
       .Times(1)
diff --git a/components/download/internal/background_service/controller_impl.cc b/components/download/internal/background_service/controller_impl.cc
index 18de3f0..3c76cce 100644
--- a/components/download/internal/background_service/controller_impl.cc
+++ b/components/download/internal/background_service/controller_impl.cc
@@ -1152,6 +1152,7 @@
     DCHECK(driver_entry.has_value());
     stats::LogFilePathRenamed(driver_entry->current_file_path !=
                               entry->target_file_path);
+    stats::LogHashPresence(!driver_entry->hash256.empty());
     entry->target_file_path = driver_entry->current_file_path;
     entry->completion_time = driver_entry->completion_time;
     entry->bytes_downloaded = driver_entry->bytes_downloaded;
@@ -1159,6 +1160,7 @@
                                    driver_entry->bytes_downloaded,
                                    entry->url_chain, entry->response_headers);
     completion_info.blob_handle = driver_entry->blob_handle;
+    completion_info.hash256 = driver_entry->hash256;
 
     entry->last_cleanup_check_time = driver_entry->completion_time;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/components/download/internal/background_service/controller_impl_unittest.cc b/components/download/internal/background_service/controller_impl_unittest.cc
index d934125..0cd66071 100644
--- a/components/download/internal/background_service/controller_impl_unittest.cc
+++ b/components/download/internal/background_service/controller_impl_unittest.cc
@@ -1010,6 +1010,7 @@
   CompletionInfo completion_info(dentry.current_file_path,
                                  dentry.bytes_downloaded, entry.url_chain,
                                  entry.response_headers);
+  completion_info.hash256 = "01234567ABCDEF";
   EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1);
   EXPECT_CALL(*client_, OnDownloadSucceeded(entry.guid, completion_info))
       .Times(1);
@@ -1026,6 +1027,7 @@
   done_dentry.done = true;
   done_dentry.current_file_path = completion_info.path;
   done_dentry.bytes_downloaded = completion_info.bytes_downloaded;
+  done_dentry.hash256 = completion_info.hash256;
   base::Time now = base::Time::Now();
   done_dentry.completion_time = now;
 
@@ -1042,7 +1044,7 @@
   EXPECT_EQ(now, updated_entry->completion_time);
   EXPECT_LE(done_dentry.completion_time + config_->file_keep_alive_time,
             now + base::TimeDelta::FromSeconds(start_time));
-
+  EXPECT_EQ(completion_info.hash256, done_dentry.hash256);
   task_runner_->RunUntilIdle();
 }
 
@@ -1050,16 +1052,22 @@
   // Create initial Entry and DriverEntry objects.
   Entry succeeded_entry = test::BuildBasicEntry(Entry::State::ACTIVE);
   ASSERT_TRUE(succeeded_entry.response_headers);
+  Entry succeeded_with_hash_entry = test::BuildBasicEntry(Entry::State::ACTIVE);
+  ASSERT_TRUE(succeeded_with_hash_entry.response_headers);
   Entry failed_entry = test::BuildBasicEntry(Entry::State::ACTIVE);
   ASSERT_TRUE(failed_entry.response_headers);
-  std::vector<Entry> entries = {succeeded_entry, failed_entry};
+  std::vector<Entry> entries = {succeeded_entry, succeeded_with_hash_entry,
+                                failed_entry};
 
   DriverEntry succeeded_dentry =
       BuildDriverEntry(succeeded_entry, DriverEntry::State::IN_PROGRESS);
+  DriverEntry succeeded_with_hash_dentry = BuildDriverEntry(
+      succeeded_with_hash_entry, DriverEntry::State::IN_PROGRESS);
   DriverEntry failed_dentry =
       BuildDriverEntry(failed_entry, DriverEntry::State::IN_PROGRESS);
-  driver_->AddTestData(
-      std::vector<DriverEntry>{succeeded_dentry, failed_dentry});
+
+  driver_->AddTestData(std::vector<DriverEntry>{
+      succeeded_dentry, succeeded_with_hash_dentry, failed_dentry});
 
   // Mock expectations.
   EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1);
@@ -1068,6 +1076,10 @@
   EXPECT_CALL(*client_, OnDownloadSucceeded(succeeded_entry.guid, _))
       .WillOnce(SaveArg<1>(&succeeded_completion_info));
 
+  CompletionInfo succeeded_with_hash_completion_info;
+  EXPECT_CALL(*client_, OnDownloadSucceeded(succeeded_with_hash_entry.guid, _))
+      .WillOnce(SaveArg<1>(&succeeded_with_hash_completion_info));
+
   CompletionInfo failed_completion_info;
   EXPECT_CALL(*client_, OnDownloadFailed(failed_entry.guid, _, _))
       .WillOnce(SaveArg<1>(&failed_completion_info));
@@ -1084,6 +1096,13 @@
   succeeded_done_dentry.current_file_path =
       base::FilePath::FromUTF8Unsafe("abc");
 
+  DriverEntry succeeded_with_hash_done_dentry =
+      BuildDriverEntry(succeeded_with_hash_entry, DriverEntry::State::COMPLETE);
+  succeeded_with_hash_done_dentry.done = true;
+  succeeded_with_hash_done_dentry.current_file_path =
+      base::FilePath::FromUTF8Unsafe("abc");
+  succeeded_with_hash_done_dentry.hash256 = "01234567ABCDEF";
+
   DriverEntry failed_done_dentry =
       BuildDriverEntry(failed_entry, DriverEntry::State::COMPLETE);
   succeeded_done_dentry.current_file_path =
@@ -1091,6 +1110,7 @@
   failed_done_dentry.done = true;
 
   driver_->NotifyDownloadSucceeded(succeeded_done_dentry);
+  driver_->NotifyDownloadSucceeded(succeeded_with_hash_done_dentry);
   driver_->NotifyDownloadFailed(failed_done_dentry,
                                 FailureType::NOT_RECOVERABLE);
   task_runner_->RunUntilIdle();
@@ -1101,6 +1121,15 @@
             succeeded_entry.response_headers->raw_headers());
   EXPECT_EQ(succeeded_completion_info.path,
             succeeded_done_dentry.current_file_path);
+  EXPECT_EQ(succeeded_completion_info.hash256, "");
+
+  ASSERT_TRUE(succeeded_with_hash_completion_info.response_headers);
+  EXPECT_EQ(succeeded_with_hash_completion_info.response_headers->raw_headers(),
+            succeeded_with_hash_entry.response_headers->raw_headers());
+  EXPECT_EQ(succeeded_with_hash_completion_info.path,
+            succeeded_with_hash_done_dentry.current_file_path);
+  EXPECT_EQ(succeeded_with_hash_completion_info.hash256,
+            succeeded_with_hash_done_dentry.hash256);
 
   ASSERT_TRUE(failed_completion_info.response_headers);
   EXPECT_EQ(failed_completion_info.response_headers->raw_headers(),
diff --git a/components/download/internal/background_service/debugging_client.cc b/components/download/internal/background_service/debugging_client.cc
index ced5d313a..9bc4298 100644
--- a/components/download/internal/background_service/debugging_client.cc
+++ b/components/download/internal/background_service/debugging_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "components/download/public/background_service/download_metadata.h"
 #include "services/network/public/cpp/resource_request_body.h"
 
 namespace download {
diff --git a/components/download/internal/background_service/driver_entry.h b/components/download/internal/background_service/driver_entry.h
index 170279b..cf3f9739 100644
--- a/components/download/internal/background_service/driver_entry.h
+++ b/components/download/internal/background_service/driver_entry.h
@@ -82,6 +82,10 @@
   // The url chain of the download. Download may encounter redirects, and
   // fetches the content from the last url in the chain.
   std::vector<GURL> url_chain;
+
+  // An optional base::HexEncoded SHA-256 hash (if available) of the file
+  // contents.  If empty there is no available hash value.
+  std::string hash256;
 };
 
 }  // namespace download
diff --git a/components/download/internal/background_service/stats.cc b/components/download/internal/background_service/stats.cc
index fc489146..a5062f3 100644
--- a/components/download/internal/background_service/stats.cc
+++ b/components/download/internal/background_service/stats.cc
@@ -396,5 +396,9 @@
   base::UmaHistogramBoolean(name, has_upload_data);
 }
 
+void LogHashPresence(bool hash_exists) {
+  UMA_HISTOGRAM_BOOLEAN("Download.Service.Finish.ReportedHash", hash_exists);
+}
+
 }  // namespace stats
 }  // namespace download
diff --git a/components/download/internal/background_service/stats.h b/components/download/internal/background_service/stats.h
index 11100e1..49de816 100644
--- a/components/download/internal/background_service/stats.h
+++ b/components/download/internal/background_service/stats.h
@@ -227,6 +227,9 @@
 // Records whether the entry was an upload.
 void LogHasUploadData(DownloadClient client, bool has_upload_data);
 
+// Records whether or not a completed entry has a hash value.
+void LogHashPresence(bool hash_exists);
+
 }  // namespace stats
 }  // namespace download
 
diff --git a/components/download/public/background_service/download_metadata.cc b/components/download/public/background_service/download_metadata.cc
index 0d869c66..100a49d 100644
--- a/components/download/public/background_service/download_metadata.cc
+++ b/components/download/public/background_service/download_metadata.cc
@@ -42,7 +42,8 @@
   return path == other.path && bytes_downloaded == other.bytes_downloaded &&
          url_chain == other.url_chain &&
          AreResponseHeadersEqual(response_headers.get(),
-                                 other.response_headers.get());
+                                 other.response_headers.get()) &&
+         hash256 == other.hash256;
 }
 
 DownloadMetaData::DownloadMetaData() : current_size(0u), paused(false) {}
diff --git a/components/download/public/background_service/download_metadata.h b/components/download/public/background_service/download_metadata.h
index 80900c2..cddd230 100644
--- a/components/download/public/background_service/download_metadata.h
+++ b/components/download/public/background_service/download_metadata.h
@@ -40,6 +40,10 @@
   // account changed values during retries/resumptions.
   scoped_refptr<const net::HttpResponseHeaders> response_headers;
 
+  // An optional base::HexEncoded SHA-256 hash (if available) of the file
+  // contents.  If empty there is no available hash value.
+  std::string hash256;
+
   CompletionInfo();
   CompletionInfo(
       const base::FilePath& path,
diff --git a/components/exo/wayland/zcr_keyboard_configuration.cc b/components/exo/wayland/zcr_keyboard_configuration.cc
index 1aee392..d986c54 100644
--- a/components/exo/wayland/zcr_keyboard_configuration.cc
+++ b/components/exo/wayland/zcr_keyboard_configuration.cc
@@ -24,7 +24,7 @@
 // Send a keyboard layout name instead of XKB contents.
 // TODO(tetsui): Remove when the change becomes default.
 const base::Feature kSendKeyboardLayoutNameFeature{
-    "ExoSendKeyboardLayoutName", base::FEATURE_DISABLED_BY_DEFAULT};
+    "ExoSendKeyboardLayoutName", base::FEATURE_ENABLED_BY_DEFAULT};
 
 ////////////////////////////////////////////////////////////////////////////////
 // keyboard_device_configuration interface:
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
index 2bb5b14e..ed1b680c 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
@@ -93,11 +93,6 @@
     public static final String PREVIEWS_PAGE_LOADED = "preview_page_load";
 
     /**
-     * The download button for a media element was displayed.
-     */
-    public static final String MEDIA_DOWNLOAD_BUTTON_DISPLAYED = "media_download_button_displayed";
-
-    /**
      * Contextual Search panel was opened.
      */
     public static final String CONTEXTUAL_SEARCH_PANEL_OPENED = "contextual_search_panel_opened";
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
index 8e4cd7e..530f0bd 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
@@ -22,8 +22,6 @@
     public static final String PREVIEWS_OMNIBOX_UI_FEATURE = "IPH_PreviewsOmniboxUI";
     public static final String HOMEPAGE_TILE_FEATURE = "IPH_HomepageTile";
 
-    public static final String MEDIA_DOWNLOAD_FEATURE = "IPH_MediaDownload";
-
     public static final String TRANSLATE_MENU_BUTTON_FEATURE = "IPH_TranslateMenuButton";
 
     /**
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 2a70eed..01e6c16 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -31,8 +31,6 @@
     "IPH_ChromeHomeExpand", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHChromeHomePullToRefreshFeature{
     "IPH_ChromeHomePullToRefresh", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kIPHMediaDownloadFeature{"IPH_MediaDownload",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHContextualSearchWebSearchFeature{
     "IPH_ContextualSearchWebSearch", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHContextualSearchPromoteTapFeature{
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index 3fa6fec..d086149 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -29,7 +29,6 @@
 extern const base::Feature kIPHChromeDuetFeature;
 extern const base::Feature kIPHChromeHomeExpandFeature;
 extern const base::Feature kIPHChromeHomePullToRefreshFeature;
-extern const base::Feature kIPHMediaDownloadFeature;
 extern const base::Feature kIPHContextualSearchWebSearchFeature;
 extern const base::Feature kIPHContextualSearchPromoteTapFeature;
 extern const base::Feature kIPHContextualSearchPromotePanelOpenFeature;
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index 0d53df5..eb0a15a 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -25,7 +25,6 @@
     &kIPHChromeDuetFeature,
     &kIPHChromeHomeExpandFeature,
     &kIPHChromeHomePullToRefreshFeature,
-    &kIPHMediaDownloadFeature,
     &kIPHContextualSearchWebSearchFeature,
     &kIPHContextualSearchPromoteTapFeature,
     &kIPHContextualSearchPromotePanelOpenFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index b444357..7a2bf57 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -57,7 +57,6 @@
 DEFINE_VARIATION_PARAM(kIPHChromeHomeExpandFeature, "IPH_ChromeHomeExpand");
 DEFINE_VARIATION_PARAM(kIPHChromeHomePullToRefreshFeature,
                        "IPH_ChromeHomePullToRefresh");
-DEFINE_VARIATION_PARAM(kIPHMediaDownloadFeature, "IPH_MediaDownload");
 DEFINE_VARIATION_PARAM(kIPHContextualSearchWebSearchFeature,
                        "IPH_ContextualSearchWebSearch");
 DEFINE_VARIATION_PARAM(kIPHContextualSearchPromoteTapFeature,
@@ -111,7 +110,6 @@
         VARIATION_ENTRY(kIPHChromeDuetFeature),
         VARIATION_ENTRY(kIPHChromeHomeExpandFeature),
         VARIATION_ENTRY(kIPHChromeHomePullToRefreshFeature),
-        VARIATION_ENTRY(kIPHMediaDownloadFeature),
         VARIATION_ENTRY(kIPHContextualSearchWebSearchFeature),
         VARIATION_ENTRY(kIPHContextualSearchPromoteTapFeature),
         VARIATION_ENTRY(kIPHContextualSearchPromotePanelOpenFeature),
diff --git a/components/google/core/browser/google_util_unittest.cc b/components/google/core/browser/google_util_unittest.cc
index a6ef4c5..fa41784 100644
--- a/components/google/core/browser/google_util_unittest.cc
+++ b/components/google/core/browser/google_util_unittest.cc
@@ -448,3 +448,29 @@
                                   google_util::DISALLOW_SUBDOMAIN,
                                   google_util::DISALLOW_NON_STANDARD_PORTS));
 }
+
+TEST(GoogleUtilTest, GoogleAssociatedDomains) {
+  EXPECT_FALSE(google_util::IsGoogleAssociatedDomainUrl(GURL()));
+
+  EXPECT_FALSE(google_util::IsGoogleAssociatedDomainUrl(GURL("invalid")));
+
+  EXPECT_FALSE(
+      google_util::IsGoogleAssociatedDomainUrl(GURL("https://myblog.com.au")));
+
+  // A typical URL for a Google production API.
+  EXPECT_TRUE(google_util::IsGoogleAssociatedDomainUrl(
+      GURL("https://myapi-pa.googleapis.com/v1/myservice")));
+
+  // A typical URL for a test instance of a Google API.
+  EXPECT_TRUE(google_util::IsGoogleAssociatedDomainUrl(
+      GURL("https://daily0-myapi-pa.sandbox.googleapis.com/v1/myservice")));
+
+  // A Google production API with parameters.
+  EXPECT_TRUE(google_util::IsGoogleAssociatedDomainUrl(
+      GURL("https://myapi-pa.googleapis.com/v1/myservice?k1=v1&k2=v2")));
+
+  // A Google test API with parameters.
+  EXPECT_TRUE(google_util::IsGoogleAssociatedDomainUrl(
+      GURL("https://daily0-myapi-pa.sandbox.googleapis.com/v1/"
+           "myservice?k1=v1&k2=v2")));
+}
diff --git a/components/heap_profiling/test_driver.cc b/components/heap_profiling/test_driver.cc
index 6799497c..d8f146e 100644
--- a/components/heap_profiling/test_driver.cc
+++ b/components/heap_profiling/test_driver.cc
@@ -631,7 +631,7 @@
   }
 
   std::unique_ptr<base::Value> dump_json =
-      base::JSONReader::Read(serialized_trace_);
+      base::JSONReader::ReadDeprecated(serialized_trace_);
   if (!dump_json) {
     LOG(ERROR) << "Failed to deserialize trace.";
     return false;
diff --git a/components/history/core/browser/expire_history_backend.cc b/components/history/core/browser/expire_history_backend.cc
index ca3a6160..631b25a2ac 100644
--- a/components/history/core/browser/expire_history_backend.cc
+++ b/components/history/core/browser/expire_history_backend.cc
@@ -19,6 +19,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/sequenced_task_runner.h"
+#include "base/stl_util.h"
 #include "build/build_config.h"
 #include "components/history/core/browser/history_backend_client.h"
 #include "components/history/core/browser/history_backend_notifier.h"
@@ -212,10 +213,8 @@
     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());
+      base::EraseIf(visits_to_delete,
+                    [=](auto& v) { return v.visit_time > end_time; });
     }
     DeleteVisitRelatedInfo(visits_to_delete, &effects);
 
diff --git a/components/history/core/browser/web_history_service.cc b/components/history/core/browser/web_history_service.cc
index 7e7b4e5..13b8ffb 100644
--- a/components/history/core/browser/web_history_service.cc
+++ b/components/history/core/browser/web_history_service.cc
@@ -383,7 +383,7 @@
   std::unique_ptr<base::DictionaryValue> result;
   if (request->GetResponseCode() == net::HTTP_OK) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(request->GetResponseBody());
+        base::JSONReader::ReadDeprecated(request->GetResponseBody());
     if (value && value->is_dict())
       result.reset(static_cast<base::DictionaryValue*>(value.release()));
     else
diff --git a/components/invalidation/impl/json_unsafe_parser.cc b/components/invalidation/impl/json_unsafe_parser.cc
index 8ff09b9b..8f72ad6 100644
--- a/components/invalidation/impl/json_unsafe_parser.cc
+++ b/components/invalidation/impl/json_unsafe_parser.cc
@@ -25,7 +25,7 @@
             std::string error_msg;
             int error_line, error_column;
             std::unique_ptr<base::Value> value =
-                base::JSONReader::ReadAndReturnError(
+                base::JSONReader::ReadAndReturnErrorDeprecated(
                     unsafe_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
                     &error_msg, &error_line, &error_column);
             if (value) {
diff --git a/components/invalidation/impl/p2p_invalidator.cc b/components/invalidation/impl/p2p_invalidator.cc
index 80a92d66..cddac79 100644
--- a/components/invalidation/impl/p2p_invalidator.cc
+++ b/components/invalidation/impl/p2p_invalidator.cc
@@ -114,7 +114,8 @@
 }
 
 bool P2PNotificationData::ResetFromString(const std::string& str) {
-  std::unique_ptr<base::Value> data_value = base::JSONReader::Read(str);
+  std::unique_ptr<base::Value> data_value =
+      base::JSONReader::ReadDeprecated(str);
   const base::DictionaryValue* data_dict = nullptr;
   if (!data_value || !data_value->GetAsDictionary(&data_dict)) {
     LOG(WARNING) << "Could not parse " << str << " as a dictionary";
diff --git a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
index bc8b27d..d0973fa 100644
--- a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
@@ -31,7 +31,8 @@
 using testing::SaveArg;
 
 MATCHER_P(EqualsJSON, json, "equals JSON") {
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(json);
   if (!expected) {
     *result_listener << "INTERNAL ERROR: couldn't parse expected JSON";
     return false;
@@ -39,8 +40,9 @@
 
   std::string err_msg;
   int err_line, err_col;
-  std::unique_ptr<base::Value> actual = base::JSONReader::ReadAndReturnError(
-      arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
+  std::unique_ptr<base::Value> actual =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
   if (!actual) {
     *result_listener << "input:" << err_line << ":" << err_col << ": "
                      << "parse error: " << err_msg;
diff --git a/components/language/core/browser/heuristic_language_model_unittest.cc b/components/language/core/browser/heuristic_language_model_unittest.cc
index 3021ae1..073ea950 100644
--- a/components/language/core/browser/heuristic_language_model_unittest.cc
+++ b/components/language/core/browser/heuristic_language_model_unittest.cc
@@ -341,7 +341,8 @@
 
 // Test with no ULP languages.
 TEST(GetUlpLanguagesTest, Empty) {
-  const auto dict = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto dict =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "confidence": 1.0,
       "preference": []
@@ -353,7 +354,8 @@
 
 // Test that ULP profile of insufficient confidence is ignored.
 TEST(GetUlpLanguagesTest, ConfidenceCutoff) {
-  const auto dict = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto dict =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "confidence": 0.5,
       "preference": [{"language": "en", "probability": 1.0}]
@@ -367,7 +369,8 @@
 
 // Test that ULP languages of insufficient probability are ignored.
 TEST(GetUlpLanguagesTest, ProbabilityCutoff) {
-  const auto dict = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto dict =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "confidence": 1.0,
       "preference": [{"language": "en", "probability": 1.00},
@@ -389,24 +392,28 @@
 
 // Test that malformed ULP data is handled gracefully.
 TEST(GetUlpLanguagesTest, Malformed) {
-  const auto empty = base::DictionaryValue::From(base::JSONReader::Read("{}"));
+  const auto empty =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated("{}"));
   EXPECT_THAT(GetUlpLanguages(0.0, 0.0, empty.get()), IsEmpty());
 
-  const auto conf = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto conf =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "preference": [{"language": "en", "probability": 1.00}]
     }
   })"));
   EXPECT_THAT(GetUlpLanguages(0.0, 0.0, conf.get()), IsEmpty());
 
-  const auto no_prefs = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto no_prefs =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "confidence": 1.0
     }
   })"));
   EXPECT_THAT(GetUlpLanguages(0.0, 0.0, no_prefs.get()), IsEmpty());
 
-  const auto bad_prefs = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto bad_prefs =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "confidence": 1.0,
       "preference": [{"language": "en"}, {"probability": 1.0},
@@ -439,7 +446,8 @@
 
   // Set up ULP languages.
   registry->RegisterDictionaryPref(ulp_pref);
-  const auto ulp_value = base::DictionaryValue::From(base::JSONReader::Read(R"({
+  const auto ulp_value =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(R"({
     "reading": {
       "confidence": 1.0,
       "preference": [{"language": "en-US", "probability": 1.0}]
diff --git a/components/mirroring/service/receiver_response.cc b/components/mirroring/service/receiver_response.cc
index 6feff42..6e15a03 100644
--- a/components/mirroring/service/receiver_response.cc
+++ b/components/mirroring/service/receiver_response.cc
@@ -138,7 +138,8 @@
     ReceiverResponse&& receiver_response) = default;
 
 bool ReceiverResponse::Parse(const std::string& message_data) {
-  std::unique_ptr<base::Value> raw_value = base::JSONReader::Read(message_data);
+  std::unique_ptr<base::Value> raw_value =
+      base::JSONReader::ReadDeprecated(message_data);
   if (!raw_value || !raw_value->is_dict() ||
       !GetInt(*raw_value, "sessionId", &session_id) ||
       !GetInt(*raw_value, "seqNum", &sequence_number) ||
diff --git a/components/mirroring/service/receiver_response_unittest.cc b/components/mirroring/service/receiver_response_unittest.cc
index 807a683..1151046 100644
--- a/components/mirroring/service/receiver_response_unittest.cc
+++ b/components/mirroring/service/receiver_response_unittest.cc
@@ -106,7 +106,7 @@
   EXPECT_EQ(42, response.error->code);
   EXPECT_EQ("it is broke", response.error->description);
   std::unique_ptr<base::Value> parsed_details =
-      base::JSONReader::Read(response.error->details);
+      base::JSONReader::ReadDeprecated(response.error->details);
   ASSERT_TRUE(parsed_details && parsed_details->is_dict());
   EXPECT_EQ(2u, parsed_details->DictSize());
   int fool_value = 0;
diff --git a/components/mirroring/service/session_monitor.cc b/components/mirroring/service/session_monitor.cc
index 4e726f4..b0fa6b6 100644
--- a/components/mirroring/service/session_monitor.cc
+++ b/components/mirroring/service/session_monitor.cc
@@ -47,7 +47,8 @@
                             base::Value* tags,
                             std::string* receiver_name) {
   DCHECK(tags);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response);
 
   std::string build_version;
   bool is_connected = false;
diff --git a/components/mirroring/service/session_monitor_unittest.cc b/components/mirroring/service/session_monitor_unittest.cc
index 4611cb2..ead8561 100644
--- a/components/mirroring/service/session_monitor_unittest.cc
+++ b/components/mirroring/service/session_monitor_unittest.cc
@@ -186,7 +186,7 @@
 
   base::Value ReadStats(const std::string& stats_string) {
     std::unique_ptr<base::Value> stats_ptr =
-        base::JSONReader::Read(stats_string);
+        base::JSONReader::ReadDeprecated(stats_string);
     EXPECT_TRUE(stats_ptr);
     base::Value stats = base::Value::FromUniquePtrValue(std::move(stats_ptr));
     EXPECT_TRUE(stats.is_list());
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc
index 72bd6d5..5cf0f03 100644
--- a/components/mirroring/service/session_unittest.cc
+++ b/components/mirroring/service/session_unittest.cc
@@ -99,7 +99,7 @@
     EXPECT_TRUE(message->message_namespace == mojom::kWebRtcNamespace ||
                 message->message_namespace == mojom::kRemotingNamespace);
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(message->json_format_data);
+        base::JSONReader::ReadDeprecated(message->json_format_data);
     ASSERT_TRUE(value);
     std::string message_type;
     EXPECT_TRUE(GetString(*value, "type", &message_type));
diff --git a/components/mirroring/service/wifi_status_monitor_unittest.cc b/components/mirroring/service/wifi_status_monitor_unittest.cc
index d298cf5..8fd597a6 100644
--- a/components/mirroring/service/wifi_status_monitor_unittest.cc
+++ b/components/mirroring/service/wifi_status_monitor_unittest.cc
@@ -30,7 +30,7 @@
 std::string GetMessageType(const CastMessage& message) {
   std::string type;
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(message.json_format_data);
+      base::JSONReader::ReadDeprecated(message.json_format_data);
   EXPECT_TRUE(value);
   EXPECT_TRUE(GetString(*value, "type", &type));
   return type;
diff --git a/components/nacl/renderer/json_manifest.cc b/components/nacl/renderer/json_manifest.cc
index 5fccd15..e561702 100644
--- a/components/nacl/renderer/json_manifest.cc
+++ b/components/nacl/renderer/json_manifest.cc
@@ -415,9 +415,10 @@
 
   int json_read_error_code;
   std::string json_read_error_msg;
-  std::unique_ptr<base::Value> json_data(base::JSONReader::ReadAndReturnError(
-      manifest_json_data, base::JSON_PARSE_RFC, &json_read_error_code,
-      &json_read_error_msg));
+  std::unique_ptr<base::Value> json_data(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          manifest_json_data, base::JSON_PARSE_RFC, &json_read_error_code,
+          &json_read_error_msg));
   if (!json_data) {
     error_info->error = PP_NACL_ERROR_MANIFEST_PARSING;
     error_info->string =
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc
index 5ba429e..33e191f 100644
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -1246,7 +1246,7 @@
   int json_read_error_code;
   std::string json_read_error_msg;
   std::unique_ptr<base::DictionaryValue> json_dict(
-      base::DictionaryValue::From(json_reader.ReadAndReturnError(
+      base::DictionaryValue::From(json_reader.ReadAndReturnErrorDeprecated(
           buffer.get(), base::JSON_PARSE_RFC, &json_read_error_code,
           &json_read_error_msg)));
   if (!json_dict) {
diff --git a/components/net_log/net_export_file_writer_unittest.cc b/components/net_log/net_export_file_writer_unittest.cc
index b67b6da..f5e6d3d 100644
--- a/components/net_log/net_export_file_writer_unittest.cc
+++ b/components/net_log/net_export_file_writer_unittest.cc
@@ -178,7 +178,8 @@
     return ::testing::AssertionFailure()
            << log_path.value() << " could not be read.";
   }
-  *root = base::DictionaryValue::From(base::JSONReader::Read(log_string));
+  *root =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(log_string));
   if (!*root) {
     return ::testing::AssertionFailure()
            << "Contents of " << log_path.value()
diff --git a/components/network_time/network_time_tracker.cc b/components/network_time/network_time_tracker.cc
index 1d6d1e7..c4d92f26c 100644
--- a/components/network_time/network_time_tracker.cc
+++ b/components/network_time/network_time_tracker.cc
@@ -514,7 +514,7 @@
     return false;
   }
   data = data.substr(5);  // Skips leading )]}'\n
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value) {
     DVLOG(1) << "bad JSON";
     RecordFetchValidHistogram(false);
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc
index e156aa57..40dcaf63 100644
--- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc
+++ b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc
@@ -195,7 +195,7 @@
     const BreakingNewsGCMAppHandler::SuccessCallback& success_callback,
     const BreakingNewsGCMAppHandler::ErrorCallback& error_callback) {
   base::JSONReader json_reader;
-  std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
+  std::unique_ptr<base::Value> value = json_reader.ReadToValueDeprecated(json);
   if (value) {
     success_callback.Run(std::move(value));
   } else {
diff --git a/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc b/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc
index 0b84b66..2f09e91 100644
--- a/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc
+++ b/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc
@@ -31,7 +31,8 @@
 // TODO(mamir): Create a test_helper.cc file instead of duplicating all this
 // code.
 MATCHER_P(EqualsJSON, json, "equals JSON") {
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(json);
   if (!expected) {
     *result_listener << "INTERNAL ERROR: couldn't parse expected JSON";
     return false;
@@ -39,8 +40,9 @@
 
   std::string err_msg;
   int err_line, err_col;
-  std::unique_ptr<base::Value> actual = base::JSONReader::ReadAndReturnError(
-      arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
+  std::unique_ptr<base::Value> actual =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
   if (!actual) {
     *result_listener << "input:" << err_line << ":" << err_col << ": "
                      << "parse error: " << err_msg;
diff --git a/components/ntp_snippets/remote/json_request_unittest.cc b/components/ntp_snippets/remote/json_request_unittest.cc
index c22066e..863b6450 100644
--- a/components/ntp_snippets/remote/json_request_unittest.cc
+++ b/components/ntp_snippets/remote/json_request_unittest.cc
@@ -38,7 +38,8 @@
 using testing::StrEq;
 
 MATCHER_P(EqualsJSON, json, "equals JSON") {
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> expected =
+      base::JSONReader::ReadDeprecated(json);
   if (!expected) {
     *result_listener << "INTERNAL ERROR: couldn't parse expected JSON";
     return false;
@@ -46,8 +47,9 @@
 
   std::string err_msg;
   int err_line, err_col;
-  std::unique_ptr<base::Value> actual = base::JSONReader::ReadAndReturnError(
-      arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
+  std::unique_ptr<base::Value> actual =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
   if (!actual) {
     *result_listener << "input:" << err_line << ":" << err_col << ": "
                      << "parse error: " << err_msg;
diff --git a/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index f3e3a268..d7437fbb 100644
--- a/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -27,7 +27,7 @@
 std::unique_ptr<RemoteSuggestion> SnippetFromContentSuggestionJSON(
     const std::string& json,
     const base::Time& fetch_date) {
-  auto json_value = base::JSONReader::Read(json);
+  auto json_value = base::JSONReader::ReadDeprecated(json);
   base::DictionaryValue* json_dict;
   if (!json_value->GetAsDictionary(&json_dict)) {
     return nullptr;
@@ -210,7 +210,7 @@
       "score": 9001
     }
   )";
-  auto json_value = base::JSONReader::Read(kJsonStr);
+  auto json_value = base::JSONReader::ReadDeprecated(kJsonStr);
   base::DictionaryValue* json_dict;
   CHECK(json_value->GetAsDictionary(&json_dict));
   return json_dict->CreateDeepCopy();
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index 6287067..f0a0e56 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -151,7 +151,7 @@
                const SuccessCallback& success_callback,
                const ErrorCallback& error_callback) {
   base::JSONReader json_reader;
-  std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
+  std::unique_ptr<base::Value> value = json_reader.ReadToValueDeprecated(json);
   if (value) {
     success_callback.Run(std::move(value));
   } else {
diff --git a/components/ntp_tiles/json_unsafe_parser.cc b/components/ntp_tiles/json_unsafe_parser.cc
index 863aa5c..e1281f0 100644
--- a/components/ntp_tiles/json_unsafe_parser.cc
+++ b/components/ntp_tiles/json_unsafe_parser.cc
@@ -25,7 +25,7 @@
             std::string error_msg;
             int error_line, error_column;
             std::unique_ptr<base::Value> value =
-                base::JSONReader::ReadAndReturnError(
+                base::JSONReader::ReadAndReturnErrorDeprecated(
                     unsafe_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
                     &error_msg, &error_line, &error_column);
             if (value) {
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index 40c097c..4612f00 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -718,8 +718,6 @@
     tile.title = link.title;
     tile.url = link.url;
     tile.source = TileSource::CUSTOM_LINKS;
-    // TODO(crbug.com/773278): Populate |data_generation_time| here in order to
-    // log UMA metrics of age.
     tiles.push_back(std::move(tile));
   }
 
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index 4d6c754..02380d5 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -222,7 +222,7 @@
     return base::Value(base::Value::Type::LIST);
   }
   std::unique_ptr<base::ListValue> sites =
-      base::ListValue::From(base::JSONReader::Read(
+      base::ListValue::From(base::JSONReader::ReadDeprecated(
           ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
               IDR_DEFAULT_POPULAR_SITES_JSON)));
   DCHECK(sites);
diff --git a/components/ntp_tiles/tile_source.h b/components/ntp_tiles/tile_source.h
index 165aa71..0d26c2a 100644
--- a/components/ntp_tiles/tile_source.h
+++ b/components/ntp_tiles/tile_source.h
@@ -7,7 +7,8 @@
 
 namespace ntp_tiles {
 
-// The source of an NTP tile.
+// The source of an NTP tile. Please update webui/ntp-tiles-internals* as well
+// when modifying these values.
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
 enum class TileSource {
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index 30a35ba0..2cf7806 100644
--- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -100,6 +100,7 @@
     disabled.SetBoolean("topSites", false);
     disabled.SetBoolean("suggestionsService", false);
     disabled.SetBoolean("popular", false);
+    disabled.SetBoolean("customLinks", false);
     disabled.SetBoolean("whitelist", false);
     client_->CallJavascriptFunction(
         "chrome.ntp_tiles_internals.receiveSourceInfo", disabled);
@@ -208,6 +209,8 @@
 
   value.SetBoolean("topSites",
                    most_visited_sites_->DoesSourceExist(TileSource::TOP_SITES));
+  value.SetBoolean("customLinks", most_visited_sites_->DoesSourceExist(
+                                      TileSource::CUSTOM_LINKS));
   value.SetBoolean("whitelist",
                    most_visited_sites_->DoesSourceExist(TileSource::WHITELIST));
 
diff --git a/components/ntp_tiles/webui/resources/ntp_tiles_internals.html b/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
index b83d02cb..72ea941 100644
--- a/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
+++ b/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
@@ -86,6 +86,16 @@
           <td class="value">no</td>
         </tr>
       </tbody>
+      <tbody jsselect="customLinks">
+        <tr>
+          <th colspan="2">CUSTOM_LINKS</th>
+        </tr>
+        <tr>
+          <td class="detail">enabled</td>
+          <td class="value" jsdisplay="$this">yes</td>
+          <td class="value" jsdisplay="!$this">no</td>
+        </tr>
+      </tbody>
       <tbody jsselect="whitelist">
         <tr>
           <th colspan="2">WHITELIST</th>
@@ -116,9 +126,10 @@
           <td class="value" jsdisplay="source == 1">SUGGESTIONS_SERVICE</td>
           <td class="value" jsdisplay="source == 2">POPULAR</td>
           <td class="value" jsdisplay="source == 3">POPULAR_BAKED_IN</td>
-          <td class="value" jsdisplay="source == 4">WHITELIST</td>
-          <td class="value" jsdisplay="source == 5">HOMEPAGE</td>
-          <td class="value" jsdisplay="source &gt; 5">???</td>
+          <td class="value" jsdisplay="source == 4">CUSTOM_LINKS</td>
+          <td class="value" jsdisplay="source == 5">WHITELIST</td>
+          <td class="value" jsdisplay="source == 6">HOMEPAGE</td>
+          <td class="value" jsdisplay="source &gt; 6">???</td>
         </tr>
         <tr>
           <td class="detail">URL</td>
diff --git a/components/omnibox/browser/autocomplete_match_type_unittest.cc b/components/omnibox/browser/autocomplete_match_type_unittest.cc
index ce91824..1ee4bf9 100644
--- a/components/omnibox/browser/autocomplete_match_type_unittest.cc
+++ b/components/omnibox/browser/autocomplete_match_type_unittest.cc
@@ -47,7 +47,8 @@
 namespace {
 
 bool ParseAnswer(const std::string& answer_json, SuggestionAnswer* answer) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(answer_json);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(answer_json);
   base::DictionaryValue* dict;
   if (!value || !value->GetAsDictionary(&dict))
     return false;
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index b4bb015..9e9696a8 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -470,15 +470,11 @@
   }
 
   // Erase duplicate matches.
-  matches->erase(
-      std::remove_if(
-          matches->begin(), matches->end(),
-          [&url_to_matches](const AutocompleteMatch& m) {
-            std::pair<GURL, bool> p = GetMatchComparisonFields(m);
-            return !m.stripped_destination_url.is_empty() &&
-                   &(*url_to_matches[p].front()) != &m;
-          }),
-      matches->end());
+  base::EraseIf(*matches, [&url_to_matches](const AutocompleteMatch& m) {
+    std::pair<GURL, bool> p = GetMatchComparisonFields(m);
+    return !m.stripped_destination_url.is_empty() &&
+           &(*url_to_matches[p].front()) != &m;
+  });
 }
 
 void AutocompleteResult::InlineTailPrefixes() {
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc
index 7768908..22efd97c 100644
--- a/components/omnibox/browser/document_provider.cc
+++ b/components/omnibox/browser/document_provider.cc
@@ -340,8 +340,9 @@
 }
 
 bool DocumentProvider::UpdateResults(const std::string& json_data) {
-  std::unique_ptr<base::DictionaryValue> response = base::DictionaryValue::From(
-      base::JSONReader::Read(json_data, base::JSON_ALLOW_TRAILING_COMMAS));
+  std::unique_ptr<base::DictionaryValue> response =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
+          json_data, base::JSON_ALLOW_TRAILING_COMMAS));
   if (!response)
     return false;
 
diff --git a/components/omnibox/browser/document_provider_unittest.cc b/components/omnibox/browser/document_provider_unittest.cc
index 9e3a1420..a3a4f4b 100644
--- a/components/omnibox/browser/document_provider_unittest.cc
+++ b/components/omnibox/browser/document_provider_unittest.cc
@@ -242,8 +242,8 @@
       ]
      })";
 
-  std::unique_ptr<base::DictionaryValue> response =
-      base::DictionaryValue::From(base::JSONReader::Read(kGoodJSONResponse));
+  std::unique_ptr<base::DictionaryValue> response = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(kGoodJSONResponse));
   ASSERT_TRUE(response != nullptr);
 
   ACMatches matches;
@@ -288,7 +288,7 @@
      })";
 
   std::unique_ptr<base::DictionaryValue> response = base::DictionaryValue::From(
-      base::JSONReader::Read(kGoodJSONResponseWithTies));
+      base::JSONReader::ReadDeprecated(kGoodJSONResponseWithTies));
   ASSERT_TRUE(response != nullptr);
 
   ACMatches matches;
@@ -341,7 +341,7 @@
      })";
 
   std::unique_ptr<base::DictionaryValue> response = base::DictionaryValue::From(
-      base::JSONReader::Read(kGoodJSONResponseWithTies));
+      base::JSONReader::ReadDeprecated(kGoodJSONResponseWithTies));
   ASSERT_TRUE(response != nullptr);
 
   ACMatches matches;
@@ -396,7 +396,7 @@
      })";
 
   std::unique_ptr<base::DictionaryValue> response = base::DictionaryValue::From(
-      base::JSONReader::Read(kGoodJSONResponseWithTies));
+      base::JSONReader::ReadDeprecated(kGoodJSONResponseWithTies));
   ASSERT_TRUE(response != nullptr);
 
   ACMatches matches;
@@ -445,7 +445,7 @@
 
   ASSERT_FALSE(provider_->backoff_for_session_);
   std::unique_ptr<base::DictionaryValue> backoff_response =
-      base::DictionaryValue::From(base::JSONReader::Read(
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
           kBackoffJSONResponse, base::JSON_ALLOW_TRAILING_COMMAS));
   ASSERT_TRUE(backoff_response != nullptr);
 
@@ -480,7 +480,7 @@
   // First, parse an invalid response - shouldn't prohibit future requests
   // from working but also shouldn't trigger backoff.
   std::unique_ptr<base::DictionaryValue> bad_response =
-      base::DictionaryValue::From(base::JSONReader::Read(
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
           kMismatchedMessageJSON, base::JSON_ALLOW_TRAILING_COMMAS));
   ASSERT_TRUE(bad_response != nullptr);
   provider_->ParseDocumentSearchResults(*bad_response, &matches);
@@ -488,7 +488,7 @@
 
   // Now parse a response that does trigger backoff.
   std::unique_ptr<base::DictionaryValue> backoff_response =
-      base::DictionaryValue::From(base::JSONReader::Read(
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
           kIneligibleJSONResponse, base::JSON_ALLOW_TRAILING_COMMAS));
   ASSERT_TRUE(backoff_response != nullptr);
   provider_->ParseDocumentSearchResults(*backoff_response, &matches);
diff --git a/components/omnibox/browser/search_suggestion_parser_unittest.cc b/components/omnibox/browser/search_suggestion_parser_unittest.cc
index 58b59c8..6715b96f 100644
--- a/components/omnibox/browser/search_suggestion_parser_unittest.cc
+++ b/components/omnibox/browser/search_suggestion_parser_unittest.cc
@@ -30,7 +30,7 @@
 TEST(SearchSuggestionParserTest, DeserializeJsonData) {
   std::string json_data = R"([{"one": 1}])";
   std::unique_ptr<base::Value> manifest_value =
-      base::JSONReader::Read(json_data);
+      base::JSONReader::ReadDeprecated(json_data);
   std::unique_ptr<base::Value> result =
       SearchSuggestionParser::DeserializeJsonData(json_data);
   ASSERT_TRUE(result);
@@ -84,7 +84,8 @@
 
 TEST(SearchSuggestionParserTest, ParseNonSuggestionValueIsInvalid) {
   std::string json_data = R"([{"one": 1}])";
-  std::unique_ptr<base::Value> root_val = base::JSONReader::Read(json_data);
+  std::unique_ptr<base::Value> root_val =
+      base::JSONReader::ReadDeprecated(json_data);
   AutocompleteInput input;
   TestSchemeClassifier scheme_classifier;
   int default_result_relevance = 0;
@@ -119,7 +120,8 @@
         "google:suggesttype": ["QUERY", "ENTITY"],
         "google:verbatimrelevance": 851
       }])";
-  std::unique_ptr<base::Value> root_val = base::JSONReader::Read(json_data);
+  std::unique_ptr<base::Value> root_val =
+      base::JSONReader::ReadDeprecated(json_data);
   TestSchemeClassifier scheme_classifier;
   AutocompleteInput input(base::ASCIIToUTF16("chris"),
                           metrics::OmniboxEventProto::NTP, scheme_classifier);
diff --git a/components/omnibox/browser/suggestion_answer_unittest.cc b/components/omnibox/browser/suggestion_answer_unittest.cc
index 2991ef7..544c33a0 100644
--- a/components/omnibox/browser/suggestion_answer_unittest.cc
+++ b/components/omnibox/browser/suggestion_answer_unittest.cc
@@ -18,7 +18,8 @@
 namespace {
 
 bool ParseAnswer(const std::string& answer_json, SuggestionAnswer* answer) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(answer_json);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(answer_json);
   base::DictionaryValue* dict;
   if (!value || !value->GetAsDictionary(&dict))
     return false;
diff --git a/components/optimization_guide/OWNERS b/components/optimization_guide/OWNERS
index 52c14e4..fd70f95 100644
--- a/components/optimization_guide/OWNERS
+++ b/components/optimization_guide/OWNERS
@@ -1 +1,3 @@
 file://components/previews/OWNERS
+
+# COMPONENT: Blink>Previews
diff --git a/components/password_manager/core/browser/site_affiliation/asset_link_data.cc b/components/password_manager/core/browser/site_affiliation/asset_link_data.cc
index e20be71..345de85 100644
--- a/components/password_manager/core/browser/site_affiliation/asset_link_data.cc
+++ b/components/password_manager/core/browser/site_affiliation/asset_link_data.cc
@@ -53,7 +53,7 @@
 AssetLinkData& AssetLinkData::operator=(AssetLinkData&& other) = default;
 
 bool AssetLinkData::Parse(const std::string& data) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value || !value->is_list())
     return false;
   const base::Value::ListStorage& list_storage = value->GetList();
diff --git a/components/payments/content/utility/payment_manifest_parser_unittest.cc b/components/payments/content/utility/payment_manifest_parser_unittest.cc
index d86e491..5ec89b1d 100644
--- a/components/payments/content/utility/payment_manifest_parser_unittest.cc
+++ b/components/payments/content/utility/payment_manifest_parser_unittest.cc
@@ -21,7 +21,7 @@
   std::vector<url::Origin> actual_supported_origins;
   bool actual_all_origins_supported = false;
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(input);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(input);
 
   PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
       std::move(value), ErrorLogger(), &actual_web_app_urls,
@@ -42,7 +42,7 @@
   std::vector<url::Origin> actual_supported_origins;
   bool actual_all_origins_supported = false;
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(input);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(input);
 
   PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
       std::move(value), ErrorLogger(), &actual_web_app_urls,
@@ -276,7 +276,7 @@
 // Web app manifest parsing:
 
 void ExpectUnableToParseWebAppManifest(const std::string& input) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(input);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(input);
   std::vector<WebAppManifestSection> sections;
   PaymentManifestParser::ParseWebAppManifestIntoVector(
       std::move(value), ErrorLogger(), &sections);
@@ -288,7 +288,7 @@
     const std::string& expected_id,
     int64_t expected_min_version,
     const std::vector<std::vector<uint8_t>>& expected_fingerprints) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(input);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(input);
   std::vector<WebAppManifestSection> sections;
   EXPECT_TRUE(PaymentManifestParser::ParseWebAppManifestIntoVector(
       std::move(value), ErrorLogger(), &sections));
@@ -690,7 +690,7 @@
 }
 
 TEST(PaymentManifestParserTest, TwoRelatedApplicationsWellFormed) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       "{"
       "  \"related_applications\": [{"
       "    \"platform\": \"play\", "
@@ -744,7 +744,7 @@
 // Web app installation information parsing:
 
 void ExpectUnableToParseInstallInfo(const std::string& input) {
-  auto value = base::JSONReader::Read(input);
+  auto value = base::JSONReader::ReadDeprecated(input);
   auto installation_info = std::make_unique<WebAppInstallationInfo>();
   auto icons =
       std::make_unique<std::vector<PaymentManifestParser::WebAppIcon>>();
@@ -756,7 +756,7 @@
     const std::string& input,
     const WebAppInstallationInfo& expected_installation_info,
     const std::vector<PaymentManifestParser::WebAppIcon>& expected_icons) {
-  auto value = base::JSONReader::Read(input);
+  auto value = base::JSONReader::ReadDeprecated(input);
   WebAppInstallationInfo actual_installation_info;
   std::vector<PaymentManifestParser::WebAppIcon> actual_icons;
   EXPECT_TRUE(PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
diff --git a/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc b/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc
index a250b5d8..14f1e51 100644
--- a/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc
+++ b/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc
@@ -30,7 +30,8 @@
   bool all_origins_supported;
 
   base::StringPiece json_data(reinterpret_cast<const char*>(data), size);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json_data);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(json_data);
 
   payments::ErrorLogger log;
   log.DisableInTest();
diff --git a/components/payments/content/utility/payment_web_app_manifest_parser_fuzzer.cc b/components/payments/content/utility/payment_web_app_manifest_parser_fuzzer.cc
index d0b6ac6..d8c0d1b 100644
--- a/components/payments/content/utility/payment_web_app_manifest_parser_fuzzer.cc
+++ b/components/payments/content/utility/payment_web_app_manifest_parser_fuzzer.cc
@@ -16,7 +16,8 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   std::string json_data(reinterpret_cast<const char*>(data), size);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json_data);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(json_data);
 
   payments::ErrorLogger log;
   log.DisableInTest();
diff --git a/components/payments/core/payment_details_validation_unittest.cc b/components/payments/core/payment_details_validation_unittest.cc
index 0f3bacb..51cfa72 100644
--- a/components/payments/core/payment_details_validation_unittest.cc
+++ b/components/payments/core/payment_details_validation_unittest.cc
@@ -44,7 +44,7 @@
     : public ::testing::TestWithParam<PaymentDetailsValidationTestCase> {};
 
 TEST_P(PaymentDetailsValidationTest, Test) {
-  auto value = base::JSONReader::Read(GetParam().details);
+  auto value = base::JSONReader::ReadDeprecated(GetParam().details);
   ASSERT_NE(nullptr, value.get()) << "Should be in JSON format";
   auto dictionary = base::DictionaryValue::From(std::move(value));
   ASSERT_NE(nullptr, dictionary.get()) << "Should be a dictionary";
diff --git a/components/policy/core/browser/android/policy_converter.cc b/components/policy/core/browser/android/policy_converter.cc
index bc3b4b5..b711a64f 100644
--- a/components/policy/core/browser/android/policy_converter.cc
+++ b/components/policy/core/browser/android/policy_converter.cc
@@ -169,7 +169,7 @@
       std::string string_value;
       if (value->GetAsString(&string_value)) {
         std::unique_ptr<base::Value> decoded_value =
-            base::JSONReader::Read(string_value);
+            base::JSONReader::ReadDeprecated(string_value);
         if (decoded_value)
           return decoded_value;
       }
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc
index e0c3280..0c148279 100644
--- a/components/policy/core/browser/configuration_policy_handler.cc
+++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -571,7 +571,7 @@
     int index) {
   std::string parse_error;
   std::unique_ptr<base::Value> parsed_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           json_string, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &parse_error);
   if (errors && !parse_error.empty()) {
     errors->AddError(policy_name_, ErrorPath(index, ""),
diff --git a/components/policy/core/browser/configuration_policy_handler_unittest.cc b/components/policy/core/browser/configuration_policy_handler_unittest.cc
index a8cac572..23a7dfd 100644
--- a/components/policy/core/browser/configuration_policy_handler_unittest.cc
+++ b/components/policy/core/browser/configuration_policy_handler_unittest.cc
@@ -746,7 +746,7 @@
       "  }"
       "}";
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           kPolicyMapJson, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(policy_map_value) << error;
 
@@ -805,7 +805,7 @@
       "  }"
       "}";
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           kPolicyMapJson, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(policy_map_value) << error;
 
@@ -901,9 +901,9 @@
 TEST(SimpleJsonStringSchemaValidatingPolicyHandlerTest, ValidEmbeddedJson) {
   std::string error;
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(kPolicyMapJsonValid,
-                                           base::JSON_ALLOW_TRAILING_COMMAS,
-                                           nullptr, &error);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          kPolicyMapJsonValid, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+          &error);
   ASSERT_TRUE(policy_map_value) << error;
 
   const base::DictionaryValue* policy_map_dict = nullptr;
@@ -933,9 +933,9 @@
 TEST(SimpleJsonStringSchemaValidatingPolicyHandlerTest, InvalidEmbeddedJson) {
   std::string error;
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(kPolicyMapJsonInvalid,
-                                           base::JSON_ALLOW_TRAILING_COMMAS,
-                                           nullptr, &error);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          kPolicyMapJsonInvalid, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+          &error);
   ASSERT_TRUE(policy_map_value) << error;
 
   const base::DictionaryValue* policy_map_dict = nullptr;
@@ -965,9 +965,9 @@
 TEST(SimpleJsonStringSchemaValidatingPolicyHandlerTest, UnparsableJson) {
   std::string error;
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(kPolicyMapJsonUnparsable,
-                                           base::JSON_ALLOW_TRAILING_COMMAS,
-                                           nullptr, &error);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          kPolicyMapJsonUnparsable, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+          &error);
   ASSERT_TRUE(policy_map_value) << error;
 
   const base::DictionaryValue* policy_map_dict = nullptr;
@@ -997,9 +997,9 @@
 TEST(SimpleJsonStringSchemaValidatingPolicyHandlerTest, WrongType) {
   std::string error;
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(kPolicyMapJsonWrongTypes,
-                                           base::JSON_ALLOW_TRAILING_COMMAS,
-                                           nullptr, &error);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          kPolicyMapJsonWrongTypes, base::JSON_ALLOW_TRAILING_COMMAS, nullptr,
+          &error);
   ASSERT_TRUE(policy_map_value) << error;
 
   const base::DictionaryValue* policy_map_dict = nullptr;
@@ -1029,9 +1029,9 @@
 TEST(SimpleJsonStringSchemaValidatingPolicyHandlerTest, WrongRootType) {
   std::string error;
   std::unique_ptr<base::Value> policy_map_value =
-      base::JSONReader::ReadAndReturnError(kPolicyMapJsonWrongRootType,
-                                           base::JSON_ALLOW_TRAILING_COMMAS,
-                                           nullptr, &error);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          kPolicyMapJsonWrongRootType, base::JSON_ALLOW_TRAILING_COMMAS,
+          nullptr, &error);
   ASSERT_TRUE(policy_map_value) << error;
 
   const base::DictionaryValue* policy_map_dict = nullptr;
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index 3d20236..0f42902 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -869,9 +869,10 @@
     dm_token_ = response.register_response().device_management_token();
     reregistration_dm_token_.clear();
     if (response.register_response().has_configuration_seed()) {
-      configuration_seed_ = base::DictionaryValue::From(base::JSONReader::Read(
-          response.register_response().configuration_seed(),
-          base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
+      configuration_seed_ =
+          base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
+              response.register_response().configuration_seed(),
+              base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
       if (!configuration_seed_)
         LOG(ERROR) << "Failed to parse configuration seed";
     }
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store.cc b/components/policy/core/common/cloud/component_cloud_policy_store.cc
index d7bfe338..af5b247 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_store.cc
@@ -391,9 +391,10 @@
 bool ComponentCloudPolicyStore::ParsePolicy(const std::string& data,
                                             PolicyMap* policy) {
   std::string json_reader_error_message;
-  std::unique_ptr<base::Value> json = base::JSONReader::ReadAndReturnError(
-      data, base::JSON_PARSE_RFC, nullptr /* error_code_out */,
-      &json_reader_error_message);
+  std::unique_ptr<base::Value> json =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          data, base::JSON_PARSE_RFC, nullptr /* error_code_out */,
+          &json_reader_error_message);
   base::DictionaryValue* dict = nullptr;
   if (!json) {
     LOG(ERROR) << "Invalid JSON blob: " << json_reader_error_message;
diff --git a/components/policy/core/common/cloud/policy_header_service_unittest.cc b/components/policy/core/common/cloud/policy_header_service_unittest.cc
index aa69034..523c274a 100644
--- a/components/policy/core/common/cloud/policy_header_service_unittest.cc
+++ b/components/policy/core/common/cloud/policy_header_service_unittest.cc
@@ -64,7 +64,8 @@
     base::Base64Decode(header_value, &decoded);
 
     // Parse the JSON.
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(decoded);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadDeprecated(decoded);
     EXPECT_TRUE(value);
     base::DictionaryValue* dict;
     EXPECT_TRUE(value->GetAsDictionary(&dict));
diff --git a/components/policy/core/common/cloud/user_info_fetcher.cc b/components/policy/core/common/cloud/user_info_fetcher.cc
index b7c65e78..1e25dc0 100644
--- a/components/policy/core/common/cloud/user_info_fetcher.cc
+++ b/components/policy/core/common/cloud/user_info_fetcher.cc
@@ -110,7 +110,7 @@
   DCHECK(unparsed_data);
   DVLOG(1) << "Received UserInfo response: " << *unparsed_data;
   std::unique_ptr<base::Value> parsed_value =
-      base::JSONReader::Read(*unparsed_data);
+      base::JSONReader::ReadDeprecated(*unparsed_data);
   base::DictionaryValue* dict;
   if (parsed_value.get() && parsed_value->GetAsDictionary(&dict)) {
     delegate_->OnGetUserInfoSuccess(dict);
diff --git a/components/policy/core/common/policy_proto_decoders.cc b/components/policy/core/common/policy_proto_decoders.cc
index 5f13eddc..aab3eaca 100644
--- a/components/policy/core/common/policy_proto_decoders.cc
+++ b/components/policy/core/common/policy_proto_decoders.cc
@@ -89,7 +89,7 @@
                                              std::string* error) {
   const std::string& json = proto.value();
   std::unique_ptr<base::Value> parsed_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, error);
 
   if (!parsed_value) {
diff --git a/components/policy/core/common/registry_dict.cc b/components/policy/core/common/registry_dict.cc
index a86704d..f3ed372b 100644
--- a/components/policy/core/common/registry_dict.cc
+++ b/components/policy/core/common/registry_dict.cc
@@ -125,7 +125,7 @@
       // Dictionaries may be encoded as JSON strings.
       if (value.GetAsString(&string_value)) {
         std::unique_ptr<base::Value> result =
-            base::JSONReader::Read(string_value);
+            base::JSONReader::ReadDeprecated(string_value);
         if (result && result->type() == schema.type())
           return result;
       }
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc
index 2cf6930d..a533e9e 100644
--- a/components/policy/core/common/schema.cc
+++ b/components/policy/core/common/schema.cc
@@ -1472,8 +1472,9 @@
     int validator_options,
     std::string* error) {
   base::JSONParserOptions json_options = base::JSON_ALLOW_TRAILING_COMMAS;
-  std::unique_ptr<base::Value> json = base::JSONReader::ReadAndReturnError(
-      schema, json_options, nullptr, error);
+  std::unique_ptr<base::Value> json =
+      base::JSONReader::ReadAndReturnErrorDeprecated(schema, json_options,
+                                                     nullptr, error);
   if (!json)
     return nullptr;
   std::unique_ptr<base::DictionaryValue> dict =
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index d5e39e8..4da2a8d 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -1131,15 +1131,20 @@
   optional string plugin_vm_license_key = 1;
 }
 
-// Setting that controls whether the device should reboot after user sign out.
-message DeviceRebootAfterUserSignoutProto {
+// Setting that controls whether the device should reboot when user sign out.
+message DeviceRebootOnUserSignoutProto {
   enum RebootOnSignoutMode {
-    NEVER = 0;
-    ARC_SESSION = 1;
-    ALWAYS = 2;
+    // No value set. Default is NEVER.
+    REBOOT_ON_SIGNOUT_MODE_UNSPECIFIED = 0;
+    // Do not reboot on signout.
+    NEVER = 1;
+    // Reboot on signout if an ARC session was active during the user session.
+    ARC_SESSION = 2;
+    // Always reboot on signout.
+    ALWAYS = 3;
   }
 
-  optional RebootOnSignoutMode reboot_after_signout_mode = 1 [default = NEVER];
+  optional RebootOnSignoutMode reboot_on_signout_mode = 1 [default = NEVER];
 }
 
 message ChromeDeviceSettingsProto {
@@ -1242,6 +1247,5 @@
   optional DeviceAuthDataCacheLifetimeProto device_auth_data_cache_lifetime =
       77;
   optional PluginVmLicenseKeyProto plugin_vm_license_key = 78;
-  optional DeviceRebootAfterUserSignoutProto device_reboot_after_user_signout =
-      79;
+  optional DeviceRebootOnUserSignoutProto device_reboot_on_user_signout = 79;
 }
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index b60104c4..364cd85 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -14613,42 +14613,42 @@
     },
     {
       'id': 520,
-      'name': 'DeviceRebootAfterUserSignout',
+      'name': 'DeviceRebootOnUserSignout',
       'type': 'int-enum',
       'schema': {
         'type': 'integer',
-        'enum': [ 0, 1, 2 ],
+        'enum': [ 1, 2, 3 ],
       },
       'items': [
         {
           'name': 'Never',
-          'value': 0,
-          'caption': '''Do not reboot after user sign out.''',
+          'value': 1,
+          'caption': '''Do not reboot on user sign out.''',
         },
         {
           'name': 'ArcSession',
-          'value': 1,
-          'caption': '''Reboot after user sign out if Android has started.''',
+          'value': 2,
+          'caption': '''Reboot on user sign out if Android has started.''',
         },
         {
           'name': 'Always',
-          'value': 2,
-          'caption': '''Always reboot after user sign out.''',
+          'value': 3,
+          'caption': '''Always reboot on user sign out.''',
         },
       ],
       'device_only': True,
-      'example_value': 0,
+      'example_value': 2,
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
       },
       'supported_on': ['chrome_os:74-'],
-      'caption': '''Force device reboot after user sign out''',
+      'caption': '''Force device reboot when user sign out''',
       'tags': ['system-security'],
       'desc': '''
-      This policy, when set to ArcSession, forces the device to reboot after user sign out if Android has started.
-      When set to Always, it forces the device to reboot after every user sign out.
-      If left unset, it has no effect and no reboot is forced after user sign out. The same applies if set to Never.
+      This policy, when set to ArcSession, forces the device to reboot when a user sign out if Android has started.
+      When set to Always, it forces the device to reboot on every user sign out.
+      If left unset, it has no effect and no reboot is forced on user sign out. The same applies if set to Never.
       ''',
     },
     {
diff --git a/components/previews/content/BUILD.gn b/components/previews/content/BUILD.gn
index f19eb777..8595b0a 100644
--- a/components/previews/content/BUILD.gn
+++ b/components/previews/content/BUILD.gn
@@ -9,8 +9,6 @@
     "hint_cache_leveldb_store.cc",
     "hint_cache_leveldb_store.h",
     "hint_cache_store.h",
-    "previews_content_util.cc",
-    "previews_content_util.h",
     "previews_decider_impl.cc",
     "previews_decider_impl.h",
     "previews_hints.cc",
@@ -45,7 +43,6 @@
   sources = [
     "hint_cache_leveldb_store_unittest.cc",
     "hint_cache_unittest.cc",
-    "previews_content_util_unittest.cc",
     "previews_decider_impl_unittest.cc",
     "previews_hints_unittest.cc",
     "previews_hints_util_unittest.cc",
diff --git a/components/previews/core/previews_lite_page_redirect_unittest.cc b/components/previews/core/previews_lite_page_redirect_unittest.cc
index 957e283..7f5fbda 100644
--- a/components/previews/core/previews_lite_page_redirect_unittest.cc
+++ b/components/previews/core/previews_lite_page_redirect_unittest.cc
@@ -38,6 +38,15 @@
           "http%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes",
           true,
       },
+      {
+          "https://previews.host.com",
+          "http://original.host.com/path/path/path?query=yes#fragment",
+          "https://6p7dar4ju6r4ynz7x3pucmlcltuqsf7z5auhvckzln7voglkt56q."
+          "previews.host.com/p?u="
+          "http%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes"
+          "%23fragment#fragment",
+          true,
+      },
   };
 
   for (const TestCase& test_case : kTestCases) {
diff --git a/components/quirks/quirks_client.cc b/components/quirks/quirks_client.cc
index 3c027b9..c202a8e 100644
--- a/components/quirks/quirks_client.cc
+++ b/components/quirks/quirks_client.cc
@@ -189,7 +189,7 @@
 bool QuirksClient::ParseResult(const std::string& result, std::string* data) {
   std::string data64;
   const base::DictionaryValue* dict;
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(result);
+  std::unique_ptr<base::Value> json = base::JSONReader::ReadDeprecated(result);
   if (!json || !json->GetAsDictionary(&dict) ||
       !dict->GetString("icc", &data64)) {
     VLOG(1) << "Failed to parse JSON icc data";
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_util.cc b/components/safe_browsing/android/safe_browsing_api_handler_util.cc
index f7a2f12c..944db05b 100644
--- a/components/safe_browsing/android/safe_browsing_api_handler_util.cc
+++ b/components/safe_browsing/android/safe_browsing_api_handler_util.cc
@@ -207,7 +207,8 @@
     return UMA_STATUS_JSON_EMPTY;
 
   // Pick out the "matches" list.
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(metadata_str);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(metadata_str);
   const base::ListValue* matches = nullptr;
   if (!value.get() || !value->is_dict() ||
       !(static_cast<base::DictionaryValue*>(value.get()))
diff --git a/components/safe_search_api/url_checker.cc b/components/safe_search_api/url_checker.cc
index fa9f8890..bacd56d72 100644
--- a/components/safe_search_api/url_checker.cc
+++ b/components/safe_search_api/url_checker.cc
@@ -52,7 +52,8 @@
 // Parses a SafeSearch API |response| and stores the result in |is_porn|.
 // On errors, returns false and doesn't set |is_porn|.
 bool ParseResponse(const std::string& response, bool* is_porn) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response);
   const base::DictionaryValue* dict = nullptr;
   if (!value || !value->GetAsDictionary(&dict)) {
     DLOG(WARNING) << "ParseResponse failed to parse global dictionary";
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc
index a5d9922..8278864 100644
--- a/components/search_engines/keyword_table.cc
+++ b/components/search_engines/keyword_table.cc
@@ -474,7 +474,7 @@
   data->alternate_urls.clear();
   base::JSONReader json_reader;
   std::unique_ptr<base::Value> value(
-      json_reader.ReadToValue(s.ColumnString(15)));
+      json_reader.ReadToValueDeprecated(s.ColumnString(15)));
   base::ListValue* alternate_urls_value;
   if (value.get() && value->GetAsList(&alternate_urls_value)) {
     std::string alternate_url;
diff --git a/components/search_provider_logos/google_logo_api.cc b/components/search_provider_logos/google_logo_api.cc
index 2ef1c08..fc0e3e98 100644
--- a/components/search_provider_logos/google_logo_api.cc
+++ b/components/search_provider_logos/google_logo_api.cc
@@ -150,8 +150,9 @@
   std::string error_string;
   int error_line;
   int error_col;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      response_sp, 0, &error_code, &error_string, &error_line, &error_col);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          response_sp, 0, &error_code, &error_string, &error_line, &error_col);
   if (!value) {
     LOG(WARNING) << error_string << " at " << error_line << ":" << error_col;
     return nullptr;
diff --git a/components/search_provider_logos/logo_cache.cc b/components/search_provider_logos/logo_cache.cc
index 4dbec533..c4bccf9 100644
--- a/components/search_provider_logos/logo_cache.cc
+++ b/components/search_provider_logos/logo_cache.cc
@@ -172,7 +172,7 @@
 std::unique_ptr<LogoMetadata> LogoCache::LogoMetadataFromString(
     const std::string& str,
     int* logo_num_bytes) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
   base::DictionaryValue* dict;
   if (!value || !value->GetAsDictionary(&dict))
     return nullptr;
diff --git a/components/services/heap_profiling/json_exporter_unittest.cc b/components/services/heap_profiling/json_exporter_unittest.cc
index df61b5f..a31c9a5 100644
--- a/components/services/heap_profiling/json_exporter_unittest.cc
+++ b/components/services/heap_profiling/json_exporter_unittest.cc
@@ -167,7 +167,8 @@
 
   // JSON should parse.
   base::JSONReader reader(base::JSON_PARSE_RFC);
-  std::unique_ptr<base::Value> root = reader.ReadToValue(stream.str());
+  std::unique_ptr<base::Value> root =
+      reader.ReadToValueDeprecated(stream.str());
   ASSERT_EQ(base::JSONReader::JSON_NO_ERROR, reader.error_code())
       << reader.GetErrorMessage();
   ASSERT_TRUE(root);
@@ -320,7 +321,8 @@
 
   // JSON should parse.
   base::JSONReader reader(base::JSON_PARSE_RFC);
-  std::unique_ptr<base::Value> root = reader.ReadToValue(stream.str());
+  std::unique_ptr<base::Value> root =
+      reader.ReadToValueDeprecated(stream.str());
   ASSERT_EQ(base::JSONReader::JSON_NO_ERROR, reader.error_code())
       << reader.GetErrorMessage();
   ASSERT_TRUE(root);
@@ -392,7 +394,8 @@
 
   // JSON should parse.
   base::JSONReader reader(base::JSON_PARSE_RFC);
-  std::unique_ptr<base::Value> root = reader.ReadToValue(stream.str());
+  std::unique_ptr<base::Value> root =
+      reader.ReadToValueDeprecated(stream.str());
   ASSERT_EQ(base::JSONReader::JSON_NO_ERROR, reader.error_code())
       << reader.GetErrorMessage();
   ASSERT_TRUE(root);
@@ -463,7 +466,8 @@
 
   // JSON should parse.
   base::JSONReader reader(base::JSON_PARSE_RFC);
-  std::unique_ptr<base::Value> root = reader.ReadToValue(stream.str());
+  std::unique_ptr<base::Value> root =
+      reader.ReadToValueDeprecated(stream.str());
   ASSERT_EQ(base::JSONReader::JSON_NO_ERROR, reader.error_code())
       << reader.GetErrorMessage();
   ASSERT_TRUE(root);
@@ -523,7 +527,8 @@
 
   // JSON should parse.
   base::JSONReader reader(base::JSON_PARSE_RFC);
-  std::unique_ptr<base::Value> root = reader.ReadToValue(stream.str());
+  std::unique_ptr<base::Value> root =
+      reader.ReadToValueDeprecated(stream.str());
   ASSERT_EQ(base::JSONReader::JSON_NO_ERROR, reader.error_code())
       << reader.GetErrorMessage();
   ASSERT_TRUE(root);
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 276ee0e2..6166afaf 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -269,7 +269,7 @@
 
 void GaiaCookieManagerService::ExternalCcResultFetcher::
     OnGetCheckConnectionInfoSuccess(const std::string& data) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   const base::ListValue* list;
   if (!value || !value->GetAsList(&list)) {
     CleanupTransientState();
diff --git a/components/spellcheck/browser/spelling_service_client.cc b/components/spellcheck/browser/spelling_service_client.cc
index cce3ff31..b772a58c 100644
--- a/components/spellcheck/browser/spelling_service_client.cc
+++ b/components/spellcheck/browser/spelling_service_client.cc
@@ -246,7 +246,8 @@
   // }
   std::unique_ptr<base::DictionaryValue> value(
       static_cast<base::DictionaryValue*>(
-          base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS)
+          base::JSONReader::ReadDeprecated(data,
+                                           base::JSON_ALLOW_TRAILING_COMMAS)
               .release()));
   if (!value || !value->is_dict())
     return false;
diff --git a/components/subresource_filter/tools/filter_tool.cc b/components/subresource_filter/tools/filter_tool.cc
index 69e1b85c..ac1f8e76 100644
--- a/components/subresource_filter/tools/filter_tool.cc
+++ b/components/subresource_filter/tools/filter_tool.cc
@@ -162,7 +162,8 @@
     if (line.empty())
       continue;
 
-    std::unique_ptr<base::Value> dictionary = base::JSONReader::Read(line);
+    std::unique_ptr<base::Value> dictionary =
+        base::JSONReader::ReadDeprecated(line);
     CHECK(dictionary);
 
     const std::string& origin =
diff --git a/components/subresource_filter/tools/indexing_tool_unittest.cc b/components/subresource_filter/tools/indexing_tool_unittest.cc
index 14f0a6c..cc9f2cfa 100644
--- a/components/subresource_filter/tools/indexing_tool_unittest.cc
+++ b/components/subresource_filter/tools/indexing_tool_unittest.cc
@@ -131,8 +131,8 @@
   WriteVersionMetadata(version_path, "1.2.3", checksum);
   std::string version_json;
   EXPECT_TRUE(base::ReadFileToString(version_path, &version_json));
-  std::unique_ptr<base::DictionaryValue> json =
-      base::DictionaryValue::From(base::JSONReader::Read(version_json));
+  std::unique_ptr<base::DictionaryValue> json = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(version_json));
 
   std::string actual_content =
       json->FindPath({"subresource_filter", "ruleset_version", "content"})
diff --git a/components/sync_preferences/pref_model_associator.cc b/components/sync_preferences/pref_model_associator.cc
index 09602ff..4a2fe065 100644
--- a/components/sync_preferences/pref_model_associator.cc
+++ b/components/sync_preferences/pref_model_associator.cc
@@ -97,7 +97,7 @@
     DCHECK(pref_name == preference.name());
     base::JSONReader reader;
     std::unique_ptr<base::Value> sync_value(
-        reader.ReadToValue(preference.value()));
+        reader.ReadToValueDeprecated(preference.value()));
     if (!sync_value.get()) {
       LOG(ERROR) << "Failed to deserialize value of preference '" << pref_name
                  << "': " << reader.GetErrorMessage();
@@ -420,7 +420,8 @@
 base::Value* PrefModelAssociator::ReadPreferenceSpecifics(
     const sync_pb::PreferenceSpecifics& preference) {
   base::JSONReader reader;
-  std::unique_ptr<base::Value> value(reader.ReadToValue(preference.value()));
+  std::unique_ptr<base::Value> value(
+      reader.ReadToValueDeprecated(preference.value()));
   if (!value.get()) {
     std::string err =
         "Failed to deserialize preference value: " + reader.GetErrorMessage();
diff --git a/components/sync_preferences/pref_service_syncable_unittest.cc b/components/sync_preferences/pref_service_syncable_unittest.cc
index 601de14..e792149 100644
--- a/components/sync_preferences/pref_service_syncable_unittest.cc
+++ b/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -167,7 +167,7 @@
     auto it = list.begin();
     for (; it != list.end(); ++it) {
       if (syncer::SyncDataLocal(it->sync_data()).GetTag() == name) {
-        return base::JSONReader::Read(
+        return base::JSONReader::ReadDeprecated(
             it->sync_data().GetSpecifics().preference().value());
       }
     }
@@ -207,7 +207,7 @@
   EXPECT_EQ(std::string(kStringPrefName), specifics.name());
 
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(specifics.value());
+      base::JSONReader::ReadDeprecated(specifics.value());
   EXPECT_TRUE(pref->GetValue()->Equals(value.get()));
 }
 
@@ -417,7 +417,7 @@
     auto it = list.begin();
     for (; it != list.end(); ++it) {
       if (syncer::SyncDataLocal(it->sync_data()).GetTag() == name) {
-        return base::JSONReader::Read(
+        return base::JSONReader::ReadDeprecated(
             it->sync_data().GetSpecifics().preference().value());
       }
     }
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.reposition_bar_keyboard_open.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.reposition_bar_keyboard_open.Pixel_XL-25.png.sha1
new file mode 100644
index 0000000..1d7d7d7d
--- /dev/null
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.reposition_bar_keyboard_open.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@
+6f34c598a6fb92ef2ab443ce734a1b3ba0fe1c51
\ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.reposition_bar_keyboard_open.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.reposition_bar_keyboard_open.Pixel_XL-26.png.sha1
new file mode 100644
index 0000000..21c8bfa
--- /dev/null
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.reposition_bar_keyboard_open.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@
+dd76a89ce00dbc4115c055527f53770a1e376c8f
\ No newline at end of file
diff --git a/components/tracing/common/trace_startup_config.cc b/components/tracing/common/trace_startup_config.cc
index 0f5f37af..4376acb3 100644
--- a/components/tracing/common/trace_startup_config.cc
+++ b/components/tracing/common/trace_startup_config.cc
@@ -227,7 +227,7 @@
 
 bool TraceStartupConfig::ParseTraceConfigFileContent(
     const std::string& content) {
-  std::unique_ptr<base::Value> value(base::JSONReader::Read(content));
+  std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(content));
   if (!value || !value->is_dict())
     return false;
 
diff --git a/components/tracing/common/tracing_sampler_profiler_unittest.cc b/components/tracing/common/tracing_sampler_profiler_unittest.cc
index 2c1f9e13..a4f2554 100644
--- a/components/tracing/common/tracing_sampler_profiler_unittest.cc
+++ b/components/tracing/common/tracing_sampler_profiler_unittest.cc
@@ -93,7 +93,8 @@
 
     std::string error_msg;
     std::unique_ptr<base::Value> trace_data =
-        base::JSONReader::ReadAndReturnError(json_data, 0, nullptr, &error_msg);
+        base::JSONReader::ReadAndReturnErrorDeprecated(json_data, 0, nullptr,
+                                                       &error_msg);
     CHECK(trace_data) << "JSON parsing failed (" << error_msg << ")";
 
     base::ListValue* list;
diff --git a/components/translate/core/browser/translate_language_list.cc b/components/translate/core/browser/translate_language_list.cc
index 159bee1..f2605b0 100644
--- a/components/translate/core/browser/translate_language_list.cc
+++ b/components/translate/core/browser/translate_language_list.cc
@@ -300,8 +300,8 @@
   //   "tl": {"XX": "LanguageName", ...}
   // }
   // Where "tl" is set in kTargetLanguagesKey.
-  std::unique_ptr<base::Value> json_value =
-      base::JSONReader::Read(language_list, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> json_value = base::JSONReader::ReadDeprecated(
+      language_list, base::JSON_ALLOW_TRAILING_COMMAS);
 
   if (!json_value || !json_value->is_dict()) {
     NotifyEvent(__LINE__, "Language list is invalid");
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc
index 05a33fc..f2beef2d 100644
--- a/components/translate/core/browser/translate_prefs.cc
+++ b/components/translate/core/browser/translate_prefs.cc
@@ -947,12 +947,9 @@
                    languages_in_same_family.end(), [](const std::string& lang) {
                      return TranslateAcceptLanguages::CanBeAcceptLanguage(lang);
                    })) {
-    list->erase(
-        std::remove_if(list->begin(), list->end(),
-                       [&languages_in_same_family](const std::string& lang) {
-                         return languages_in_same_family.count(lang) > 0;
-                       }),
-        list->end());
+    base::EraseIf(*list, [&languages_in_same_family](const std::string& lang) {
+      return languages_in_same_family.count(lang) > 0;
+    });
   }
 }
 
diff --git a/components/ui_devtools/views/dom_agent_aura.cc b/components/ui_devtools/views/dom_agent_aura.cc
index 3a140cd..db17684b 100644
--- a/components/ui_devtools/views/dom_agent_aura.cc
+++ b/components/ui_devtools/views/dom_agent_aura.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/stl_util.h"
 #include "components/ui_devtools/devtools_server.h"
 #include "components/ui_devtools/root_element.h"
 #include "components/ui_devtools/ui_element.h"
@@ -65,7 +66,7 @@
 }
 
 void DOMAgentAura::OnWindowDestroying(aura::Window* window) {
-  roots_.erase(std::remove(roots_.begin(), roots_.end(), window), roots_.end());
+  base::Erase(roots_, window);
 }
 
 std::vector<UIElement*> DOMAgentAura::CreateChildrenForRoot() {
diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc
index 1dec1e4..c76ffd2 100644
--- a/components/update_client/ping_manager_unittest.cc
+++ b/components/update_client/ping_manager_unittest.cc
@@ -140,7 +140,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     const auto msg = interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(msg);
+      const auto root = base::JSONReader().ReadDeprecated(msg);
       const auto* request = root->FindKey("request");
       ASSERT_TRUE(request);
       EXPECT_TRUE(request->FindKey("@os"));
@@ -220,7 +220,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     const auto msg = interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(msg);
+      const auto root = base::JSONReader().ReadDeprecated(msg);
       const auto* request = root->FindKey("request");
       const auto& app = request->FindKey("app")->GetList()[0];
       EXPECT_EQ("abc", app.FindKey("appid")->GetString());
@@ -267,7 +267,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     const auto msg = interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(msg);
+      const auto root = base::JSONReader().ReadDeprecated(msg);
       const auto* request = root->FindKey("request");
       const auto& app = request->FindKey("app")->GetList()[0];
       EXPECT_EQ("abc", app.FindKey("appid")->GetString());
@@ -317,7 +317,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     const auto msg = interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(msg);
+      const auto root = base::JSONReader().ReadDeprecated(msg);
       const auto* request = root->FindKey("request");
       const auto& app = request->FindKey("app")->GetList()[0];
       EXPECT_EQ("abc", app.FindKey("appid")->GetString());
@@ -351,7 +351,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     const auto msg = interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(msg);
+      const auto root = base::JSONReader().ReadDeprecated(msg);
       const auto* request = root->FindKey("request");
       const auto& app = request->FindKey("app")->GetList()[0];
       EXPECT_EQ("abc", app.FindKey("appid")->GetString());
@@ -415,7 +415,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     const auto msg = interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(msg);
+      const auto root = base::JSONReader().ReadDeprecated(msg);
       const auto* request = root->FindKey("request");
       const auto& app = request->FindKey("app")->GetList()[0];
       EXPECT_EQ("abc", app.FindKey("appid")->GetString());
diff --git a/components/update_client/protocol_parser_json.cc b/components/update_client/protocol_parser_json.cc
index 77cea14..d7d0037 100644
--- a/components/update_client/protocol_parser_json.cc
+++ b/components/update_client/protocol_parser_json.cc
@@ -282,7 +282,7 @@
     ParseError("Missing secure JSON prefix.");
     return false;
   }
-  const auto doc = base::JSONReader().Read(
+  const auto doc = base::JSONReader().ReadDeprecated(
       {response_json.begin() + std::char_traits<char>::length(kJSONPrefix),
        response_json.end()});
   if (!doc) {
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 1e11a96..9619a4c0 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -286,7 +286,7 @@
   // Sanity check the request.
   const auto& request = post_interceptor_->GetRequestBody(0);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     const auto* request = root->FindKey("request");
     ASSERT_TRUE(request);
     EXPECT_TRUE(request->FindKey("@os"));
@@ -433,7 +433,7 @@
 
   const auto request = post_interceptor_->GetRequestBody(0);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -490,7 +490,7 @@
   const auto request = post_interceptor_->GetRequestBody(0);
 
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -572,7 +572,7 @@
   // The request must contain dlpref="cacheable".
   const auto request = post_interceptor_->GetRequestBody(0);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     EXPECT_EQ("cacheable",
               root->FindKey("request")->FindKey("dlpref")->GetString());
   } else {
@@ -610,7 +610,7 @@
   // Sanity check the request.
   const auto& request = post_interceptor_->GetRequestBody(0);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -713,11 +713,11 @@
 
   if (use_JSON_) {
     const auto root1 =
-        base::JSONReader().Read(post_interceptor_->GetRequestBody(0));
+        base::JSONReader().ReadDeprecated(post_interceptor_->GetRequestBody(0));
     const auto& app1 = root1->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(5, app1.FindPath({"ping", "r"})->GetInt());
     const auto root2 =
-        base::JSONReader().Read(post_interceptor_->GetRequestBody(1));
+        base::JSONReader().ReadDeprecated(post_interceptor_->GetRequestBody(1));
     const auto& app2 = root2->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(3383, app2.FindPath({"ping", "rd"})->GetInt());
     EXPECT_TRUE(app2.FindPath({"ping", "ping_freshness"})->is_string());
@@ -785,23 +785,23 @@
 
   if (use_JSON_) {
     {
-      const auto root =
-          base::JSONReader().Read(post_interceptor_->GetRequestBody(0));
+      const auto root = base::JSONReader().ReadDeprecated(
+          post_interceptor_->GetRequestBody(0));
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(10, app.FindPath({"ping", "a"})->GetInt());
       EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
     }
     {
-      const auto root =
-          base::JSONReader().Read(post_interceptor_->GetRequestBody(1));
+      const auto root = base::JSONReader().ReadDeprecated(
+          post_interceptor_->GetRequestBody(1));
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(3383, app.FindPath({"ping", "ad"})->GetInt());
       EXPECT_EQ(3383, app.FindPath({"ping", "rd"})->GetInt());
       EXPECT_TRUE(app.FindPath({"ping", "ping_freshness"})->is_string());
     }
     {
-      const auto root =
-          base::JSONReader().Read(post_interceptor_->GetRequestBody(2));
+      const auto root = base::JSONReader().ReadDeprecated(
+          post_interceptor_->GetRequestBody(2));
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(3383, app.FindPath({"ping", "rd"})->GetInt());
       EXPECT_TRUE(app.FindPath({"ping", "ping_freshness"})->is_string());
@@ -841,7 +841,7 @@
       RunThreads();
       const auto& request = post_interceptor->GetRequestBody(0);
       if (use_JSON_) {
-        const auto root = base::JSONReader().Read(request);
+        const auto root = base::JSONReader().ReadDeprecated(request);
         const auto& app =
             root->FindKey("request")->FindKey("app")->GetList()[0];
         EXPECT_EQ("ondemand", app.FindKey("installsource")->GetString());
@@ -869,7 +869,7 @@
       RunThreads();
       const auto& request = post_interceptor->GetRequestBody(0);
       if (use_JSON_) {
-        const auto root = base::JSONReader().Read(request);
+        const auto root = base::JSONReader().ReadDeprecated(request);
         const auto& app =
             root->FindKey("request")->FindKey("app")->GetList()[0];
         EXPECT_EQ("sideload", app.FindKey("installsource")->GetString());
@@ -897,7 +897,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_FALSE(app.FindKey("installsource"));
     } else {
@@ -921,7 +921,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ("webstore", app.FindKey("installsource")->GetString());
       EXPECT_EQ("external", app.FindKey("installedby")->GetString());
@@ -955,7 +955,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(true, app.FindKey("enabled")->GetBool());
       EXPECT_FALSE(app.FindKey("disabled"));
@@ -981,7 +981,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(true, app.FindKey("enabled")->GetBool());
       EXPECT_FALSE(app.FindKey("disabled"));
@@ -1007,7 +1007,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
       const auto& disabled = app.FindKey("disabled")->GetList();
@@ -1034,7 +1034,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
       const auto& disabled = app.FindKey("disabled")->GetList();
@@ -1062,7 +1062,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
       const auto& disabled = app.FindKey("disabled")->GetList();
@@ -1094,7 +1094,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
       const auto& disabled = app.FindKey("disabled")->GetList();
@@ -1145,7 +1145,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
       EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -1178,7 +1178,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
       EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -1211,7 +1211,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
       EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -1244,7 +1244,7 @@
     RunThreads();
     const auto& request = post_interceptor->GetRequestBody(0);
     if (use_JSON_) {
-      const auto root = base::JSONReader().Read(request);
+      const auto root = base::JSONReader().ReadDeprecated(request);
       const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
       EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
       EXPECT_EQ("0.9", app.FindKey("version")->GetString());
@@ -1319,7 +1319,7 @@
 
   const auto& request = post_interceptor_->GetRequestBody(0);
   if (use_JSON_) {
-    const auto root = base::JSONReader().Read(request);
+    const auto root = base::JSONReader().ReadDeprecated(request);
     const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
     EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
     EXPECT_EQ("0.9", app.FindKey("version")->GetString());
diff --git a/components/viz/common/quads/draw_quad.h b/components/viz/common/quads/draw_quad.h
index ab160c3..4cbe49f 100644
--- a/components/viz/common/quads/draw_quad.h
+++ b/components/viz/common/quads/draw_quad.h
@@ -73,8 +73,7 @@
   bool IsDebugQuad() const { return material == DEBUG_BORDER; }
 
   bool ShouldDrawWithBlending() const {
-    return needs_blending || shared_quad_state->opacity < 1.0f ||
-           shared_quad_state->blend_mode != SkBlendMode::kSrcOver;
+    return needs_blending || shared_quad_state->opacity < 1.0f;
   }
 
   // Is the left edge of this tile aligned with the originating layer's
diff --git a/components/viz/common/yuv_readback_unittest.cc b/components/viz/common/yuv_readback_unittest.cc
index def5ebf..437ecef 100644
--- a/components/viz/common/yuv_readback_unittest.cc
+++ b/components/viz/common/yuv_readback_unittest.cc
@@ -102,7 +102,8 @@
 
     std::string error_msg;
     std::unique_ptr<base::Value> trace_data =
-        base::JSONReader::ReadAndReturnError(json_data, 0, nullptr, &error_msg);
+        base::JSONReader::ReadAndReturnErrorDeprecated(json_data, 0, nullptr,
+                                                       &error_msg);
     CHECK(trace_data) << "JSON parsing failed (" << error_msg
                       << ") JSON data:" << std::endl
                       << json_data;
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 7764f9e..7d50893 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -1956,7 +1956,6 @@
                  fragment_tex_translate_x, fragment_tex_translate_y,
                  fragment_tex_scale_x, fragment_tex_scale_y);
 
-  DCHECK_EQ(quad->shared_quad_state->blend_mode, SkBlendMode::kSrcOver);
   // Blending is required for antialiasing.
   SetBlendEnabled(true);
   SetShaderOpacity(quad->shared_quad_state->opacity);
@@ -2045,9 +2044,7 @@
                  tex_coord_rect.x(), tex_coord_rect.y(), tex_coord_rect.width(),
                  tex_coord_rect.height());
 
-  DCHECK(CanApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode));
   SetBlendEnabled(quad->ShouldDrawWithBlending());
-  ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
 
   SetShaderOpacity(quad->shared_quad_state->opacity);
 
@@ -2089,7 +2086,6 @@
 
   gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
   num_triangles_drawn_ += 2;
-  RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
 }
 
 void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 521ce7e..67542b76 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -427,18 +427,24 @@
     return;
   }
 
-  // Reserve a buffer from the pool for the next frame.
+  // Reserve a buffer from the pool for the next frame. Optimization: If there
+  // are no changes in the source that need to be captured AND there are no
+  // captures currently in-flight, attempt to resurrect the last frame from the
+  // pool (and there is no need to capture anything new into the frame).
   const OracleFrameNumber oracle_frame_number = oracle_.next_frame_number();
   const gfx::Size capture_size =
       AdjustSizeForPixelFormat(oracle_.capture_size());
   scoped_refptr<VideoFrame> frame;
-  if (dirty_rect_.IsEmpty()) {
+  bool using_resurrected_frame =
+      dirty_rect_.IsEmpty() &&
+      next_capture_frame_number_ == next_delivery_frame_number_;
+  if (using_resurrected_frame) {
     frame = frame_pool_.ResurrectLastVideoFrame(pixel_format_, capture_size);
     // If the resurrection failed, promote to a full frame capture.
     if (!frame) {
       TRACE_EVENT_INSTANT0("gpu.capture", "ResurrectionFailed",
                            TRACE_EVENT_SCOPE_THREAD);
-      dirty_rect_ = kMaxRect;
+      using_resurrected_frame = false;
       frame = frame_pool_.ReserveVideoFrame(pixel_format_, capture_size);
     }
   } else {
@@ -537,8 +543,9 @@
     return;
   }
 
-  // For passive refreshes, just deliver the resurrected frame.
-  if (dirty_rect_.IsEmpty()) {
+  // If the frame is a resurrected one, just deliver it since it already
+  // contains the most up-to-date capture of the source content.
+  if (using_resurrected_frame) {
     DidCaptureFrame(frame_number, oracle_frame_number, content_rect,
                     std::move(frame));
     return;
@@ -564,7 +571,20 @@
   // just the part of the result that would have changed due to aggregated
   // damage over all the frames that weren't captured.
   request->set_result_selection(gfx::Rect(content_rect.size()));
+
+  // Clear the |dirty_rect_|, to indicate all changes at the source are now
+  // being captured. This will also enable the "frame resurrection" optimization
+  // in future calls to this method. In other words, while the source content
+  // remains unchanged, there is no need to make any more CopyOutputRequests.
+  //
+  // Note that some optimistic assumptions are being made here: 1) that this
+  // |request| will succeed and it's image data successfully transferred to the
+  // VideoFrame; and 2) that delivery of the VideoFrame to the consumer will
+  // succeed. If, later in the pipeline, either of these assumptions is
+  // violated, the |dirty_rect_| will be changed to indicate that there might
+  // still be source changes requiring capture. See MaybeDeliverFrame().
   dirty_rect_ = gfx::Rect();
+
   resolved_target_->RequestCopyOfOutput(LocalSurfaceId(), std::move(request));
 }
 
@@ -687,8 +707,11 @@
                            "success", false);
 
     // Mark the whole source as dirty, since this frame may have contained
-    // updated content that will not be delivered.
+    // updated content that will not be delivered. See the comment at the end of
+    // MaybeCaptureFrame() regarding "optimistic assumptions" for further
+    // discussion.
     dirty_rect_ = kMaxRect;
+
     ScheduleRefreshFrame();
     return;
   }
diff --git a/components/viz/test/data/image_mask_with_effect.png b/components/viz/test/data/image_mask_with_effect.png
deleted file mode 100644
index 8414527..0000000
--- a/components/viz/test/data/image_mask_with_effect.png
+++ /dev/null
Binary files differ
diff --git a/components/viz/test/data/mask_with_effect.png b/components/viz/test/data/mask_with_effect.png
deleted file mode 100644
index 8414527..0000000
--- a/components/viz/test/data/mask_with_effect.png
+++ /dev/null
Binary files differ
diff --git a/components/viz/test/data/mask_with_effect_different_size.png b/components/viz/test/data/mask_with_effect_different_size.png
deleted file mode 100644
index 82917eb..0000000
--- a/components/viz/test/data/mask_with_effect_different_size.png
+++ /dev/null
Binary files differ
diff --git a/components/webcrypto/algorithms/test_helpers.cc b/components/webcrypto/algorithms/test_helpers.cc
index 394805d..0feaaef 100644
--- a/components/webcrypto/algorithms/test_helpers.cc
+++ b/components/webcrypto/algorithms/test_helpers.cc
@@ -162,7 +162,7 @@
   re2::RE2::GlobalReplace(&file_contents, re2::RE2("\\s*//.*"), "");
 
   // Parse the JSON to a dictionary.
-  *value = base::JSONReader::Read(file_contents);
+  *value = base::JSONReader::ReadDeprecated(file_contents);
   if (!*value) {
     return ::testing::AssertionFailure()
            << "Couldn't parse test file JSON: " << file_path.value();
@@ -389,7 +389,8 @@
     const std::vector<uint8_t>& json) {
   base::StringPiece json_string(reinterpret_cast<const char*>(json.data()),
                                 json.size());
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json_string);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(json_string);
   EXPECT_TRUE(value.get());
   EXPECT_TRUE(value->is_dict());
 
diff --git a/components/webcrypto/jwk.cc b/components/webcrypto/jwk.cc
index b76d6d2f..3e7ae46 100644
--- a/components/webcrypto/jwk.cc
+++ b/components/webcrypto/jwk.cc
@@ -196,7 +196,8 @@
   base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
                                 bytes.byte_length());
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json_string);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(json_string);
   base::DictionaryValue* dict_value = nullptr;
 
   if (!value || !value->GetAsDictionary(&dict_value) || !dict_value)
diff --git a/content/app/strings/content_strings.grd b/content/app/strings/content_strings.grd
index 0ce1cc31..bc295409 100644
--- a/content/app/strings/content_strings.grd
+++ b/content/app/strings/content_strings.grd
@@ -245,6 +245,7 @@
         <ph name="WEEK">$1<ex>Week 38, 2014</ex></ph>, starting on <ph name="WEEK_START_DATE">$2<ex>September 15, 2014</ex></ph>
       </message>
 
+      <!-- Localized names for accessibility roles -->
       <message name="IDS_AX_ROLE_ARTICLE" desc="Accessibility role description for article">
         article
       </message>
@@ -604,6 +605,35 @@
         </message>
       </if>
 
+      <!-- Automatic image annotations for accessibility -->
+      <if expr="is_win">
+        <then>
+          <message name="IDS_AX_UNLABELED_IMAGE_ROLE_DESCRIPTION" desc="Accessibility role description for a graphic (image) on a web page that does not have a description for blind users.">
+            Unlabeled graphic
+          </message>
+        </then>
+        <else>
+          <message name="IDS_AX_UNLABELED_IMAGE_ROLE_DESCRIPTION" desc="Accessibility role description for an image on a web page that does not have a description for blind users.">
+            Unlabeled image
+          </message>
+        </else>
+      </if>
+      <message name="IDS_AX_IMAGE_ELIGIBLE_FOR_ANNOTATION" desc="Accessibility message spoken out loud to screen reader users to inform them that they can get a description of an image by opening the context menu.">
+        To get missing image descriptions, open the context menu.
+      </message>
+      <message name="IDS_AX_IMAGE_ANNOTATION_PENDING" desc="Accessibility message spoken out loud to screen reader users saying that the browser is in the middle of trying to get a description for an image.">
+        Getting description...
+      </message>
+      <message name="IDS_AX_IMAGE_ANNOTATION_EMPTY" desc="Accessibility message spoken out loud to screen reader users indicating that there is no description for this image.">
+        No description is available.
+      </message>
+      <message name="IDS_AX_IMAGE_ANNOTATION_ADULT" desc="Accessibility message spoken out loud to screen reader users indicating that an image appears to be something like nudity or pornography or other policy violation that is not appropriate for children.">
+        Appears to be adult content.
+      </message>
+      <message name="IDS_AX_IMAGE_ANNOTATION_PROCESS_FAILED" desc="Accessibility message spoken out loud to screen reader users that the browser was not able to get a description for an image.">
+        Unable to get a description.
+      </message>
+
       <message name="IDS_AX_AM_PM_FIELD_TEXT" desc="Accessible description of the AM/PM field in a date/time control">
         AM/PM
       </message>
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index da6578c..250227f1 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -81,6 +81,8 @@
       return ui::ToString(static_cast<ax::mojom::TextDirection>(value));
     case ax::mojom::IntAttribute::kTextPosition:
       return ui::ToString(static_cast<ax::mojom::TextPosition>(value));
+    case ax::mojom::IntAttribute::kImageAnnotationStatus:
+      return ui::ToString(static_cast<ax::mojom::ImageAnnotationStatus>(value));
     // No pretty printing necessary for these:
     case ax::mojom::IntAttribute::kActivedescendantId:
     case ax::mojom::IntAttribute::kAriaCellColumnIndex:
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 4cbb5aa..ed27057c 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -13,9 +13,11 @@
 #include "base/no_destructor.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "content/app/strings/grit/content_strings.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/common/accessibility_messages.h"
+#include "content/public/common/content_client.h"
 #include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/ax_text_utils.h"
 #include "ui/accessibility/platform/ax_unique_id.h"
@@ -1242,6 +1244,45 @@
   }
 }
 
+base::string16 BrowserAccessibility::GetLocalizedStringForImageAnnotationStatus(
+    ax::mojom::ImageAnnotationStatus status) const {
+  const ContentClient* content_client = content::GetContentClient();
+
+  int message_id = 0;
+  switch (status) {
+    case ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation:
+      message_id = IDS_AX_IMAGE_ELIGIBLE_FOR_ANNOTATION;
+      break;
+    case ax::mojom::ImageAnnotationStatus::kAnnotationPending:
+      message_id = IDS_AX_IMAGE_ANNOTATION_PENDING;
+      break;
+    case ax::mojom::ImageAnnotationStatus::kAnnotationEmpty:
+      message_id = IDS_AX_IMAGE_ANNOTATION_EMPTY;
+      break;
+    case ax::mojom::ImageAnnotationStatus::kAnnotationAdult:
+      message_id = IDS_AX_IMAGE_ANNOTATION_ADULT;
+      break;
+    case ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed:
+      message_id = IDS_AX_IMAGE_ANNOTATION_PROCESS_FAILED;
+      break;
+    case ax::mojom::ImageAnnotationStatus::kNone:
+    case ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation:
+    case ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded:
+      return base::string16();
+  }
+
+  DCHECK(message_id);
+
+  return content_client->GetLocalizedString(message_id);
+}
+
+base::string16
+BrowserAccessibility::GetLocalizedRoleDescriptionForUnlabeledImage() const {
+  const ContentClient* content_client = content::GetContentClient();
+  return content_client->GetLocalizedString(
+      IDS_AX_UNLABELED_IMAGE_ROLE_DESCRIPTION);
+}
+
 bool BrowserAccessibility::ShouldIgnoreHoveredStateForTesting() {
   BrowserAccessibilityStateImpl* accessibility_state =
       BrowserAccessibilityStateImpl::GetInstance();
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index b30c3ae..db2ca08e0 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -386,6 +386,9 @@
   int32_t CellIndexToId(int32_t cell_index) const override;
 
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
+  base::string16 GetLocalizedStringForImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus status) const override;
+  base::string16 GetLocalizedRoleDescriptionForUnlabeledImage() const override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   bool IsOffscreen() const override;
   ui::AXPlatformNode* GetTargetNodeForRelation(
diff --git a/content/browser/appcache/appcache.h b/content/browser/appcache/appcache.h
index 87fd8fa..ff137cfe7 100644
--- a/content/browser/appcache/appcache.h
+++ b/content/browser/appcache/appcache.h
@@ -39,7 +39,7 @@
 
 // Set of cached resources for an application. A cache exists as long as a
 // host is associated with it, the cache is in an appcache group or the
-// cache is being created during an appcache upate.
+// cache is being created during an appcache update.
 class CONTENT_EXPORT AppCache
     : public base::RefCounted<AppCache> {
  public:
diff --git a/content/browser/appcache/appcache_database.h b/content/browser/appcache/appcache_database.h
index e52180a..32685dc82 100644
--- a/content/browser/appcache/appcache_database.h
+++ b/content/browser/appcache/appcache_database.h
@@ -47,6 +47,7 @@
 class AppCacheDatabaseTest;
 class AppCacheStorageImplTest;
 
+// A wrapper around the SQLite database that serves one StoragePartition.
 class CONTENT_EXPORT AppCacheDatabase {
  public:
   struct CONTENT_EXPORT GroupRecord {
diff --git a/content/browser/appcache/appcache_host.h b/content/browser/appcache/appcache_host.h
index 7aac74a..2dbdff7 100644
--- a/content/browser/appcache/appcache_host.h
+++ b/content/browser/appcache/appcache_host.h
@@ -59,7 +59,7 @@
 class AppCacheUpdateJobTest;
 }
 
-// Server-side representation of an application cache host.
+// The browser-side implementation of the document hosting an application cache.
 class CONTENT_EXPORT AppCacheHost : public blink::mojom::AppCacheHost,
                                     public AppCacheStorage::Delegate,
                                     public AppCacheGroup::UpdateObserver,
diff --git a/content/browser/appcache/appcache_service_impl.h b/content/browser/appcache/appcache_service_impl.h
index f143ec77..f3188722 100644
--- a/content/browser/appcache/appcache_service_impl.h
+++ b/content/browser/appcache/appcache_service_impl.h
@@ -62,9 +62,9 @@
   std::unique_ptr<AppCacheStorage> storage_;
 };
 
-// Class that manages the application cache service. Sends notifications
-// to many frontends.  One instance per user-profile. Each instance has
-// exclusive access to its cache_directory on disk.
+// Handles operations that apply to caches across multiple renderer processes
+// for a user-profile. Each instance has exclusive access to its cache_directory
+// on disk.
 class CONTENT_EXPORT AppCacheServiceImpl : public AppCacheService {
  public:
   using OnceCompletionCallback = base::OnceCallback<void(int)>;
diff --git a/content/browser/appcache/appcache_storage_impl.h b/content/browser/appcache/appcache_storage_impl.h
index c7b389b1..528c262 100644
--- a/content/browser/appcache/appcache_storage_impl.h
+++ b/content/browser/appcache/appcache_storage_impl.h
@@ -33,6 +33,7 @@
 class AppCacheStorageImplTest;
 class ChromeAppCacheServiceTest;
 
+// Task scheduler for database read/write operations.
 class AppCacheStorageImpl : public AppCacheStorage {
  public:
   explicit AppCacheStorageImpl(AppCacheServiceImpl* service);
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index 5a3463a..c7909d4 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -90,15 +90,7 @@
   void Match(blink::mojom::FetchAPIRequestPtr request,
              blink::mojom::CacheQueryOptionsPtr match_options,
              MatchCallback callback) override {
-    content::CacheStorageCache* cache = cache_handle_.value();
-    if (!cache) {
-      std::move(callback).Run(blink::mojom::MatchResult::NewStatus(
-          CacheStorageError::kErrorNotFound));
-      return;
-    }
-
-    cache->Match(
-        std::move(request), std::move(match_options),
+    auto cb =
         base::BindOnce(
             [](blink::mojom::CacheStorageCache::MatchCallback callback,
                blink::mojom::CacheStorageError error,
@@ -111,21 +103,21 @@
               std::move(callback).Run(
                   blink::mojom::MatchResult::NewResponse(std::move(response)));
             },
-            std::move(callback)));
+            std::move(callback));
+
+    content::CacheStorageCache* cache = cache_handle_.value();
+    if (!cache) {
+      std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr);
+      return;
+    }
+
+    cache->Match(std::move(request), std::move(match_options), std::move(cb));
   }
 
   void MatchAll(blink::mojom::FetchAPIRequestPtr request,
                 blink::mojom::CacheQueryOptionsPtr match_options,
                 MatchAllCallback callback) override {
-    content::CacheStorageCache* cache = cache_handle_.value();
-    if (!cache) {
-      std::move(callback).Run(blink::mojom::MatchAllResult::NewStatus(
-          CacheStorageError::kErrorNotFound));
-      return;
-    }
-
-    cache->MatchAll(
-        std::move(request), std::move(match_options),
+    auto cb =
         base::BindOnce(
             [](blink::mojom::CacheStorageCache::MatchAllCallback callback,
                blink::mojom::CacheStorageError error,
@@ -141,21 +133,23 @@
                   blink::mojom::MatchAllResult::NewResponses(
                       std::move(responses)));
             },
-            std::move(callback)));
+            std::move(callback));
+
+    content::CacheStorageCache* cache = cache_handle_.value();
+    if (!cache) {
+      std::move(cb).Run(CacheStorageError::kErrorNotFound,
+                        std::vector<blink::mojom::FetchAPIResponsePtr>());
+      return;
+    }
+
+    cache->MatchAll(std::move(request), std::move(match_options),
+                    std::move(cb));
   }
 
   void Keys(blink::mojom::FetchAPIRequestPtr request,
             blink::mojom::CacheQueryOptionsPtr match_options,
             KeysCallback callback) override {
-    content::CacheStorageCache* cache = cache_handle_.value();
-    if (!cache) {
-      std::move(callback).Run(blink::mojom::CacheKeysResult::NewStatus(
-          CacheStorageError::kErrorNotFound));
-      return;
-    }
-
-    cache->Keys(
-        std::move(request), std::move(match_options),
+    auto cb =
         base::BindOnce(
             [](blink::mojom::CacheStorageCache::KeysCallback callback,
                blink::mojom::CacheStorageError error,
@@ -174,7 +168,15 @@
               std::move(callback).Run(
                   blink::mojom::CacheKeysResult::NewKeys(std::move(requests_)));
             },
-            std::move(callback)));
+            std::move(callback));
+
+    content::CacheStorageCache* cache = cache_handle_.value();
+    if (!cache) {
+      std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr);
+      return;
+    }
+
+    cache->Keys(std::move(request), std::move(match_options), std::move(cb));
   }
 
   void Batch(std::vector<blink::mojom::BatchOperationPtr> batch_operations,
@@ -184,20 +186,23 @@
       mojo::ReportBadMessage("CSDH_UNEXPECTED_OPERATION");
       return;
     }
+
+    auto cb = base::BindOnce(
+        [](blink::mojom::CacheStorageCache::BatchCallback callback,
+           blink::mojom::CacheStorageVerboseErrorPtr error) {
+          std::move(callback).Run(std::move(error));
+        },
+        std::move(callback));
+
     content::CacheStorageCache* cache = cache_handle_.value();
     if (!cache) {
-      std::move(callback).Run(CacheStorageVerboseError::New(
+      std::move(cb).Run(CacheStorageVerboseError::New(
           CacheStorageError::kErrorNotFound, base::nullopt));
       return;
     }
+
     cache->BatchOperation(
-        std::move(batch_operations), fail_on_duplicates,
-        base::BindOnce(
-            [](blink::mojom::CacheStorageCache::BatchCallback callback,
-               blink::mojom::CacheStorageVerboseErrorPtr error) {
-              std::move(callback).Run(std::move(error));
-            },
-            std::move(callback)),
+        std::move(batch_operations), fail_on_duplicates, std::move(cb),
         base::BindOnce(
             [](mojo::ReportBadMessageCallback bad_message_callback) {
               std::move(bad_message_callback).Run("CSDH_UNEXPECTED_OPERATION");
@@ -244,12 +249,7 @@
 
   // Mojo CacheStorage Interface implementation:
   void Keys(blink::mojom::CacheStorage::KeysCallback callback) override {
-    content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
-    if (!cache_storage) {
-      std::move(callback).Run(std::vector<base::string16>());
-      return;
-    }
-    cache_storage->EnumerateCaches(base::BindOnce(
+    auto cb = base::BindOnce(
         [](blink::mojom::CacheStorage::KeysCallback callback,
            const CacheStorageIndex& cache_index) {
           std::vector<base::string16> string16s;
@@ -258,52 +258,54 @@
           }
           std::move(callback).Run(string16s);
         },
-        std::move(callback)));
+        std::move(callback));
+
+    content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
+    if (!cache_storage) {
+      std::move(cb).Run(CacheStorageIndex());
+      return;
+    }
+
+    cache_storage->EnumerateCaches(std::move(cb));
   }
 
   void Delete(const base::string16& cache_name,
               blink::mojom::CacheStorage::DeleteCallback callback) override {
+    auto cb = std::move(callback);
+
     content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
     if (!cache_storage) {
-      std::move(callback).Run(
-          MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
+      std::move(cb).Run(MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
       return;
     }
-    cache_storage->DoomCache(base::UTF16ToUTF8(cache_name),
-                             std::move(callback));
+    cache_storage->DoomCache(base::UTF16ToUTF8(cache_name), std::move(cb));
   }
 
   void Has(const base::string16& cache_name,
            blink::mojom::CacheStorage::HasCallback callback) override {
+    auto cb = base::BindOnce(
+        [](blink::mojom::CacheStorage::HasCallback callback, bool has_cache,
+           CacheStorageError error) {
+          if (!has_cache)
+            error = CacheStorageError::kErrorNotFound;
+          std::move(callback).Run(error);
+        },
+        std::move(callback));
+
     content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
     if (!cache_storage) {
-      std::move(callback).Run(
-          MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
+      std::move(cb).Run(/* has_cache = */ false,
+                        MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
       return;
     }
-    cache_storage->HasCache(
-        base::UTF16ToUTF8(cache_name),
-        base::BindOnce(
-            [](blink::mojom::CacheStorage::HasCallback callback, bool has_cache,
-               CacheStorageError error) {
-              if (!has_cache)
-                error = CacheStorageError::kErrorNotFound;
-              std::move(callback).Run(error);
-            },
-            std::move(callback)));
+
+    cache_storage->HasCache(base::UTF16ToUTF8(cache_name), std::move(cb));
   }
 
   void Match(blink::mojom::FetchAPIRequestPtr request,
              blink::mojom::MultiCacheQueryOptionsPtr match_options,
              blink::mojom::CacheStorage::MatchCallback callback) override {
-    content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
-    if (!cache_storage) {
-      std::move(callback).Run(blink::mojom::MatchResult::NewStatus(
-          CacheStorageError::kErrorNotFound));
-      return;
-    }
-
-    auto on_match = BindOnce(
+    auto cb = BindOnce(
         [](blink::mojom::CacheStorage::MatchCallback callback,
            CacheStorageError error,
            blink::mojom::FetchAPIResponsePtr response) {
@@ -318,28 +320,28 @@
         },
         std::move(callback));
 
+    content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
+    if (!cache_storage) {
+      std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr);
+      return;
+    }
+
     if (!match_options->cache_name) {
       cache_storage->MatchAllCaches(std::move(request),
                                     std::move(match_options->query_options),
-                                    std::move(on_match));
+                                    std::move(cb));
       return;
     }
     std::string cache_name = base::UTF16ToUTF8(*match_options->cache_name);
     cache_storage->MatchCache(std::move(cache_name), std::move(request),
                               std::move(match_options->query_options),
-                              std::move(on_match));
+                              std::move(cb));
   }
 
   void Open(const base::string16& cache_name,
             blink::mojom::CacheStorage::OpenCallback callback) override {
     content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
-    if (!cache_storage) {
-      std::move(callback).Run(blink::mojom::OpenResult::NewStatus(
-          MakeErrorStorage(ErrorStorageType::kStorageHandleNull)));
-      return;
-    }
-    cache_storage->OpenCache(
-        base::UTF16ToUTF8(cache_name),
+    auto cb =
         base::BindOnce(
             [](base::WeakPtr<CacheStorageImpl> self,
                blink::mojom::CacheStorage::OpenCallback callback,
@@ -363,7 +365,15 @@
               std::move(callback).Run(
                   blink::mojom::OpenResult::NewCache(std::move(ptr_info)));
             },
-            weak_factory_.GetWeakPtr(), std::move(callback)));
+            weak_factory_.GetWeakPtr(), std::move(callback));
+
+    if (!cache_storage) {
+      std::move(cb).Run(CacheStorageCacheHandle(),
+                        MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
+      return;
+    }
+
+    cache_storage->OpenCache(base::UTF16ToUTF8(cache_name), std::move(cb));
   }
 
  private:
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index d190bab..cd57cca 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -1383,13 +1383,13 @@
   Attach();
   SendCommand("Network.enable", nullptr, true);
   SendCommand("Security.enable", nullptr, false);
-  SendCommand(
-      "Network.setRequestInterception",
-      base::JSONReader::Read("{\"patterns\": [{\"urlPattern\": \"*\"}]}"),
-      true);
+  SendCommand("Network.setRequestInterception",
+              base::JSONReader::ReadDeprecated(
+                  "{\"patterns\": [{\"urlPattern\": \"*\"}]}"),
+              true);
 
   SendCommand("Security.setIgnoreCertificateErrors",
-              base::JSONReader::Read("{\"ignore\": true}"), true);
+              base::JSONReader::ReadDeprecated("{\"ignore\": true}"), true);
 
   SendCommand("Network.clearBrowserCache", nullptr, true);
   SendCommand("Network.clearBrowserCookies", nullptr, true);
@@ -1400,8 +1400,8 @@
   std::string interceptionId;
   EXPECT_TRUE(params->GetString("interceptionId", &interceptionId));
   SendCommand("Network.continueInterceptedRequest",
-              base::JSONReader::Read("{\"interceptionId\": \"" +
-                                     interceptionId + "\"}"),
+              base::JSONReader::ReadDeprecated("{\"interceptionId\": \"" +
+                                               interceptionId + "\"}"),
               false);
   continue_observer.Wait();
   EXPECT_EQ(test_url, shell()
diff --git a/content/browser/devtools/protocol/devtools_protocol_test_support.cc b/content/browser/devtools/protocol/devtools_protocol_test_support.cc
index 14d94c8a..f74ff05 100644
--- a/content/browser/devtools/protocol/devtools_protocol_test_support.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_test_support.cc
@@ -232,7 +232,7 @@
     const std::string& message) {
   std::unique_ptr<base::DictionaryValue> root(
       static_cast<base::DictionaryValue*>(
-          base::JSONReader::Read(message).release()));
+          base::JSONReader::ReadDeprecated(message).release()));
   int id;
   if (root->GetInteger("id", &id)) {
     result_ids_.push_back(id);
diff --git a/content/browser/devtools/protocol/system_info_handler.cc b/content/browser/devtools/protocol/system_info_handler.cc
index 2cb2b8a..bdd7562 100644
--- a/content/browser/devtools/protocol/system_info_handler.cc
+++ b/content/browser/devtools/protocol/system_info_handler.cc
@@ -90,6 +90,10 @@
 
   void EndVideoEncodeAcceleratorSupportedProfile() override {}
 
+  void BeginImageDecodeAcceleratorSupportedProfile() override {}
+
+  void EndImageDecodeAcceleratorSupportedProfile() override {}
+
   void BeginOverlayCapability() override {}
 
   void EndOverlayCapability() override {}
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index bc31d2c..50901401 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -177,7 +177,8 @@
   void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
                                const std::string& message) {
     if (agent_host == page_host_.get()) {
-      std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+      std::unique_ptr<base::Value> value =
+          base::JSONReader::ReadDeprecated(message);
       if (!value || !value->is_dict())
         return;
       // Make sure this is a binding call.
diff --git a/content/browser/devtools/protocol/tracing_handler_unittest.cc b/content/browser/devtools/protocol/tracing_handler_unittest.cc
index 9db9c9c8..a8e3dba4 100644
--- a/content/browser/devtools/protocol/tracing_handler_unittest.cc
+++ b/content/browser/devtools/protocol/tracing_handler_unittest.cc
@@ -90,7 +90,7 @@
 
 TEST_F(TracingHandlerTest, GetTraceConfigFromDevToolsConfig) {
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(kCustomTraceConfigStringDevToolsStyle);
+      base::JSONReader::ReadDeprecated(kCustomTraceConfigStringDevToolsStyle);
   std::unique_ptr<base::DictionaryValue> devtools_style_dict(
       static_cast<base::DictionaryValue*>(value.release()));
 
diff --git a/content/browser/indexed_db/indexed_db_leveldb_operations.cc b/content/browser/indexed_db/indexed_db_leveldb_operations.cc
index 9469413..0d6b7905 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_operations.cc
+++ b/content/browser/indexed_db/indexed_db_leveldb_operations.cc
@@ -229,7 +229,7 @@
     if (file_size == file.Read(0, base::data(input_js), file_size)) {
       base::JSONReader reader;
       std::unique_ptr<base::DictionaryValue> val(
-          base::DictionaryValue::From(reader.ReadToValue(input_js)));
+          base::DictionaryValue::From(reader.ReadToValueDeprecated(input_js)));
       if (val)
         val->GetString("message", &message);
     }
diff --git a/content/browser/loader/loader_browsertest.cc b/content/browser/loader/loader_browsertest.cc
index cfe0b98..4fc86bc 100644
--- a/content/browser/loader/loader_browsertest.cc
+++ b/content/browser/loader/loader_browsertest.cc
@@ -30,6 +30,7 @@
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_loader_throttle.h"
@@ -152,6 +153,7 @@
   CheckTitleTest(
       net::URLRequestMockHTTPJob::GetMockUrl("content-sniffer-test0.html"),
       "Content Sniffer Test 0");
+  EXPECT_EQ("text/html", shell()->web_contents()->GetContentsMimeType());
 }
 
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, RespectNoSniffDirective) {
@@ -161,16 +163,18 @@
 
   CheckTitleTest(net::URLRequestMockHTTPJob::GetMockUrl("nosniff-test.html"),
                  "mock.http/nosniff-test.html");
+  EXPECT_EQ("text/plain", shell()->web_contents()->GetContentsMimeType());
 }
 
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, DoNotSniffHTMLFromTextPlain) {
-  // Covered by URLLoaderTest.DoNotSniffHTMLFromTextPlain.
+  // Covered by URLLoaderTest.SniffTextPlainDoesNotResultInHTML.
   if (base::FeatureList::IsEnabled(network::features::kNetworkService))
     return;
 
   CheckTitleTest(
       net::URLRequestMockHTTPJob::GetMockUrl("content-sniffer-test1.html"),
       "mock.http/content-sniffer-test1.html");
+  EXPECT_EQ("text/plain", shell()->web_contents()->GetContentsMimeType());
 }
 
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, DoNotSniffHTMLFromImageGIF) {
@@ -181,6 +185,7 @@
   CheckTitleTest(
       net::URLRequestMockHTTPJob::GetMockUrl("content-sniffer-test2.html"),
       "mock.http/content-sniffer-test2.html");
+  EXPECT_EQ("image/gif", shell()->web_contents()->GetContentsMimeType());
 }
 
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, SniffNoContentTypeNoData) {
@@ -311,7 +316,7 @@
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, SyncXMLHttpRequest_Cancelled) {
   // If network service is running in-process, we can't simulate a crash.
   if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-      IsNetworkServiceRunningInProcess()) {
+      IsInProcessNetworkService()) {
     return;
   }
 
diff --git a/content/browser/media/media_internals_unittest.cc b/content/browser/media/media_internals_unittest.cc
index 1880e9af..cb9ce20 100644
--- a/content/browser/media/media_internals_unittest.cc
+++ b/content/browser/media/media_internals_unittest.cc
@@ -66,8 +66,9 @@
     std::string utf8_update = base::UTF16ToUTF8(update);
     const std::string::size_type first_brace = utf8_update.find('{');
     const std::string::size_type last_brace = utf8_update.rfind('}');
-    std::unique_ptr<base::Value> output_value = base::JSONReader::Read(
-        utf8_update.substr(first_brace, last_brace - first_brace + 1));
+    std::unique_ptr<base::Value> output_value =
+        base::JSONReader::ReadDeprecated(
+            utf8_update.substr(first_brace, last_brace - first_brace + 1));
     CHECK(output_value);
 
     base::DictionaryValue* output_dict = nullptr;
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index b2b1f74..6de7f2f 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -141,9 +141,6 @@
         OnMediaEffectivelyFullscreenChanged)
     IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaSizeChanged,
                         OnMediaSizeChanged)
-    IPC_MESSAGE_HANDLER(
-        MediaPlayerDelegateHostMsg_OnSetPictureInPictureCustomControls,
-        OnSetPictureInPictureCustomControls)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -273,17 +270,6 @@
   web_contents_impl()->MediaResized(size, id);
 }
 
-void MediaWebContentsObserver::OnSetPictureInPictureCustomControls(
-    RenderFrameHost* render_frame_host,
-    int delegate_id,
-    const std::vector<blink::PictureInPictureControlInfo>& controls) {
-  PictureInPictureWindowControllerImpl* pip_controller =
-      PictureInPictureWindowControllerImpl::FromWebContents(
-          web_contents_impl());
-  if (pip_controller)
-    pip_controller->SetPictureInPictureCustomControls(controls);
-}
-
 void MediaWebContentsObserver::ClearWakeLocks(
     RenderFrameHost* render_frame_host) {
   std::set<MediaPlayerId> video_players;
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h
index aaffbc3f..36e701f 100644
--- a/content/browser/media/media_web_contents_observer.h
+++ b/content/browser/media/media_web_contents_observer.h
@@ -24,7 +24,6 @@
 
 namespace blink {
 enum class WebFullscreenVideoStatus;
-struct PictureInPictureControlInfo;
 }  // namespace blink
 
 namespace media {
@@ -126,10 +125,6 @@
   void OnMediaMutedStatusChanged(RenderFrameHost* render_frame_host,
                                  int delegate_id,
                                  bool muted);
-  void OnSetPictureInPictureCustomControls(
-      RenderFrameHost* render_frame_host,
-      int delegate_id,
-      const std::vector<blink::PictureInPictureControlInfo>& controls);
 
   // Clear |render_frame_host|'s tracking entry for its WakeLocks.
   void ClearWakeLocks(RenderFrameHost* render_frame_host);
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index ffadd93..1342957 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -187,6 +187,14 @@
 
 void MediaSessionImpl::OnWebContentsFocused(RenderWidgetHost*) {
   focused_ = true;
+
+#if !defined(OS_ANDROID) && !defined(OS_MACOSX)
+  // If we have just gained focus and we have audio focus we should re-request
+  // system audio focus. This will ensure this media session is towards the top
+  // of the stack if we have multiple sessions active at the same time.
+  if (audio_focus_state_ == State::ACTIVE)
+    RequestSystemAudioFocus(desired_audio_focus_type_);
+#endif
 }
 
 void MediaSessionImpl::OnWebContentsLostFocus(RenderWidgetHost*) {
diff --git a/content/browser/media/session/media_session_impl_unittest.cc b/content/browser/media/session/media_session_impl_unittest.cc
index e559d9d..a0ffe56 100644
--- a/content/browser/media/session/media_session_impl_unittest.cc
+++ b/content/browser/media/session/media_session_impl_unittest.cc
@@ -575,6 +575,8 @@
   }
 }
 
+#if defined(OS_MACOSX)
+
 TEST_F(MediaSessionImplTest, TabFocusDoesNotCauseAudioFocus) {
   MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
   SetDelegateForTests(GetMediaSession(), delegate);
@@ -591,6 +593,59 @@
   EXPECT_EQ(1, delegate->request_audio_focus_count());
 }
 
+#else  // defined(OS_MACOSX)
+
+TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Active) {
+  MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
+  SetDelegateForTests(GetMediaSession(), delegate);
+
+  {
+    MockMediaSessionMojoObserver observer(*GetMediaSession());
+    RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
+    FlushForTesting(GetMediaSession());
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+  }
+
+  EXPECT_EQ(1, delegate->request_audio_focus_count());
+  GetMediaSession()->OnWebContentsFocused(nullptr);
+  EXPECT_EQ(2, delegate->request_audio_focus_count());
+}
+
+TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Inactive) {
+  MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
+  SetDelegateForTests(GetMediaSession(), delegate);
+  EXPECT_EQ(MediaSessionInfo::SessionState::kInactive,
+            GetState(GetMediaSession()));
+
+  EXPECT_EQ(0, delegate->request_audio_focus_count());
+  GetMediaSession()->OnWebContentsFocused(nullptr);
+  EXPECT_EQ(0, delegate->request_audio_focus_count());
+}
+
+TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Suspended) {
+  MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
+  SetDelegateForTests(GetMediaSession(), delegate);
+
+  {
+    MockMediaSessionMojoObserver observer(*GetMediaSession());
+    RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
+    FlushForTesting(GetMediaSession());
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+  }
+
+  {
+    MockMediaSessionMojoObserver observer(*GetMediaSession());
+    GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+  }
+
+  EXPECT_EQ(1, delegate->request_audio_focus_count());
+  GetMediaSession()->OnWebContentsFocused(nullptr);
+  EXPECT_EQ(1, delegate->request_audio_focus_count());
+}
+
+#endif  // defined(OS_MACOSX)
+
 #endif  // !defined(OS_ANDROID)
 
 }  // namespace content
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 9b314e2a..3d74389c 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -368,7 +368,7 @@
 
 IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                        MemoryPressureSentToNetworkProcess) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
 
   network::mojom::NetworkServiceTestPtr network_service_test;
diff --git a/content/browser/network_service_restart_browsertest.cc b/content/browser/network_service_restart_browsertest.cc
index 05ffffa..0ad9d31 100644
--- a/content/browser/network_service_restart_browsertest.cc
+++ b/content/browser/network_service_restart_browsertest.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -304,7 +305,7 @@
 
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        NetworkServiceProcessRecovery) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   network::mojom::NetworkContextPtr network_context = CreateNetworkContext();
   EXPECT_EQ(net::OK, LoadBasicRequest(network_context.get(), GetTestURL()));
@@ -338,7 +339,7 @@
 // This test verifies basic functionality of RegisterNetworkServiceCrashHandler
 // and UnregisterNetworkServiceCrashHandler.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, CrashHandlers) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   network::mojom::NetworkContextPtr network_context = CreateNetworkContext();
   EXPECT_TRUE(network_context.is_bound());
@@ -389,7 +390,7 @@
 // after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        StoragePartitionImplGetNetworkContext) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -414,7 +415,7 @@
 // Make sure |URLLoaderFactoryGetter| returns valid interface after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        URLLoaderFactoryGetterGetNetworkFactory) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -444,7 +445,7 @@
 // crashes.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        BrowserIOSharedURLLoaderFactory) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -471,7 +472,7 @@
 // it's called after the StoragePartition is deleted.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        BrowserIOSharedFactoryAfterStoragePartitionGone) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   base::ScopedAllowBlockingForTesting allow_blocking;
   std::unique_ptr<ShellBrowserContext> browser_context =
@@ -492,7 +493,7 @@
 // Make sure basic navigation works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        NavigationURLLoaderBasic) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -514,7 +515,7 @@
 
 // Make sure basic XHR works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, BasicXHR) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -541,7 +542,7 @@
 // |StoragePartition::GetURLLoaderFactoryForBrowserProcess()| continues to work
 // after crashes.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, BrowserUIFactory) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   auto* partition =
       BrowserContext::GetDefaultStoragePartition(browser_context());
@@ -561,7 +562,7 @@
 // it's called after the StoragePartition is deleted.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        BrowserUIFactoryAfterStoragePartitionGone) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   base::ScopedAllowBlockingForTesting allow_blocking;
   std::unique_ptr<ShellBrowserContext> browser_context =
@@ -590,7 +591,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        MAYBE_BrowserIOFactoryInfo) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   auto* partition =
       BrowserContext::GetDefaultStoragePartition(browser_context());
@@ -614,7 +615,7 @@
 // |StoragePartition::GetURLLoaderFactoryForBrowserProcessIOThread()| continues
 // to work after crashes.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, BrowserIOFactory) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   auto* partition =
       BrowserContext::GetDefaultStoragePartition(browser_context());
@@ -635,7 +636,7 @@
 
 // Make sure the window from |window.open()| can load XHR after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, WindowOpenXHR) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -660,7 +661,7 @@
 
 // Make sure worker fetch works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, WorkerFetch) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -685,7 +686,7 @@
 
 // Make sure multiple workers are tracked correctly and work after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, MultipleWorkerFetch) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -728,7 +729,7 @@
 // a fetch handler works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        FetchFromServiceWorkerControlledPage_NoFetchHandler) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -771,7 +772,7 @@
 // handler but falls back to the network works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        FetchFromServiceWorkerControlledPage_PassThrough) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -814,7 +815,7 @@
 // handler and responds with fetch() works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        FetchFromServiceWorkerControlledPage_RespondWithFetch) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -856,7 +857,7 @@
 
 // Make sure fetch from service worker context works after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, ServiceWorkerFetch) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -901,7 +902,7 @@
 #endif
 // Make sure shared workers terminate after crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, MAYBE_SharedWorker) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
@@ -936,7 +937,7 @@
 // after process closed.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        GetNetworkUsagesClosed) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   EXPECT_TRUE(NavigateToURL(shell(), GetTestURL()));
   Shell* shell2 = CreateBrowser();
@@ -978,7 +979,7 @@
 // crash. See 'network_usage_accumulator_unittest' for quantified tests.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        GetNetworkUsagesCrashed) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   EXPECT_TRUE(NavigateToURL(shell(), GetTestURL()));
   Shell* shell2 = CreateBrowser();
@@ -1013,7 +1014,7 @@
 
 // Make sure cookie access doesn't hang or fail after a network process crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, Cookies) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   auto* web_contents = shell()->web_contents();
   ASSERT_TRUE(
@@ -1056,7 +1057,7 @@
 // Make sure that "trusted" plugins continue to be able to issue cross-origin
 // requests after a network process crash.
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, Plugin) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   auto* web_contents = shell()->web_contents();
   ASSERT_TRUE(NavigateToURL(web_contents,
@@ -1126,7 +1127,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
                        MAYBE_SyncCallDuringRestart) {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     return;
   network::mojom::NetworkServiceTestPtr network_service_test;
   base::RunLoop run_loop;
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
index 6fc0fc2a9..f430ff6 100644
--- a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include "content/common/media/media_player_delegate_messages.h"
 #include "content/public/browser/overlay_window.h"
@@ -47,9 +46,6 @@
   void Close() override {}
   void ShowInactive() override {}
   void Hide() override {}
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>& controls)
-      override {}
   bool IsVisible() const override { return false; }
   bool IsAlwaysOnTop() const override { return false; }
   ui::Layer* GetLayer() override { return nullptr; }
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 824a42b3..240fbdc 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
@@ -18,7 +18,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_client.h"
-#include "media/base/media_switches.h"
 #include "ui/compositor/layer.h"
 
 namespace content {
@@ -98,12 +97,6 @@
   return window_->GetBounds().size();
 }
 
-void PictureInPictureWindowControllerImpl::SetPictureInPictureCustomControls(
-    const std::vector<blink::PictureInPictureControlInfo>& controls) {
-  DCHECK(window_);
-  window_->SetPictureInPictureCustomControls(controls);
-}
-
 void PictureInPictureWindowControllerImpl::Close(bool should_pause_video,
                                                  bool should_reset_pip_player) {
   if (!window_ || !window_->IsVisible())
@@ -232,16 +225,6 @@
   return true /* playing */;
 }
 
-void PictureInPictureWindowControllerImpl::CustomControlPressed(
-    const std::string& control_id) {
-  DCHECK(window_);
-
-  media_player_id_->render_frame_host->Send(
-      new MediaPlayerDelegateMsg_ClickPictureInPictureControl(
-          media_player_id_->render_frame_host->GetRoutingID(),
-          media_player_id_->delegate_id, control_id));
-}
-
 void PictureInPictureWindowControllerImpl::UpdateMediaPlayerId() {
   media_player_id_ = service_ ? service_->player_id() : base::nullopt;
   UpdatePlaybackState(IsPlayerActive(), !media_player_id_.has_value());
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
index 9e2516c..eb3834b 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -45,8 +45,6 @@
                             bool should_reset_pip_player) override;
   CONTENT_EXPORT void CloseAndFocusInitiator() override;
   CONTENT_EXPORT void OnWindowDestroyed() override;
-  CONTENT_EXPORT void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>& controls) override;
   CONTENT_EXPORT void EmbedSurface(const viz::SurfaceId& surface_id,
                                    const gfx::Size& natural_size) override;
   CONTENT_EXPORT OverlayWindow* GetWindowForTesting() override;
@@ -54,8 +52,6 @@
   CONTENT_EXPORT bool IsPlayerActive() override;
   CONTENT_EXPORT WebContents* GetInitiatorWebContents() override;
   CONTENT_EXPORT bool TogglePlayPause() override;
-  CONTENT_EXPORT void CustomControlPressed(
-      const std::string& control_id) override;
   CONTENT_EXPORT void UpdatePlaybackState(bool is_playing,
                                           bool reached_end_of_stream) override;
   CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override;
diff --git a/content/browser/renderer_host/input/mouse_latency_browsertest.cc b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
index a7fef82a..e53d9ff 100644
--- a/content/browser/renderer_host/input/mouse_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
@@ -168,7 +168,7 @@
       std::unique_ptr<const base::DictionaryValue> metadata,
       base::RefCountedString* trace_data_string) {
     std::unique_ptr<base::Value> trace_data =
-        base::JSONReader::Read(trace_data_string->data());
+        base::JSONReader::ReadDeprecated(trace_data_string->data());
     ASSERT_TRUE(trace_data);
     trace_data_ = trace_data->Clone();
     runner_->Quit();
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 1f8d0e7..15fb21b 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -349,7 +349,7 @@
 
     base::JSONReader json_reader;
     std::unique_ptr<base::Value> params =
-        json_reader.ReadToValue(pointer_actions_json);
+        json_reader.ReadToValueDeprecated(pointer_actions_json);
     ASSERT_TRUE(params.get()) << json_reader.GetErrorMessage();
     ActionsParser actions_parser(params.get());
 
@@ -388,7 +388,7 @@
 
     base::JSONReader json_reader;
     std::unique_ptr<base::Value> params =
-        json_reader.ReadToValue(pointer_actions_json);
+        json_reader.ReadToValueDeprecated(pointer_actions_json);
     ASSERT_TRUE(params.get()) << json_reader.GetErrorMessage();
     ActionsParser actions_parser(params.get());
 
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
index fcd00494..96681d2 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
@@ -37,7 +37,7 @@
 namespace {
 
 bool JSONToPoint(const std::string& str, gfx::PointF* point) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
   if (!value)
     return false;
   base::DictionaryValue* root;
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index b94258e6..d88f2fb 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "content/browser/renderer_host/input/input_router_impl.h"
 #include "content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h"
 #include "content/browser/renderer_host/input/touch_action_filter.h"
@@ -17,6 +18,8 @@
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/input/synthetic_web_input_event_builders.h"
+#include "content/common/view_messages.h"
+#include "content/common/widget_messages.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test_utils.h"
@@ -24,6 +27,7 @@
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -429,4 +433,107 @@
   EXPECT_TRUE(filter->allowed_touch_action().has_value());
 }
 
+// The plumbing that this test is verifying is not utilized on Mac/Android,
+// where popup menus don't create a popup RenderWidget, but rather they trigger
+// a FrameHostMsg_ShowPopup to ask the browser to build and display the actual
+// popup using native controls.
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostSitePerProcessTest,
+                       BrowserClosesSelectPopup) {
+  // Navigate to a page with a <select> element.
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/site_isolation/page-with-select.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  auto* contents = static_cast<WebContentsImpl*>(shell()->web_contents());
+  FrameTreeNode* root = contents->GetFrameTree()->root();
+  RenderFrameHostImpl* root_frame_host = root->current_frame_host();
+  RenderProcessHost* process = root_frame_host->GetProcess();
+
+  // Open the <select> menu by focusing it and sending a space key
+  // at the focused node. This creates a popup widget.
+  NativeWebKeyboardEvent event(
+      blink::WebKeyboardEvent::kChar, blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  event.text[0] = ' ';
+
+  // A class to wait for ViewHostMsg_ShowWidget.
+  class WaitForShowWidgetFilter : public ObserveMessageFilter {
+   public:
+    explicit WaitForShowWidgetFilter()
+        : ObserveMessageFilter(ViewMsgStart, ViewHostMsg_ShowWidget::ID) {}
+
+    bool OnMessageReceived(const IPC::Message& message) override {
+      IPC_BEGIN_MESSAGE_MAP(WaitForShowWidgetFilter, message)
+        IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
+      IPC_END_MESSAGE_MAP()
+      return ObserveMessageFilter::OnMessageReceived(message);
+    }
+
+    int routing_id() const { return routing_id_; }
+
+   private:
+    ~WaitForShowWidgetFilter() override = default;
+
+    void OnShowWidget(int routing_id, const gfx::Rect& initial_rect) {
+      routing_id_ = routing_id;
+    }
+
+    int routing_id_ = 0;
+
+    DISALLOW_COPY_AND_ASSIGN(WaitForShowWidgetFilter);
+  };
+
+  for (int i = 0; i < 2; ++i) {
+    bool browser_closes = i == 0;
+
+    // This focuses and opens the select box, creating a popup RenderWidget. We
+    // wait for the RenderWidgetHost to be shown.
+    auto filter = base::MakeRefCounted<WaitForShowWidgetFilter>();
+    process->AddFilter(filter.get());
+    EXPECT_TRUE(ExecuteScript(root_frame_host, "focusSelectMenu();"));
+    root_frame_host->GetRenderWidgetHost()->ForwardKeyboardEvent(event);
+    filter->Wait();
+
+    // The popup RenderWidget will get its own routing id.
+    int popup_routing_id = filter->routing_id();
+    EXPECT_TRUE(popup_routing_id);
+    // Grab a pointer to the popup RenderWidget.
+    RenderWidgetHost* popup_widget_host =
+        RenderWidgetHost::FromID(process->GetID(), popup_routing_id);
+    ASSERT_TRUE(popup_widget_host);
+    ASSERT_NE(popup_widget_host, root_frame_host->GetRenderWidgetHost());
+
+    // A class to wait for WidgetHostMsg_Close_ACK.
+    auto close_filter = base::MakeRefCounted<ObserveMessageFilter>(
+        WidgetMsgStart, WidgetHostMsg_Close_ACK::ID);
+    process->AddFilter(close_filter.get());
+
+    if (browser_closes) {
+      // Close the popup RenderWidget from the browser side.
+      auto* popup_widget_host_impl =
+          static_cast<RenderWidgetHostImpl*>(popup_widget_host);
+      popup_widget_host_impl->ShutdownAndDestroyWidget(true);
+    } else {
+      // Close the popup RenderWidget from the renderer side by removing focus.
+      EXPECT_TRUE(
+          ExecuteScript(root_frame_host, "document.activeElement.blur()"));
+    }
+    // In either case, wait until closing the popup RenderWidget is complete to
+    // know it worked by waiting for the WidgetHostMsg_Close_ACK.
+    close_filter->Wait();
+
+    // Ensure the renderer didn't explode :).
+    {
+      base::string16 title_when_done[] = {base::UTF8ToUTF16("done 0"),
+                                          base::UTF8ToUTF16("done 1")};
+      TitleWatcher title_watcher(shell()->web_contents(), title_when_done[i]);
+      EXPECT_TRUE(ExecuteScript(root_frame_host,
+                                JsReplace("document.title='done $1'", i)));
+      EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_done[i]);
+    }
+  }
+}
+#endif
+
 }  // namespace content
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index f4e151c..c14c5f2 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -192,6 +192,7 @@
                          url_loader_factory_getter_.get());
   wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id());
   wrapper_->process_manager()->SetNewProcessIdForTest(new_render_process_id());
+  wrapper_->InitializeResourceContext(browser_context_->GetResourceContext());
 
   // Install a mocked mojom::Renderer interface to catch requests to
   // establish Mojo connection for EWInstanceClient.
@@ -345,12 +346,6 @@
     std::move(callback).Run();
 }
 
-void EmbeddedWorkerTestHelper::OnActivateEvent(
-    blink::mojom::ServiceWorker::DispatchActivateEventCallback callback) {
-  dispatched_events()->push_back(Event::Activate);
-  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
-}
-
 void EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent(
     blink::mojom::BackgroundFetchRegistrationPtr registration,
     blink::mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback
@@ -386,20 +381,6 @@
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
 }
 
-void EmbeddedWorkerTestHelper::OnExtendableMessageEvent(
-    blink::mojom::ExtendableMessageEventPtr event,
-    blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback
-        callback) {
-  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
-}
-
-void EmbeddedWorkerTestHelper::OnInstallEvent(
-    blink::mojom::ServiceWorker::DispatchInstallEventCallback callback) {
-  dispatched_events()->push_back(Event::Install);
-  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
-                          true /* has_fetch_handler */);
-}
-
 void EmbeddedWorkerTestHelper::OnFetchEvent(
     int /* embedded_worker_id */,
     blink::mojom::FetchAPIRequestPtr /* request */,
@@ -480,13 +461,6 @@
   return std::make_unique<FakeServiceWorker>(this);
 }
 
-void EmbeddedWorkerTestHelper::OnActivateEventStub(
-    blink::mojom::ServiceWorker::DispatchActivateEventCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnActivateEvent,
-                                AsWeakPtr(), std::move(callback)));
-}
-
 void EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEventStub(
     blink::mojom::BackgroundFetchRegistrationPtr registration,
     blink::mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback
@@ -541,23 +515,6 @@
                      AsWeakPtr(), cookie, cause, std::move(callback)));
 }
 
-void EmbeddedWorkerTestHelper::OnExtendableMessageEventStub(
-    blink::mojom::ExtendableMessageEventPtr event,
-    blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback
-        callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&EmbeddedWorkerTestHelper::OnExtendableMessageEvent,
-                     AsWeakPtr(), std::move(event), std::move(callback)));
-}
-
-void EmbeddedWorkerTestHelper::OnInstallEventStub(
-    blink::mojom::ServiceWorker::DispatchInstallEventCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnInstallEvent,
-                                AsWeakPtr(), std::move(callback)));
-}
-
 void EmbeddedWorkerTestHelper::OnFetchEventStub(
     int embedded_worker_id,
     blink::mojom::FetchAPIRequestPtr request,
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index f4bf3e48..de50556 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -90,15 +90,11 @@
 // See embedded_worker_instance_unittest.cc for more example usages.
 class EmbeddedWorkerTestHelper {
  public:
-  enum class Event { Install, Activate };
-
   // If |user_data_directory| is empty, the context makes storage stuff in
   // memory.
   explicit EmbeddedWorkerTestHelper(const base::FilePath& user_data_directory);
   virtual ~EmbeddedWorkerTestHelper();
 
-  std::vector<Event>* dispatched_events() { return &events_; }
-
   ServiceWorkerContextCore* context();
   ServiceWorkerContextWrapper* context_wrapper() { return wrapper_.get(); }
   void ShutdownContext();
@@ -176,8 +172,6 @@
 
  protected:
   // TODO(falken): Remove these and use FakeServiceWorker instead.
-  virtual void OnActivateEvent(
-      blink::mojom::ServiceWorker::DispatchActivateEventCallback callback);
   virtual void OnBackgroundFetchAbortEvent(
       blink::mojom::BackgroundFetchRegistrationPtr registration,
       blink::mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback
@@ -198,12 +192,6 @@
       const net::CanonicalCookie& cookie,
       ::network::mojom::CookieChangeCause cause,
       blink::mojom::ServiceWorker::DispatchCookieChangeEventCallback callback);
-  virtual void OnExtendableMessageEvent(
-      blink::mojom::ExtendableMessageEventPtr event,
-      blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback
-          callback);
-  virtual void OnInstallEvent(
-      blink::mojom::ServiceWorker::DispatchInstallEventCallback callback);
   virtual void OnFetchEvent(
       int embedded_worker_id,
       blink::mojom::FetchAPIRequestPtr request,
@@ -264,8 +252,6 @@
   class MockRendererInterface;
 
   // TODO(falken): Remove these and use FakeServiceWorker instead.
-  void OnActivateEventStub(
-      blink::mojom::ServiceWorker::DispatchActivateEventCallback callback);
   void OnBackgroundFetchAbortEventStub(
       blink::mojom::BackgroundFetchRegistrationPtr registration,
       blink::mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback
@@ -290,8 +276,6 @@
       blink::mojom::ExtendableMessageEventPtr event,
       blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback
           callback);
-  void OnInstallEventStub(
-      blink::mojom::ServiceWorker::DispatchInstallEventCallback callback);
   void OnFetchEventStub(
       int embedded_worker_id,
       blink::mojom::FetchAPIRequestPtr request,
@@ -369,7 +353,6 @@
                ServiceWorkerRegistrationObjectInfoPtr /* registration_info */>
       embedded_worker_id_registration_info_map_;
 
-  std::vector<Event> events_;
   scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_;
   std::unique_ptr<MockNetworkURLLoaderFactory> default_network_loader_factory_;
 
diff --git a/content/browser/service_worker/fake_service_worker.cc b/content/browser/service_worker/fake_service_worker.cc
index 9a84517..77f09a5 100644
--- a/content/browser/service_worker/fake_service_worker.cc
+++ b/content/browser/service_worker/fake_service_worker.cc
@@ -21,7 +21,7 @@
 void FakeServiceWorker::Bind(blink::mojom::ServiceWorkerRequest request) {
   binding_.Bind(std::move(request));
   binding_.set_connection_error_handler(base::BindOnce(
-      &FakeServiceWorker::OnConnectionError, base::Unretained(this)));
+      &FakeServiceWorker::CallOnConnectionError, base::Unretained(this)));
 }
 
 void FakeServiceWorker::RunUntilInitializeGlobalScope() {
@@ -60,12 +60,13 @@
 
 void FakeServiceWorker::DispatchInstallEvent(
     DispatchInstallEventCallback callback) {
-  helper_->OnInstallEventStub(std::move(callback));
+  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
+                          true /* has_fetch_handler */);
 }
 
 void FakeServiceWorker::DispatchActivateEvent(
     DispatchActivateEventCallback callback) {
-  helper_->OnActivateEventStub(std::move(callback));
+  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
 }
 
 void FakeServiceWorker::DispatchBackgroundFetchAbortEvent(
@@ -171,14 +172,14 @@
 void FakeServiceWorker::DispatchExtendableMessageEvent(
     blink::mojom::ExtendableMessageEventPtr event,
     DispatchExtendableMessageEventCallback callback) {
-  helper_->OnExtendableMessageEventStub(std::move(event), std::move(callback));
+  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
 }
 
 void FakeServiceWorker::DispatchExtendableMessageEventWithCustomTimeout(
     blink::mojom::ExtendableMessageEventPtr event,
     base::TimeDelta timeout,
     DispatchExtendableMessageEventWithCustomTimeoutCallback callback) {
-  helper_->OnExtendableMessageEventStub(std::move(event), std::move(callback));
+  std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
 }
 
 void FakeServiceWorker::Ping(PingCallback callback) {
@@ -194,4 +195,9 @@
   helper_->RemoveServiceWorker(this);
 }
 
+void FakeServiceWorker::CallOnConnectionError() {
+  // Call OnConnectionError(), which subclasses can override.
+  OnConnectionError();
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/fake_service_worker.h b/content/browser/service_worker/fake_service_worker.h
index 6e00902..846e2f59 100644
--- a/content/browser/service_worker/fake_service_worker.h
+++ b/content/browser/service_worker/fake_service_worker.h
@@ -100,8 +100,10 @@
   void Ping(PingCallback callback) override;
   void SetIdleTimerDelayToZero() override;
 
+  virtual void OnConnectionError();
+
  private:
-  void OnConnectionError();
+  void CallOnConnectionError();
 
   // |helper_| owns |this|.
   EmbeddedWorkerTestHelper* const helper_;
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 2d67a21..1753b6b 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -2556,7 +2556,7 @@
       kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript,
       "text/javascript");
 
-  std::unique_ptr<base::Value> result = base::JSONReader::Read(
+  std::unique_ptr<base::Value> result = base::JSONReader::ReadDeprecated(
       LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED"));
 
   // The page request must be sent only once, since the worker responded with
@@ -2613,7 +2613,7 @@
       kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript,
       "text/javascript");
 
-  std::unique_ptr<base::Value> result = base::JSONReader::Read(
+  std::unique_ptr<base::Value> result = base::JSONReader::ReadDeprecated(
       LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED"));
 
   // The page request must be sent only once, since the worker responded with
@@ -3711,7 +3711,7 @@
                                "document.body.textContent");
   ASSERT_TRUE(result.error.empty());
   std::unique_ptr<base::DictionaryValue> dict = base::DictionaryValue::From(
-      base::JSONReader::Read(result.ExtractString()));
+      base::JSONReader::ReadDeprecated(result.ExtractString()));
   ASSERT_TRUE(dict);
 
   // Default headers are present.
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index 7c5b49b..afb36f3b 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -17,6 +17,7 @@
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_core_observer.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_storage.h"
@@ -87,28 +88,49 @@
             registration->update_via_cache());
 }
 
-class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
+class InstallActivateWorker : public FakeServiceWorker {
  public:
-  RejectInstallTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+  InstallActivateWorker(EmbeddedWorkerTestHelper* helper)
+      : FakeServiceWorker(helper) {}
+  ~InstallActivateWorker() override = default;
 
-  void OnInstallEvent(blink::mojom::ServiceWorker::DispatchInstallEventCallback
-                          callback) override {
-    dispatched_events()->push_back(Event::Install);
-    std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
-                            true /* has_fetch_handler */);
+  const std::vector<ServiceWorkerMetrics::EventType>& events() const {
+    return events_;
   }
-};
 
-class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
- public:
-  RejectActivateTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+  void SetToRejectInstall() { reject_install_ = true; }
 
-  void OnActivateEvent(
+  void SetToRejectActivate() { reject_activate_ = true; }
+
+  void DispatchInstallEvent(
+      blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)
+      override {
+    events_.emplace_back(ServiceWorkerMetrics::EventType::INSTALL);
+    std::move(callback).Run(
+        reject_install_ ? blink::mojom::ServiceWorkerEventStatus::REJECTED
+                        : blink::mojom::ServiceWorkerEventStatus::COMPLETED,
+        true /* has_fetch_handler */);
+  }
+
+  void DispatchActivateEvent(
       blink::mojom::ServiceWorker::DispatchActivateEventCallback callback)
       override {
-    dispatched_events()->push_back(Event::Activate);
-    std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED);
+    events_.emplace_back(ServiceWorkerMetrics::EventType::ACTIVATE);
+    std::move(callback).Run(
+        reject_activate_ ? blink::mojom::ServiceWorkerEventStatus::REJECTED
+                         : blink::mojom::ServiceWorkerEventStatus::COMPLETED);
   }
+
+  void OnConnectionError() override {
+    // Do nothing. This allows the object to stay until the test is over, so
+    // |events_| can be accessed even after the worker is stopped in the case of
+    // rejected install.
+  }
+
+ private:
+  std::vector<ServiceWorkerMetrics::EventType> events_;
+  bool reject_install_ = false;
+  bool reject_activate_ = false;
 };
 
 enum NotificationType {
@@ -398,6 +420,8 @@
       helper_
           ->AddNewPendingInstanceClient<RecordableEmbeddedWorkerInstanceClient>(
               helper_.get());
+  auto* worker =
+      helper_->AddNewPendingServiceWorker<InstallActivateWorker>(helper_.get());
 
   int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId;
   bool called = false;
@@ -408,14 +432,12 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
 
-  ASSERT_EQ(2u, helper_->dispatched_events()->size());
+  ASSERT_EQ(2u, worker->events().size());
   ASSERT_EQ(1u, client->events().size());
   EXPECT_EQ(RecordableEmbeddedWorkerInstanceClient::Message::StartWorker,
             client->events()[0]);
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Install,
-            helper_->dispatched_events()->at(0));
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Activate,
-            helper_->dispatched_events()->at(1));
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::INSTALL, worker->events()[0]);
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::ACTIVATE, worker->events()[1]);
 
   EXPECT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, registration_id);
 
@@ -444,14 +466,13 @@
   blink::mojom::ServiceWorkerRegistrationOptions options;
   options.scope = scope;
 
-  helper_.reset();  // Make sure the process lookups stay overridden.
-  helper_.reset(new RejectInstallTestHelper);
-  helper_->context_wrapper()->AddObserver(this);
-
   auto* client =
       helper_
           ->AddNewPendingInstanceClient<RecordableEmbeddedWorkerInstanceClient>(
               helper_.get());
+  auto* worker =
+      helper_->AddNewPendingServiceWorker<InstallActivateWorker>(helper_.get());
+  worker->SetToRejectInstall();
 
   int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId;
   bool called = false;
@@ -462,12 +483,11 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
 
-  ASSERT_EQ(1u, helper_->dispatched_events()->size());
+  ASSERT_EQ(1u, worker->events().size());
   ASSERT_EQ(2u, client->events().size());
   EXPECT_EQ(RecordableEmbeddedWorkerInstanceClient::Message::StartWorker,
             client->events()[0]);
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Install,
-            helper_->dispatched_events()->at(0));
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::INSTALL, worker->events()[0]);
   EXPECT_EQ(RecordableEmbeddedWorkerInstanceClient::Message::StopWorker,
             client->events()[1]);
 
@@ -494,14 +514,13 @@
   blink::mojom::ServiceWorkerRegistrationOptions options;
   options.scope = scope;
 
-  helper_.reset();
-  helper_.reset(new RejectActivateTestHelper);
-  helper_->context_wrapper()->AddObserver(this);
-
   auto* client =
       helper_
           ->AddNewPendingInstanceClient<RecordableEmbeddedWorkerInstanceClient>(
               helper_.get());
+  auto* worker =
+      helper_->AddNewPendingServiceWorker<InstallActivateWorker>(helper_.get());
+  worker->SetToRejectActivate();
 
   int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId;
   bool called = false;
@@ -512,14 +531,12 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
 
-  ASSERT_EQ(2u, helper_->dispatched_events()->size());
+  ASSERT_EQ(2u, worker->events().size());
   ASSERT_EQ(1u, client->events().size());
   EXPECT_EQ(RecordableEmbeddedWorkerInstanceClient::Message::StartWorker,
             client->events()[0]);
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Install,
-            helper_->dispatched_events()->at(0));
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Activate,
-            helper_->dispatched_events()->at(1));
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::INSTALL, worker->events()[0]);
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::ACTIVATE, worker->events()[1]);
 
   EXPECT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, registration_id);
 
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 929b637..825e994e 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -301,18 +301,48 @@
   ASSERT_NE(registration1, registration2);
 }
 
+class RecordInstallActivateWorker : public FakeServiceWorker {
+ public:
+  RecordInstallActivateWorker(EmbeddedWorkerTestHelper* helper)
+      : FakeServiceWorker(helper) {}
+  ~RecordInstallActivateWorker() override = default;
+
+  const std::vector<ServiceWorkerMetrics::EventType>& events() const {
+    return events_;
+  }
+
+  void DispatchInstallEvent(
+      blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)
+      override {
+    events_.emplace_back(ServiceWorkerMetrics::EventType::INSTALL);
+    FakeServiceWorker::DispatchInstallEvent(std::move(callback));
+  }
+
+  void DispatchActivateEvent(
+      blink::mojom::ServiceWorker::DispatchActivateEventCallback callback)
+      override {
+    events_.emplace_back(ServiceWorkerMetrics::EventType::ACTIVATE);
+    FakeServiceWorker::DispatchActivateEvent(std::move(callback));
+  }
+
+ private:
+  std::vector<ServiceWorkerMetrics::EventType> events_;
+};
+
 // Make sure basic registration is working.
 TEST_F(ServiceWorkerJobTest, Register) {
   blink::mojom::ServiceWorkerRegistrationOptions options;
   options.scope = GURL("https://www.example.com/");
+  auto* worker =
+      helper_->AddNewPendingServiceWorker<RecordInstallActivateWorker>(
+          helper_.get());
   scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(
       GURL("https://www.example.com/service_worker.js"), options);
 
   EXPECT_TRUE(registration);
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Install,
-            helper_->dispatched_events()->at(0));
-  EXPECT_EQ(EmbeddedWorkerTestHelper::Event::Activate,
-            helper_->dispatched_events()->at(1));
+  ASSERT_EQ(2u, worker->events().size());
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::INSTALL, worker->events()[0]);
+  EXPECT_EQ(ServiceWorkerMetrics::EventType::ACTIVATE, worker->events()[1]);
 }
 
 // Make sure registrations are cleaned up when they are unregistered.
@@ -1648,199 +1678,46 @@
   EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, third_version->status());
 }
 
-class EventCallbackHelper : public EmbeddedWorkerTestHelper {
+// A fake service worker for toggling whether a fetch event handler exists.
+class FetchHandlerWorker : public FakeServiceWorker {
  public:
-  EventCallbackHelper()
-      : EmbeddedWorkerTestHelper(base::FilePath()),
-        install_event_result_(
-            blink::mojom::ServiceWorkerEventStatus::COMPLETED),
-        activate_event_result_(
-            blink::mojom::ServiceWorkerEventStatus::COMPLETED) {}
+  FetchHandlerWorker(EmbeddedWorkerTestHelper* helper)
+      : FakeServiceWorker(helper) {}
+  ~FetchHandlerWorker() override = default;
 
-  void OnInstallEvent(blink::mojom::ServiceWorker::DispatchInstallEventCallback
-                          callback) override {
-    if (!install_callback_.is_null())
-      std::move(install_callback_).Run();
-    std::move(callback).Run(install_event_result_, has_fetch_handler_);
-  }
-
-  void OnActivateEvent(
-      blink::mojom::ServiceWorker::DispatchActivateEventCallback callback)
-      override {
-    std::move(callback).Run(activate_event_result_);
-  }
-
-  void set_install_callback(base::OnceClosure callback) {
-    install_callback_ = std::move(callback);
-  }
-  void set_install_event_result(blink::mojom::ServiceWorkerEventStatus result) {
-    install_event_result_ = result;
-  }
-  void set_activate_event_result(
-      blink::mojom::ServiceWorkerEventStatus result) {
-    activate_event_result_ = result;
-  }
   void set_has_fetch_handler(bool has_fetch_handler) {
     has_fetch_handler_ = has_fetch_handler;
   }
 
+  void DispatchInstallEvent(
+      blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)
+      override {
+    std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
+                            has_fetch_handler_);
+  }
+
  private:
-  base::OnceClosure install_callback_;
-  blink::mojom::ServiceWorkerEventStatus install_event_result_;
-  blink::mojom::ServiceWorkerEventStatus activate_event_result_;
-  bool has_fetch_handler_ = true;
+  bool has_fetch_handler_ = false;
 };
 
-TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringInstall) {
-  // S13nServiceWorker: RemoveControllee doesn't affect activation so let's skip
-  // this test.
-  if (blink::ServiceWorkerUtils::IsServicificationEnabled())
-    return;
-
-  EventCallbackHelper* helper = new EventCallbackHelper;
-  helper_.reset(helper);
-
-  GURL script1("https://www.example.com/service_worker.js");
-  GURL script2("https://www.example.com/service_worker.js?new");
-  blink::mojom::ServiceWorkerRegistrationOptions options;
-  options.scope = GURL("https://www.example.com/one/");
-
-  scoped_refptr<ServiceWorkerRegistration> registration =
-      RunRegisterJob(script1, options);
-
-  // Add a controllee and queue an unregister to force the uninstalling state.
-  ServiceWorkerProviderHost* host = CreateControllee();
-  scoped_refptr<ServiceWorkerVersion> old_version =
-      registration->active_version();
-  old_version->AddControllee(host);
-  RunUnregisterJob(options.scope);
-
-  // Register another script. While installing, old_version loses controllee.
-  helper->set_install_callback(
-      base::BindOnce(&ServiceWorkerVersion::RemoveControllee, old_version,
-                     host->client_uuid()));
-  EXPECT_EQ(registration, RunRegisterJob(script2, options));
-
-  EXPECT_FALSE(registration->is_uninstalling());
-  EXPECT_FALSE(registration->is_uninstalled());
-
-  // Verify the new version is activated.
-  scoped_refptr<ServiceWorkerVersion> new_version =
-      registration->active_version();
-  EXPECT_NE(old_version, new_version);
-  EXPECT_EQ(nullptr, registration->installing_version());
-  EXPECT_EQ(nullptr, registration->waiting_version());
-  EXPECT_EQ(new_version, registration->active_version());
-  EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, new_version->running_status());
-  EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status());
-
-  EXPECT_EQ(registration, FindRegistrationForScope(options.scope));
-}
-
-TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringRejectedInstall) {
-  // S13nServiceWorker: RemoveControllee doesn't affect activation so let's skip
-  // this test.
-  if (blink::ServiceWorkerUtils::IsServicificationEnabled())
-    return;
-
-  EventCallbackHelper* helper = new EventCallbackHelper;
-  helper_.reset(helper);
-
-  GURL script1("https://www.example.com/service_worker.js");
-  GURL script2("https://www.example.com/service_worker.js?new");
-  blink::mojom::ServiceWorkerRegistrationOptions options;
-  options.scope = GURL("https://www.example.com/one/");
-
-  scoped_refptr<ServiceWorkerRegistration> registration =
-      RunRegisterJob(script1, options);
-
-  // Add a controllee and queue an unregister to force the uninstalling state.
-  ServiceWorkerProviderHost* host = CreateControllee();
-  scoped_refptr<ServiceWorkerVersion> old_version =
-      registration->active_version();
-  old_version->AddControllee(host);
-  RunUnregisterJob(options.scope);
-
-  // Register another script that fails to install. While installing,
-  // old_version loses controllee.
-  helper->set_install_callback(
-      base::BindOnce(&ServiceWorkerVersion::RemoveControllee, old_version,
-                     host->client_uuid()));
-  helper->set_install_event_result(
-      blink::mojom::ServiceWorkerEventStatus::REJECTED);
-  EXPECT_EQ(registration, RunRegisterJob(script2, options));
-
-  // Verify the registration was uninstalled.
-  EXPECT_FALSE(registration->is_uninstalling());
-  EXPECT_TRUE(registration->is_uninstalled());
-
-  EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, old_version->running_status());
-  EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
-
-  FindRegistrationForScope(options.scope,
-                           blink::ServiceWorkerStatusCode::kErrorNotFound);
-}
-
-TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringInstall_RejectActivate) {
-  // S13nServiceWorker: RemoveControllee doesn't affect activation so let's skip
-  // this test.
-  if (blink::ServiceWorkerUtils::IsServicificationEnabled())
-    return;
-
-  EventCallbackHelper* helper = new EventCallbackHelper;
-  helper_.reset(helper);
-
-  GURL script1("https://www.example.com/service_worker.js");
-  GURL script2("https://www.example.com/service_worker.js?new");
-  blink::mojom::ServiceWorkerRegistrationOptions options;
-  options.scope = GURL("https://www.example.com/one/");
-
-  scoped_refptr<ServiceWorkerRegistration> registration =
-      RunRegisterJob(script1, options);
-
-  // Add a controllee and queue an unregister to force the uninstalling state.
-  ServiceWorkerProviderHost* host = CreateControllee();
-  scoped_refptr<ServiceWorkerVersion> old_version =
-      registration->active_version();
-  old_version->AddControllee(host);
-  RunUnregisterJob(options.scope);
-
-  // Register another script that fails to activate. While installing,
-  // old_version loses controllee.
-  helper->set_install_callback(
-      base::BindOnce(&ServiceWorkerVersion::RemoveControllee, old_version,
-                     host->client_uuid()));
-  helper->set_activate_event_result(
-      blink::mojom::ServiceWorkerEventStatus::REJECTED);
-  EXPECT_EQ(registration, RunRegisterJob(script2, options));
-
-  // Verify the registration remains.
-  EXPECT_FALSE(registration->is_uninstalling());
-  EXPECT_FALSE(registration->is_uninstalled());
-
-  EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, old_version->running_status());
-  EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
-
-  FindRegistrationForScope(options.scope, blink::ServiceWorkerStatusCode::kOk);
-}
-
 TEST_F(ServiceWorkerJobTest, HasFetchHandler) {
-  EventCallbackHelper* helper = new EventCallbackHelper;
-  helper_.reset(helper);
-
   GURL script("https://www.example.com/service_worker.js");
   blink::mojom::ServiceWorkerRegistrationOptions options;
   options.scope = GURL("https://www.example.com/");
   scoped_refptr<ServiceWorkerRegistration> registration;
 
-  helper->set_has_fetch_handler(true);
+  auto* fetch_handler_worker =
+      helper_->AddNewPendingServiceWorker<FetchHandlerWorker>(helper_.get());
+  fetch_handler_worker->set_has_fetch_handler(true);
   RunRegisterJob(script, options);
   registration = FindRegistrationForScope(options.scope);
   EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::EXISTS,
             registration->active_version()->fetch_handler_existence());
   RunUnregisterJob(options.scope);
 
-  helper->set_has_fetch_handler(false);
+  auto* no_fetch_handler_worker =
+      helper_->AddNewPendingServiceWorker<FetchHandlerWorker>(helper_.get());
+  no_fetch_handler_worker->set_has_fetch_handler(false);
   RunRegisterJob(script, options);
   registration = FindRegistrationForScope(options.scope);
   EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST,
diff --git a/content/browser/service_worker/service_worker_object_host_unittest.cc b/content/browser/service_worker/service_worker_object_host_unittest.cc
index 54c9c30..f5aca0b 100644
--- a/content/browser/service_worker/service_worker_object_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -46,14 +46,14 @@
   ports->push_back(blink::MessagePortChannel(std::move(pipe.handle0)));
 }
 
-// A helper that holds on to ExtendableMessageEventPtr so it doesn't get
+// A worker that holds on to ExtendableMessageEventPtr so it doesn't get
 // destroyed after the message event handler runs.
-class ExtendableMessageEventTestHelper : public EmbeddedWorkerTestHelper {
+class MessageEventWorker : public FakeServiceWorker {
  public:
-  ExtendableMessageEventTestHelper()
-      : EmbeddedWorkerTestHelper(base::FilePath()) {}
+  MessageEventWorker(EmbeddedWorkerTestHelper* helper)
+      : FakeServiceWorker(helper) {}
 
-  void OnExtendableMessageEvent(
+  void DispatchExtendableMessageEvent(
       blink::mojom::ExtendableMessageEventPtr event,
       blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback
           callback) override {
@@ -236,12 +236,15 @@
   EXPECT_EQ(blink::mojom::ServiceWorkerState::kInstalled, mock_object->state());
 }
 
+// Tests postMessage() from a service worker to itself.
 TEST_F(ServiceWorkerObjectHostTest,
        DispatchExtendableMessageEvent_FromServiceWorker) {
   const GURL scope("https://www.example.com/");
   const GURL script_url("https://www.example.com/service_worker.js");
-  Initialize(std::make_unique<ExtendableMessageEventTestHelper>());
+  Initialize(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()));
   SetUpRegistration(scope, script_url);
+  auto* worker =
+      helper_->AddNewPendingServiceWorker<MessageEventWorker>(helper_.get());
 
   base::SimpleTestTickClock tick_clock;
   // Set mock clock on version_ to check timeout behavior.
@@ -266,37 +269,38 @@
   base::TimeDelta remaining_time = version_->remaining_timeout();
   EXPECT_EQ(base::TimeDelta::FromSeconds(6), remaining_time);
 
-  // Prepare a ServiceWorkerObjectHost corresponding to a JavaScript
-  // ServiceWorker object in the service worker execution context for
-  // |version_|.
+  // This test will simulate the worker calling postMessage() on itself.
+  // Prepare |object_host|. This corresponds to the JavaScript ServiceWorker
+  // object for the service worker, inside the service worker's own
+  // execution context (e.g., self.registration.active inside the active
+  // worker).
   ServiceWorkerProviderHost* provider_host = version_->provider_host();
   blink::mojom::ServiceWorkerObjectInfoPtr info =
       provider_host->GetOrCreateServiceWorkerObjectHost(version_)
           ->CreateCompleteObjectInfoToSend();
-  ServiceWorkerObjectHost* sender_worker_object_host =
+  ServiceWorkerObjectHost* object_host =
       GetServiceWorkerObjectHost(provider_host, version_->version_id());
-  EXPECT_EQ(1u, GetBindingsCount(sender_worker_object_host));
+  EXPECT_EQ(1u, GetBindingsCount(object_host));
 
-  // Dispatch an ExtendableMessageEvent simulating calling
-  // ServiceWorker#postMessage() on the ServiceWorker object corresponding to
-  // |service_worker_object_host|.
+  // Now simulate the service worker calling postMessage() to itself,
+  // by calling DispatchExtendableMessageEvent on |object_host|.
   blink::TransferableMessage message;
   SetUpDummyMessagePort(&message.ports);
   called = false;
   status = blink::ServiceWorkerStatusCode::kErrorFailed;
   CallDispatchExtendableMessageEvent(
-      sender_worker_object_host, std::move(message),
+      object_host, std::move(message),
       base::BindOnce(&SaveStatusCallback, &called, &status));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
   EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
-  // The dispatched ExtendableMessageEvent should be kept in
-  // ExtendableMessageEventTestHelper, and the source service worker object info
-  // should correspond to the pair (|version_->provider_host()|, |version_|),
-  // means it should correspond to |sender_worker_object_host|.
-  EXPECT_EQ(2u, GetBindingsCount(sender_worker_object_host));
+
+  // The dispatched ExtendableMessageEvent should be received
+  // by the worker, and the source service worker object info
+  // should be for its own version id.
+  EXPECT_EQ(2u, GetBindingsCount(object_host));
   const std::vector<blink::mojom::ExtendableMessageEventPtr>& events =
-      static_cast<ExtendableMessageEventTestHelper*>(helper_.get())->events();
+      worker->events();
   EXPECT_EQ(1u, events.size());
   EXPECT_FALSE(events[0]->source_info_for_client);
   EXPECT_TRUE(events[0]->source_info_for_service_worker);
@@ -311,12 +315,15 @@
   stop_loop.Run();
 }
 
+// Tests postMessage() from a page to a service worker.
 TEST_F(ServiceWorkerObjectHostTest, DispatchExtendableMessageEvent_FromClient) {
   const int64_t kProviderId = 99;
   const GURL scope("https://www.example.com/");
   const GURL script_url("https://www.example.com/service_worker.js");
-  Initialize(std::make_unique<ExtendableMessageEventTestHelper>());
+  Initialize(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()));
   SetUpRegistration(scope, script_url);
+  auto* worker =
+      helper_->AddNewPendingServiceWorker<MessageEventWorker>(helper_.get());
 
   // Prepare a ServiceWorkerProviderHost for a window client. A
   // WebContents/RenderFrameHost must be created too because it's needed for
@@ -333,14 +340,15 @@
                                         std::move(provider_host_info),
                                         helper_->context()->AsWeakPtr());
   provider_host->UpdateUrls(scope, scope);
-  // Prepare a ServiceWorkerObjectHost for the above |provider_host|.
+
+  // Prepare a ServiceWorkerObjectHost for the worker.
   blink::mojom::ServiceWorkerObjectInfoPtr info =
       provider_host->GetOrCreateServiceWorkerObjectHost(version_)
           ->CreateCompleteObjectInfoToSend();
   ServiceWorkerObjectHost* object_host =
       GetServiceWorkerObjectHost(provider_host.get(), version_->version_id());
 
-  // Simulate dispatching an ExtendableMessageEvent.
+  // Simulate postMessage() from the window client to the worker.
   blink::TransferableMessage message;
   SetUpDummyMessagePort(&message.ports);
   bool called = false;
@@ -352,11 +360,11 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
   EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
-  // The dispatched ExtendableMessageEvent should be kept in
-  // ExtendableMessageEventTestHelper, and its source client info should
-  // correspond to |provider_host|.
+
+  // The worker should have received an ExtendableMessageEvent whose
+  // source is |provider_host|.
   const std::vector<blink::mojom::ExtendableMessageEventPtr>& events =
-      static_cast<ExtendableMessageEventTestHelper*>(helper_.get())->events();
+      worker->events();
   EXPECT_EQ(1u, events.size());
   EXPECT_FALSE(events[0]->source_info_for_service_worker);
   EXPECT_TRUE(events[0]->source_info_for_client);
@@ -366,56 +374,5 @@
             events[0]->source_info_for_client->client_type);
 }
 
-TEST_F(ServiceWorkerObjectHostTest, DispatchExtendableMessageEvent_Fail) {
-  const int64_t kProviderId = 99;
-  const GURL scope("https://www.example.com/");
-  const GURL script_url("https://www.example.com/service_worker.js");
-  Initialize(std::make_unique<ExtendableMessageEventTestHelper>());
-  SetUpRegistration(scope, script_url);
-
-  // Prepare a ServiceWorkerProviderHost for a window client. A
-  // WebContents/RenderFrameHost must be created too because it's needed for
-  // DispatchExtendableMessageEvent to populate ExtendableMessageEvent#source.
-  RenderViewHostTestEnabler rvh_test_enabler;
-  std::unique_ptr<WebContents> web_contents(
-      WebContentsTester::CreateTestWebContents(helper_->browser_context(),
-                                               nullptr));
-  RenderFrameHost* frame_host = web_contents->GetMainFrame();
-  blink::mojom::ServiceWorkerProviderHostInfoPtr provider_host_info =
-      CreateProviderHostInfoForWindow(kProviderId, frame_host->GetRoutingID());
-  std::unique_ptr<ServiceWorkerProviderHost> provider_host =
-      ServiceWorkerProviderHost::Create(frame_host->GetProcess()->GetID(),
-                                        std::move(provider_host_info),
-                                        helper_->context()->AsWeakPtr());
-  provider_host->UpdateUrls(scope, scope);
-  // Prepare a ServiceWorkerObjectHost for the above |provider_host|.
-  blink::mojom::ServiceWorkerObjectInfoPtr info =
-      provider_host->GetOrCreateServiceWorkerObjectHost(version_)
-          ->CreateCompleteObjectInfoToSend();
-  ServiceWorkerObjectHost* object_host =
-      GetServiceWorkerObjectHost(provider_host.get(), version_->version_id());
-
-  // Set up the service worker to fail to start.
-  helper_->AddPendingInstanceClient(
-      std::make_unique<FailStartInstanceClient>(helper_.get()));
-
-  // Try to dispatch ExtendableMessageEvent. This should fail to start the
-  // worker and to dispatch the event.
-  blink::TransferableMessage message;
-  SetUpDummyMessagePort(&message.ports);
-  bool called = false;
-  blink::ServiceWorkerStatusCode status = blink::ServiceWorkerStatusCode::kOk;
-  CallDispatchExtendableMessageEvent(
-      object_host, std::move(message),
-      base::BindOnce(&SaveStatusCallback, &called, &status));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed, status);
-  // No ExtendableMessageEvent has been dispatched.
-  const std::vector<blink::mojom::ExtendableMessageEventPtr>& events =
-      static_cast<ExtendableMessageEventTestHelper*>(helper_.get())->events();
-  EXPECT_EQ(0u, events.size());
-}
-
 }  // namespace service_worker_object_host_unittest
 }  // namespace content
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 2bc40d1..1e93ba7 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -444,7 +444,7 @@
 };
 
 bool ConvertJSONToPoint(const std::string& str, gfx::PointF* point) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
   if (!value)
     return false;
   base::DictionaryValue* root;
@@ -13613,7 +13613,7 @@
                          tap_position.y(), tap_position.x(), tap_position.y());
   base::JSONReader json_reader;
   std::unique_ptr<base::Value> params =
-      json_reader.ReadToValue(double_tap_actions_json);
+      json_reader.ReadToValueDeprecated(double_tap_actions_json);
   ASSERT_TRUE(params.get()) << json_reader.GetErrorMessage();
   ActionsParser actions_parser(params.get());
 
@@ -14272,7 +14272,7 @@
       scroll_end_location_in_screen.y());
   base::JSONReader json_reader;
   std::unique_ptr<base::Value> touch_params =
-      json_reader.ReadToValue(touch_move_sequence_json);
+      json_reader.ReadToValueDeprecated(touch_move_sequence_json);
   ASSERT_TRUE(touch_params.get()) << json_reader.GetErrorMessage();
   ActionsParser actions_parser(touch_params.get());
 
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index e21d025..297fccb 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -572,7 +572,7 @@
 
 #if defined(USE_AURA)
 bool ConvertJSONToPoint(const std::string& str, gfx::PointF* point) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
   if (!value)
     return false;
   base::DictionaryValue* root;
@@ -589,7 +589,7 @@
 }
 
 bool ConvertJSONToRect(const std::string& str, gfx::Rect* rect) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
   if (!value)
     return false;
   base::DictionaryValue* root;
diff --git a/content/browser/tracing/background_tracing_config_unittest.cc b/content/browser/tracing/background_tracing_config_unittest.cc
index ab34921..7094160 100644
--- a/content/browser/tracing/background_tracing_config_unittest.cc
+++ b/content/browser/tracing/background_tracing_config_unittest.cc
@@ -24,7 +24,8 @@
 
 std::unique_ptr<BackgroundTracingConfigImpl> ReadFromJSONString(
     const std::string& json_text) {
-  std::unique_ptr<base::Value> json_value(base::JSONReader::Read(json_text));
+  std::unique_ptr<base::Value> json_value(
+      base::JSONReader::ReadDeprecated(json_text));
 
   base::DictionaryValue* dict = nullptr;
   if (json_value)
diff --git a/content/browser/tracing/tracing_controller_browsertest.cc b/content/browser/tracing/tracing_controller_browsertest.cc
index 1a5b3ff..d3f2cd5 100644
--- a/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/content/browser/tracing/tracing_controller_browsertest.cc
@@ -439,7 +439,8 @@
   EXPECT_TRUE(not_whitelisted == "__stripped__");
 
   // Also check the trace content.
-  std::unique_ptr<base::Value> trace_json = base::JSONReader::Read(last_data());
+  std::unique_ptr<base::Value> trace_json =
+      base::JSONReader::ReadDeprecated(last_data());
   ASSERT_TRUE(trace_json);
   const base::Value* metadata_json =
       trace_json->FindKeyOfType("metadata", base::Value::Type::DICTIONARY);
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index bc61bff..ada09e58 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -262,7 +262,8 @@
     return false;
   }
 
-  std::unique_ptr<base::Value> optionsRaw = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> optionsRaw =
+      base::JSONReader::ReadDeprecated(data);
   if (!optionsRaw) {
     LOG(ERROR) << "Options were not valid JSON";
     return false;
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index 1ef0ab54..ffb4223 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -35,9 +35,9 @@
 
 namespace {
 
-constexpr char kLoadResultHistogram[] = "SignedExchange.LoadResult";
+constexpr char kLoadResultHistogram[] = "SignedExchange.LoadResult2";
 constexpr char kPrefetchLoadResultHistogram[] =
-    "SignedExchange.Prefetch.LoadResult";
+    "SignedExchange.Prefetch.LoadResult2";
 constexpr char kContentTypeOptionsHeaderName[] = "x-content-type-options";
 constexpr char kNoSniffHeaderValue[] = "nosniff";
 
@@ -278,18 +278,10 @@
     const GURL& request_url,
     const network::ResourceResponseHead& resource_response,
     std::unique_ptr<net::SourceStream> payload_stream) {
-  UMA_HISTOGRAM_ENUMERATION(kLoadResultHistogram, result);
-  // |metric_recorder_| could be null in some tests.
-  if ((outer_request_.load_flags & net::LOAD_PREFETCH) && metric_recorder_) {
-    UMA_HISTOGRAM_ENUMERATION(kPrefetchLoadResultHistogram, result);
-    metric_recorder_->OnSignedExchangePrefetchFinished(
-        outer_request_.url, outer_response_.response_time);
-  }
-
   if (error) {
     DCHECK_NE(result, SignedExchangeLoadResult::kSuccess);
-    if (reporter_)
-      reporter_->ReportResult(result);
+    ReportLoadResult(result);
+
     if (error != net::ERR_INVALID_SIGNED_EXCHANGE ||
         !should_redirect_on_failure_ || !request_url.is_valid()) {
       // Let the request fail.
@@ -372,12 +364,9 @@
   if (!encoded_data_length_ || !decoded_body_read_result_)
     return;
 
-  if (reporter_) {
-    reporter_->ReportResult(
-        *decoded_body_read_result_ == net::OK
-            ? SignedExchangeLoadResult::kSuccess
-            : SignedExchangeLoadResult::kMerkleIntegrityError);
-  }
+  ReportLoadResult(*decoded_body_read_result_ == net::OK
+                       ? SignedExchangeLoadResult::kSuccess
+                       : SignedExchangeLoadResult::kMerkleIntegrityError);
 
   // TODO(https://crbug.com/803774): Fill the data length information (
   // encoded_body_length, decoded_body_length) too.
@@ -398,6 +387,19 @@
   client_->OnComplete(status);
 }
 
+void SignedExchangeLoader::ReportLoadResult(SignedExchangeLoadResult result) {
+  UMA_HISTOGRAM_ENUMERATION(kLoadResultHistogram, result);
+  // |metric_recorder_| could be null in some tests.
+  if ((outer_request_.load_flags & net::LOAD_PREFETCH) && metric_recorder_) {
+    UMA_HISTOGRAM_ENUMERATION(kPrefetchLoadResultHistogram, result);
+    metric_recorder_->OnSignedExchangePrefetchFinished(
+        outer_request_.url, outer_response_.response_time);
+  }
+
+  if (reporter_)
+    reporter_->ReportResult(result);
+}
+
 void SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(
     SignedExchangeHandlerFactory* factory) {
   g_signed_exchange_factory_for_testing_ = factory;
diff --git a/content/browser/web_package/signed_exchange_loader.h b/content/browser/web_package/signed_exchange_loader.h
index 6611a9b..300ab49c 100644
--- a/content/browser/web_package/signed_exchange_loader.h
+++ b/content/browser/web_package/signed_exchange_loader.h
@@ -121,6 +121,7 @@
 
   void FinishReadingBody(int result);
   void NotifyClientOnCompleteIfReady();
+  void ReportLoadResult(SignedExchangeLoadResult result);
 
   const network::ResourceRequest outer_request_;
 
diff --git a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
index d018088..d652e8960 100644
--- a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -62,6 +62,10 @@
 constexpr char kExpectedSXGEnabledAcceptHeaderForPrefetch[] =
     "application/signed-exchange;v=b3;q=0.9,*/*;q=0.8";
 
+constexpr char kLoadResultHistogram[] = "SignedExchange.LoadResult2";
+constexpr char kPrefetchResultHistogram[] =
+    "SignedExchange.Prefetch.LoadResult2";
+
 class RedirectObserver : public WebContentsObserver {
  public:
   explicit RedirectObserver(WebContents* web_contents)
@@ -265,14 +269,14 @@
       net::X509Certificate::CalculateFingerprint256(
           original_cert->cert_buffer());
   EXPECT_EQ(original_fingerprint, fingerprint);
-  histogram_tester_.ExpectUniqueSample("SignedExchange.LoadResult",
+  histogram_tester_.ExpectUniqueSample(kLoadResultHistogram,
                                        SignedExchangeLoadResult::kSuccess,
                                        PrefetchIsEnabled() ? 2 : 1);
   histogram_tester_.ExpectTotalCount(
       "SignedExchange.Time.CertificateFetch.Success",
       PrefetchIsEnabled() ? 2 : 1);
   if (PrefetchIsEnabled()) {
-    histogram_tester_.ExpectUniqueSample("SignedExchange.Prefetch.LoadResult",
+    histogram_tester_.ExpectUniqueSample(kPrefetchResultHistogram,
                                          SignedExchangeLoadResult::kSuccess, 1);
     histogram_tester_.ExpectUniqueSample(
         "SignedExchange.Prefetch.Recall.30Seconds", true, 1);
@@ -304,8 +308,7 @@
   EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   EXPECT_EQ(303, redirect_observer.response_code());
   histogram_tester_.ExpectUniqueSample(
-      "SignedExchange.LoadResult",
-      SignedExchangeLoadResult::kSXGServedWithoutNosniff,
+      kLoadResultHistogram, SignedExchangeLoadResult::kSXGServedWithoutNosniff,
       PrefetchIsEnabled() ? 2 : 1);
 }
 
@@ -332,7 +335,7 @@
   EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   EXPECT_EQ(303, redirect_observer.response_code());
   histogram_tester_.ExpectUniqueSample(
-      "SignedExchange.LoadResult", SignedExchangeLoadResult::kVersionMismatch,
+      kLoadResultHistogram, SignedExchangeLoadResult::kVersionMismatch,
       PrefetchIsEnabled() ? 2 : 1);
 }
 
@@ -359,7 +362,7 @@
   EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   EXPECT_EQ(303, redirect_observer.response_code());
   histogram_tester_.ExpectUniqueSample(
-      "SignedExchange.LoadResult",
+      kLoadResultHistogram,
       SignedExchangeLoadResult::kSignatureVerificationError, 1);
   histogram_tester_.ExpectUniqueSample(
       "SignedExchange.SignatureVerificationResult",
@@ -393,13 +396,13 @@
     NavigateToURL(shell(), url);
     EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   }
-  histogram_tester_.ExpectTotalCount("SignedExchange.LoadResult",
+  histogram_tester_.ExpectTotalCount(kLoadResultHistogram,
                                      PrefetchIsEnabled() ? 4 : 2);
   histogram_tester_.ExpectBucketCount(
-      "SignedExchange.LoadResult", SignedExchangeLoadResult::kVersionMismatch,
+      kLoadResultHistogram, SignedExchangeLoadResult::kVersionMismatch,
       PrefetchIsEnabled() ? 2 : 1);
   histogram_tester_.ExpectBucketCount(
-      "SignedExchange.LoadResult", SignedExchangeLoadResult::kHeaderParseError,
+      kLoadResultHistogram, SignedExchangeLoadResult::kHeaderParseError,
       PrefetchIsEnabled() ? 2 : 1);
 }
 
@@ -421,7 +424,7 @@
   NavigateToURL(shell(), url);
   EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   histogram_tester_.ExpectUniqueSample(
-      "SignedExchange.LoadResult", SignedExchangeLoadResult::kCertFetchError,
+      kLoadResultHistogram, SignedExchangeLoadResult::kCertFetchError,
       PrefetchIsEnabled() ? 2 : 1);
   histogram_tester_.ExpectTotalCount(
       "SignedExchange.Time.CertificateFetch.Failure",
@@ -543,7 +546,7 @@
   NavigateToURL(shell(), url);
   EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   // Verify that it failed at the OCSP check step.
-  histogram_tester_.ExpectUniqueSample("SignedExchange.LoadResult",
+  histogram_tester_.ExpectUniqueSample(kLoadResultHistogram,
                                        SignedExchangeLoadResult::kOCSPError, 1);
 }
 
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 2d2dcc1..a6feba0 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -598,10 +598,11 @@
 // also in the second, and with the same value.
 void CheckJSONIsSubsetOfJSON(base::StringPiece subset_str,
                              base::StringPiece test_str) {
-  std::unique_ptr<base::Value> subset(base::JSONReader::Read(subset_str));
+  std::unique_ptr<base::Value> subset(
+      base::JSONReader::ReadDeprecated(subset_str));
   ASSERT_TRUE(subset);
   ASSERT_TRUE(subset->is_dict());
-  std::unique_ptr<base::Value> test(base::JSONReader::Read(test_str));
+  std::unique_ptr<base::Value> test(base::JSONReader::ReadDeprecated(test_str));
   ASSERT_TRUE(test);
   ASSERT_TRUE(test->is_dict());
 
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc
index b50777b1..f4718c61 100644
--- a/content/browser/webauth/webauth_browsertest.cc
+++ b/content/browser/webauth/webauth_browsertest.cc
@@ -846,7 +846,7 @@
     }
 
     base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
-    std::unique_ptr<base::Value> result = reader.ReadToValue(json);
+    std::unique_ptr<base::Value> result = reader.ReadToValueDeprecated(json);
     if (!result) {
       return base::nullopt;
     }
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index 7a5d8cf..e2c91ea0 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -149,9 +149,10 @@
 
     int error_code;
     std::string error_message;
-    std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-        devices_as_json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
-        &error_message);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            devices_as_json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
+            &error_message);
 
     ASSERT_TRUE(value.get() != nullptr) << error_message;
     EXPECT_EQ(value->type(), base::Value::Type::LIST);
diff --git a/content/browser/webrtc/webrtc_internals_browsertest.cc b/content/browser/webrtc/webrtc_internals_browsertest.cc
index 213d360..8b324eb 100644
--- a/content/browser/webrtc/webrtc_internals_browsertest.cc
+++ b/content/browser/webrtc/webrtc_internals_browsertest.cc
@@ -237,7 +237,7 @@
                                       "    JSON.stringify(userMediaRequests));",
                                       &json_requests));
     std::unique_ptr<base::Value> value_requests =
-        base::JSONReader::Read(json_requests);
+        base::JSONReader::ReadDeprecated(json_requests);
 
     EXPECT_EQ(base::Value::Type::LIST, value_requests->type());
 
@@ -785,7 +785,8 @@
       "window.domAutomationController.send("
       "    JSON.stringify(peerConnectionDataStore));",
       &dump_json));
-  std::unique_ptr<base::Value> dump = base::JSONReader::Read(dump_json);
+  std::unique_ptr<base::Value> dump =
+      base::JSONReader::ReadDeprecated(dump_json);
   VerifyPageDumpStructure(dump.get(),
                           2 /*peer_connection_number*/,
                           2 /*update_number*/,
@@ -804,7 +805,7 @@
       "window.domAutomationController.send("
       "    JSON.stringify(peerConnectionDataStore));",
       &dump_json));
-  dump = base::JSONReader::Read(dump_json);
+  dump = base::JSONReader::ReadDeprecated(dump_json);
   VerifyStatsDump(dump.get(), pc_0, type, id, stats);
 }
 
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index a08976d..305ae0f 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -299,6 +299,12 @@
       appcache_handle_core ? appcache_handle_core->host()->GetWeakPtr()
                            : nullptr;
 
+  // Create a ResourceContext getter using |service_worker_context|.
+  // This context is aware of shutdown and safely returns a nullptr
+  // instead of a destroyed ResourceContext in that case.
+  auto resource_context_getter = base::BindRepeating(
+      &ServiceWorkerContextWrapper::resource_context, service_worker_context);
+
   // NetworkService (PlzWorker):
   // Start loading a shared worker main script.
   if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
@@ -314,7 +320,7 @@
     WorkerScriptFetcher::CreateAndStart(
         std::make_unique<WorkerScriptLoaderFactory>(
             process_id, std::move(service_worker_host),
-            std::move(appcache_host), resource_context,
+            std::move(appcache_host), resource_context_getter,
             std::move(url_loader_factory)),
         std::move(throttles), std::move(resource_request),
         base::BindOnce(WorkerScriptFetchInitiator::DidCreateScriptLoaderOnIO,
@@ -329,7 +335,7 @@
   mojo::MakeStrongAssociatedBinding(
       std::make_unique<WorkerScriptLoaderFactory>(
           process_id, std::move(service_worker_host), std::move(appcache_host),
-          resource_context, std::move(url_loader_factory)),
+          resource_context_getter, std::move(url_loader_factory)),
       mojo::MakeRequest(&main_script_loader_factory));
 
   DidCreateScriptLoaderOnIO(std::move(callback), std::move(provider_info),
diff --git a/content/browser/worker_host/worker_script_loader.cc b/content/browser/worker_host/worker_script_loader.cc
index 2423559b..f6874918 100644
--- a/content/browser/worker_host/worker_script_loader.cc
+++ b/content/browser/worker_host/worker_script_loader.cc
@@ -25,7 +25,7 @@
     network::mojom::URLLoaderClientPtr client,
     base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
     base::WeakPtr<AppCacheHost> appcache_host,
-    ResourceContext* resource_context,
+    const ResourceContextGetter& resource_context_getter,
     scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
     : process_id_(process_id),
@@ -35,7 +35,7 @@
       resource_request_(resource_request),
       client_(std::move(client)),
       service_worker_provider_host_(service_worker_provider_host),
-      resource_context_(resource_context),
+      resource_context_getter_(resource_context_getter),
       default_loader_factory_(std::move(default_loader_factory)),
       traffic_annotation_(traffic_annotation),
       url_loader_client_binding_(this),
@@ -68,10 +68,18 @@
 }
 
 void WorkerScriptLoader::Start() {
+  DCHECK(!completed_);
+
+  ResourceContext* resource_context = resource_context_getter_.Run();
+  if (!resource_context) {
+    CommitCompleted(network::URLLoaderCompletionStatus(net::ERR_ABORTED));
+    return;
+  }
+
   if (interceptor_index_ < interceptors_.size()) {
     auto* interceptor = interceptors_[interceptor_index_++].get();
     interceptor->MaybeCreateLoader(
-        resource_request_, resource_context_,
+        resource_request_, resource_context,
         base::BindOnce(&WorkerScriptLoader::MaybeStartLoader,
                        weak_factory_.GetWeakPtr(), interceptor),
         base::BindOnce(&WorkerScriptLoader::LoadFromNetwork,
@@ -85,6 +93,7 @@
 void WorkerScriptLoader::MaybeStartLoader(
     NavigationLoaderInterceptor* interceptor,
     SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
+  DCHECK(!completed_);
   DCHECK(interceptor);
 
   // Create SubresourceLoaderParams for intercepting subresource requests and
@@ -117,6 +126,8 @@
 }
 
 void WorkerScriptLoader::LoadFromNetwork(bool reset_subresource_loader_params) {
+  DCHECK(!completed_);
+
   default_loader_used_ = true;
   network::mojom::URLLoaderClientPtr client;
   if (url_loader_client_binding_)
@@ -191,8 +202,9 @@
   if (url_loader_)
     url_loader_->ResumeReadingBodyFromNet();
 }
+// URLLoader end --------------------------------------------------------------
 
-// URLLoaderClient ----------------------------------------------------------
+// URLLoaderClient ------------------------------------------------------------
 // This class forwards any client messages to the outer client in the renderer.
 // Additionally, on redirects it saves the redirect info so if the renderer
 // calls FollowRedirect(), it can do so.
@@ -206,7 +218,7 @@
     const net::RedirectInfo& redirect_info,
     const network::ResourceResponseHead& response_head) {
   if (--redirect_limit_ == 0) {
-    client_->OnComplete(
+    CommitCompleted(
         network::URLLoaderCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
     return;
   }
@@ -239,11 +251,11 @@
 
 void WorkerScriptLoader::OnComplete(
     const network::URLLoaderCompletionStatus& status) {
-  if (service_worker_provider_host_ && status.error_code == net::OK)
-    service_worker_provider_host_->CompleteSharedWorkerPreparation();
-  client_->OnComplete(status);
+  CommitCompleted(status);
 }
 
+// URLLoaderClient end ---------------------------------------------------------
+
 bool WorkerScriptLoader::MaybeCreateLoaderForResponse(
     const network::ResourceResponseHead& response,
     network::mojom::URLLoaderPtr* response_url_loader,
@@ -272,4 +284,20 @@
   return false;
 }
 
+void WorkerScriptLoader::CommitCompleted(
+    const network::URLLoaderCompletionStatus& status) {
+  DCHECK(!completed_);
+  completed_ = true;
+
+  if (service_worker_provider_host_ && status.error_code == net::OK)
+    service_worker_provider_host_->CompleteSharedWorkerPreparation();
+  client_->OnComplete(status);
+
+  // We're done. Ensure we no longer send messages to our client, and no longer
+  // talk to the loader we're a client of.
+  client_.reset();
+  url_loader_client_binding_.Close();
+  url_loader_.reset();
+}
+
 }  // namespace content
diff --git a/content/browser/worker_host/worker_script_loader.h b/content/browser/worker_host/worker_script_loader.h
index 0cf0badb..6627801f 100644
--- a/content/browser/worker_host/worker_script_loader.h
+++ b/content/browser/worker_host/worker_script_loader.h
@@ -39,6 +39,10 @@
 class WorkerScriptLoader : public network::mojom::URLLoader,
                            public network::mojom::URLLoaderClient {
  public:
+  // Returns the resource context, or nullptr during shutdown. Must be called on
+  // the IO thread.
+  using ResourceContextGetter = base::RepeatingCallback<ResourceContext*(void)>;
+
   // |default_loader_factory| is used to load the script if the load is not
   // intercepted by a feature like service worker. Typically it will load the
   // script from the NetworkService. However, it may internally contain
@@ -53,7 +57,7 @@
       network::mojom::URLLoaderClientPtr client,
       base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
       base::WeakPtr<AppCacheHost> appcache_host,
-      ResourceContext* resource_context,
+      const ResourceContextGetter& resource_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation);
   ~WorkerScriptLoader() override;
@@ -108,6 +112,7 @@
       NavigationLoaderInterceptor* interceptor,
       SingleRequestURLLoaderFactory::RequestHandler single_request_handler);
   void LoadFromNetwork(bool reset_subresource_loader_params);
+  void CommitCompleted(const network::URLLoaderCompletionStatus& status);
 
   // The order of the interceptors is important. The former interceptor can
   // preferentially get a chance to intercept a network request.
@@ -123,7 +128,7 @@
   network::ResourceRequest resource_request_;
   network::mojom::URLLoaderClientPtr client_;
   base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
-  ResourceContext* const resource_context_;
+  ResourceContextGetter resource_context_getter_;
   scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory_;
   net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
 
@@ -137,6 +142,8 @@
   // elect to handle the request.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
+  bool completed_ = false;
+
   base::WeakPtrFactory<WorkerScriptLoader> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WorkerScriptLoader);
diff --git a/content/browser/worker_host/worker_script_loader_factory.cc b/content/browser/worker_host/worker_script_loader_factory.cc
index 908379e8..65a7f7d 100644
--- a/content/browser/worker_host/worker_script_loader_factory.cc
+++ b/content/browser/worker_host/worker_script_loader_factory.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 #include "base/feature_list.h"
-#include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/browser/worker_host/worker_script_loader.h"
@@ -24,12 +23,12 @@
     int process_id,
     base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
     base::WeakPtr<AppCacheHost> appcache_host,
-    ResourceContext* resource_context,
+    const ResourceContextGetter& resource_context_getter,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
     : process_id_(process_id),
       service_worker_provider_host_(std::move(service_worker_provider_host)),
       appcache_host_(std::move(appcache_host)),
-      resource_context_(resource_context),
+      resource_context_getter_(resource_context_getter),
       loader_factory_(std::move(loader_factory)) {
 #if DCHECK_IS_ON()
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -82,17 +81,11 @@
       << resource_request.resource_type;
   DCHECK(!script_loader_);
 
-  // TODO(falken): There's no guarantee |resource_context_| is still valid here.
-  // WorkerScriptLoaderFactory needs access to an IO thread class that
-  // can tell it if shutdown has started (e.g.,
-  // ServiceWorkerContextWrapper::resource_context(), though it's weird to
-  // depend on service worker infra for this.
-
   // Create a WorkerScriptLoader to load the script.
   auto script_loader = std::make_unique<WorkerScriptLoader>(
       process_id_, routing_id, request_id, options, resource_request,
       std::move(client), service_worker_provider_host_, appcache_host_,
-      resource_context_, loader_factory_, traffic_annotation);
+      resource_context_getter_, loader_factory_, traffic_annotation);
   script_loader_ = script_loader->GetWeakPtr();
   mojo::MakeStrongBinding(std::move(script_loader), std::move(request));
 }
diff --git a/content/browser/worker_host/worker_script_loader_factory.h b/content/browser/worker_host/worker_script_loader_factory.h
index 3344080..7ff56fd 100644
--- a/content/browser/worker_host/worker_script_loader_factory.h
+++ b/content/browser/worker_host/worker_script_loader_factory.h
@@ -32,6 +32,10 @@
 class CONTENT_EXPORT WorkerScriptLoaderFactory
     : public network::mojom::URLLoaderFactory {
  public:
+  // Returns the resource context, or nullptr during shutdown. Must be called on
+  // the IO thread.
+  using ResourceContextGetter = base::RepeatingCallback<ResourceContext*(void)>;
+
   // |loader_factory| is used to load the script if the load is not intercepted
   // by a feature like service worker. Typically it will load the script from
   // the NetworkService. However, it may internally contain non-NetworkService
@@ -40,7 +44,7 @@
       int process_id,
       base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
       base::WeakPtr<AppCacheHost> appcache_host,
-      ResourceContext* resource_context,
+      const ResourceContextGetter& resource_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
   ~WorkerScriptLoaderFactory() override;
 
@@ -61,7 +65,7 @@
   const int process_id_;
   base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
   base::WeakPtr<AppCacheHost> appcache_host_;
-  ResourceContext* resource_context_ = nullptr;
+  ResourceContextGetter resource_context_getter_;
   scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
 
   // This is owned by StrongBinding associated with the given URLLoaderRequest,
diff --git a/content/browser/worker_host/worker_script_loader_factory_unittest.cc b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
index 26c307a..65849e8 100644
--- a/content/browser/worker_host/worker_script_loader_factory_unittest.cc
+++ b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/run_loop.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "net/http/http_util.h"
@@ -71,6 +72,8 @@
   DISALLOW_COPY_AND_ASSIGN(MockNetworkURLLoaderFactory);
 };
 
+const int kProcessId = 1;
+
 }  // namespace
 
 class WorkerScriptLoaderFactoryTest : public testing::Test {
@@ -80,11 +83,17 @@
   ~WorkerScriptLoaderFactoryTest() override = default;
 
   void SetUp() override {
+    // Set up the service worker system.
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
     ServiceWorkerContextCore* context = helper_->context();
     context->storage()->LazyInitializeForTest(base::DoNothing());
     base::RunLoop().RunUntilIdle();
 
+    resource_context_getter_ =
+        base::BindRepeating(&ServiceWorkerContextWrapper::resource_context,
+                            helper_->context_wrapper());
+
+    // Set up the network factory.
     network_loader_factory_instance_ =
         std::make_unique<MockNetworkURLLoaderFactory>();
     network::mojom::URLLoaderFactoryPtrInfo factory;
@@ -93,6 +102,14 @@
         std::move(factory));
     network_loader_factory_ =
         network::SharedURLLoaderFactory::Create(std::move(info));
+
+    // Set up a service worker host for the shared worker.
+    service_worker_provider_info_ =
+        blink::mojom::ServiceWorkerProviderInfoForWorker::New();
+    service_worker_provider_host_ =
+        ServiceWorkerProviderHost::PreCreateForSharedWorker(
+            helper_->context()->AsWeakPtr(), kProcessId,
+            &service_worker_provider_info_);
   }
 
  protected:
@@ -116,25 +133,19 @@
   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
   std::unique_ptr<MockNetworkURLLoaderFactory> network_loader_factory_instance_;
   scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
+
+  blink::mojom::ServiceWorkerProviderInfoForWorkerPtr
+      service_worker_provider_info_;
+  base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
+
+  WorkerScriptLoaderFactory::ResourceContextGetter resource_context_getter_;
 };
 
 TEST_F(WorkerScriptLoaderFactoryTest, ServiceWorkerProviderHost) {
-  // Make a service worker provider host for the shared worker.
-  auto service_worker_provider_info =
-      blink::mojom::ServiceWorkerProviderInfoForWorker::New();
-  base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host =
-      ServiceWorkerProviderHost::PreCreateForSharedWorker(
-          helper_->context()->AsWeakPtr(), 1 /* process_id */,
-          &service_worker_provider_info);
-
-  // Skip AppCache host as it's not worth testing.
-  base::WeakPtr<AppCacheHost> appcache_host;
-
   // Make the factory.
-  std::unique_ptr<WorkerScriptLoaderFactory> factory =
-      std::make_unique<WorkerScriptLoaderFactory>(
-          1 /* process_id */, service_worker_provider_host, appcache_host,
-          nullptr /* resource_context */, network_loader_factory_);
+  auto factory = std::make_unique<WorkerScriptLoaderFactory>(
+      kProcessId, service_worker_provider_host_, nullptr /* appcache_host */,
+      resource_context_getter_, network_loader_factory_);
 
   // Load the script.
   GURL url("https://www.example.com/worker.js");
@@ -145,25 +156,19 @@
   EXPECT_EQ(net::OK, client.completion_status().error_code);
 
   // The provider host should be set up.
-  EXPECT_TRUE(service_worker_provider_host->is_response_committed());
-  EXPECT_TRUE(service_worker_provider_host->is_execution_ready());
-  EXPECT_EQ(url, service_worker_provider_host->url());
+  EXPECT_TRUE(service_worker_provider_host_->is_response_committed());
+  EXPECT_TRUE(service_worker_provider_host_->is_execution_ready());
+  EXPECT_EQ(url, service_worker_provider_host_->url());
 }
 
 // Test a null service worker provider host. This typically only happens during
 // shutdown or after a fatal error occurred in the service worker system.
 TEST_F(WorkerScriptLoaderFactoryTest, NullServiceWorkerProviderHost) {
-  // Use a null service worker provider host.
-  base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host;
-
-  // Skip AppCache host as it's not worth testing.
-  base::WeakPtr<AppCacheHost> appcache_host;
-
-  // Make the factory.
-  std::unique_ptr<WorkerScriptLoaderFactory> factory =
-      std::make_unique<WorkerScriptLoaderFactory>(
-          1 /* process_id */, service_worker_provider_host, appcache_host,
-          nullptr /* resource_context */, network_loader_factory_);
+  // Make the factory with null provider host.
+  auto factory = std::make_unique<WorkerScriptLoaderFactory>(
+      kProcessId, nullptr /* service_worker_provider_host */,
+      nullptr /* appcache_host */, resource_context_getter_,
+      network_loader_factory_);
 
   // Load the script.
   GURL url("https://www.example.com/worker.js");
@@ -174,6 +179,27 @@
   EXPECT_EQ(net::OK, client.completion_status().error_code);
 }
 
+// Test a null resource context when the request starts. This happens when
+// shutdown starts between the constructor and when CreateLoaderAndStart is
+// invoked.
+TEST_F(WorkerScriptLoaderFactoryTest, NullResourceContext) {
+  // Make the factory.
+  auto factory = std::make_unique<WorkerScriptLoaderFactory>(
+      kProcessId, service_worker_provider_host_, nullptr /* appcache_host */,
+      resource_context_getter_, network_loader_factory_);
+
+  // Set a null resource context.
+  helper_->context_wrapper()->InitializeResourceContext(nullptr);
+
+  // Load the script.
+  GURL url("https://www.example.com/worker.js");
+  network::TestURLLoaderClient client;
+  network::mojom::URLLoaderPtr loader =
+      CreateTestLoaderAndStart(url, factory.get(), &client);
+  client.RunUntilComplete();
+  EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
+}
+
 // TODO(falken): Add a test for a shared worker that's controlled by a service
 // worker.
 
diff --git a/content/common/input/actions_parser_unittest.cc b/content/common/input/actions_parser_unittest.cc
index 03407e2..78db89a 100644
--- a/content/common/input/actions_parser_unittest.cc
+++ b/content/common/input/actions_parser_unittest.cc
@@ -10,7 +10,7 @@
 namespace content {
 
 TEST(ActionsParserTest, ParseMousePointerActionSequence) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 2, "y": 3,
                          "button": 0},
@@ -37,7 +37,7 @@
 }
 
 TEST(ActionsParserTest, ParseTouchPointerActionSequence) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 3, "y": 5},
                         {"type": "pointerMove", "x": 30, "y": 30},
@@ -70,7 +70,7 @@
 }
 
 TEST(ActionsParserTest, ParseTouchPointerActionSequenceIdNotString) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 0, "y": 0},
                         {"type": "pointerMove", "x": 30, "y": 30},
@@ -91,7 +91,7 @@
 }
 
 TEST(ActionsParserTest, ParseTouchPointerActionSequenceDuplicateId) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 0, "y": 0},
                         {"type": "pointerMove", "x": 30, "y": 30},
@@ -111,7 +111,7 @@
 }
 
 TEST(ActionsParserTest, ParseMousePointerActionSequenceNoParameters) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 2, "y": 3,
                          "button": 0},
@@ -126,7 +126,7 @@
 }
 
 TEST(ActionsParserTest, ParseMousePointerActionSequenceNoPointerType) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 2, "y": 3,
                          "button": 0},
@@ -142,7 +142,7 @@
 }
 
 TEST(ActionsParserTest, ParseMousePointerActionSequenceNoAction) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer", "parameters": {"pointerType": "mouse"},
             "id": "pointer1"}] )");
 
@@ -153,7 +153,7 @@
 }
 
 TEST(ActionsParserTest, ParseMousePointerActionSequenceUnsupportedButton) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 2, "y": 3,
                          "button": -1},
@@ -169,7 +169,7 @@
 }
 
 TEST(ActionsParserTest, ParseTouchPointerActionSequenceMultiActionsType) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "key",
             "actions": [{"type":"keyDown","value":"p"},
                         {"type":"keyUp","value":"p"},
@@ -184,7 +184,7 @@
 }
 
 TEST(ActionsParserTest, ParseTouchPointerActionSequenceMultiPointerType) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 3, "y": 5},
                         {"type": "pointerMove", "x": 30, "y": 30},
@@ -205,7 +205,7 @@
 }
 
 TEST(ActionsParserTest, ParseTouchPointerActionSequenceMultiMouse) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"type": "pointer",
             "actions": [{"type": "pointerDown", "x": 3, "y": 5},
                         {"type": "pointerMove", "x": 30, "y": 30},
@@ -226,7 +226,7 @@
 }
 
 TEST(ActionsParserTest, OldParseMousePointerActionSequence) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "mouse", "id": 0,
             "actions": [{"name": "pointerDown", "x": 2, "y": 3,
                          "button": 0},
@@ -251,7 +251,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequence1) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": 1,
             "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -280,7 +280,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceWithoutId) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": 0,
             "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -309,7 +309,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceIdNotInt) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": "0",
             "actions": [{"name": "pointerDown", "x": 0, "y": 0},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -325,7 +325,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceIdNegative) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": -1,
             "actions": [{"name": "pointerDown", "x": 0, "y": 0},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -341,7 +341,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceDuplicateId) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": 0,
             "actions": [{"name": "pointerDown", "x": 0, "y": 0},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -357,7 +357,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceNoId) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": 0,
             "actions": [{"name": "pointerDown", "x": 0, "y": 0},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -374,7 +374,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceMissingId) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch",
             "actions": [{"name": "pointerDown", "x": 0, "y": 0},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -391,7 +391,7 @@
 }
 
 TEST(ActionsParserTest, OldParseMousePointerActionSequenceNoSource) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"id": 0, "actions": [{"name": "pointerDown", "x": 2, "y": 3,
                                   "button": 0},
                                  {"name": "pointerUp", "x": 2, "y": 3,
@@ -404,8 +404,8 @@
 }
 
 TEST(ActionsParserTest, OldParseMousePointerActionSequenceNoAction) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
-      R"( [{"source": "mouse", "id": 0}] )");
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(R"( [{"source": "mouse", "id": 0}] )");
 
   ActionsParser actions_parser(value.get());
   EXPECT_FALSE(actions_parser.ParsePointerActionSequence());
@@ -414,7 +414,7 @@
 }
 
 TEST(ActionsParserTest, OldParseMousePointerActionSequenceUnsupportedButton) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "mouse", "id": 0,
             "actions": [{"name": "pointerDown", "x": 2, "y": 3,
                          "button": -1},
@@ -428,7 +428,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceMultiSource) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "touch", "id": 1,
             "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -445,7 +445,7 @@
 }
 
 TEST(ActionsParserTest, OldParseTouchPointerActionSequenceMultiMouse) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "mouse", "id": 1,
             "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                         {"name": "pointerMove", "x": 30, "y": 30},
@@ -464,7 +464,7 @@
 }
 
 TEST(ActionsParserTest, OldParsePointerActionSequenceInvalidKey) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       R"( [{"source": "mouse", "id": 0,
             "actions": [{"name": "pointerDown", "x": 3, "y": 5,
                          "keys": "Ctrl"} ]}] )");
diff --git a/content/common/media/media_player_delegate_messages.h b/content/common/media/media_player_delegate_messages.h
index 4870d5b2..5b60fb3 100644
--- a/content/common/media/media_player_delegate_messages.h
+++ b/content/common/media/media_player_delegate_messages.h
@@ -17,7 +17,6 @@
 #include "content/common/content_export.h"
 #include "ipc/ipc_message_macros.h"
 #include "media/base/media_content_type.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
 #include "ui/gfx/ipc/geometry/gfx_param_traits.h"
 
@@ -25,18 +24,6 @@
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
 #define IPC_MESSAGE_START MediaPlayerDelegateMsgStart
 
-IPC_STRUCT_TRAITS_BEGIN(blink::PictureInPictureControlInfo::Icon)
-  IPC_STRUCT_TRAITS_MEMBER(src)
-  IPC_STRUCT_TRAITS_MEMBER(sizes)
-  IPC_STRUCT_TRAITS_MEMBER(type)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(blink::PictureInPictureControlInfo)
-  IPC_STRUCT_TRAITS_MEMBER(id)
-  IPC_STRUCT_TRAITS_MEMBER(label)
-  IPC_STRUCT_TRAITS_MEMBER(icons)
-IPC_STRUCT_TRAITS_END()
-
 IPC_ENUM_TRAITS_MAX_VALUE(media::MediaContentType, media::MediaContentType::Max)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFullscreenVideoStatus,
                           blink::WebFullscreenVideoStatus::kMax)
@@ -72,10 +59,6 @@
 IPC_MESSAGE_ROUTED1(MediaPlayerDelegateMsg_EndPictureInPictureMode,
                     int /* delegate_id, distinguishes instances */)
 
-IPC_MESSAGE_ROUTED2(MediaPlayerDelegateMsg_ClickPictureInPictureControl,
-                    int /* delegate_id, distinguishes instances */,
-                    std::string /* control_id */)
-
 // ----------------------------------------------------------------------------
 // Messages from the renderer notifying the browser of playback state changes.
 // ----------------------------------------------------------------------------
@@ -107,9 +90,4 @@
                     int /* delegate_id, distinguishes instances */,
                     gfx::Size /* new size of video */)
 
-IPC_MESSAGE_ROUTED2(
-    MediaPlayerDelegateHostMsg_OnSetPictureInPictureCustomControls,
-    int /* delegate id */,
-    std::vector<blink::PictureInPictureControlInfo> /* custom controls */)
-
 #endif  // CONTENT_COMMON_MEDIA_MEDIA_PLAYER_DELEGATE_MESSAGES_H_
diff --git a/content/public/browser/overlay_window.h b/content/public/browser/overlay_window.h
index 3ae666d..e072fc8 100644
--- a/content/public/browser/overlay_window.h
+++ b/content/public/browser/overlay_window.h
@@ -9,10 +9,6 @@
 
 #include "ui/gfx/native_widget_types.h"
 
-namespace blink {
-struct PictureInPictureControlInfo;
-}
-
 namespace gfx {
 class Rect;
 class Size;
@@ -56,8 +52,6 @@
   virtual gfx::Rect GetBounds() const = 0;
   virtual void UpdateVideoSize(const gfx::Size& natural_size) = 0;
   virtual void SetPlaybackState(PlaybackState playback_state) = 0;
-  virtual void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>& controls) = 0;
   virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0;
   virtual void SetSkipAdButtonVisibility(bool is_visible) = 0;
   virtual void SetNextTrackButtonVisibility(bool is_visible) = 0;
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h
index ec7807fb..f358c60 100644
--- a/content/public/browser/picture_in_picture_window_controller.h
+++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -5,14 +5,8 @@
 #ifndef CONTENT_PUBLIC_BROWSER_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_H_
 #define CONTENT_PUBLIC_BROWSER_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_H_
 
-#include <string>
-#include <vector>
 #include "content/common/content_export.h"
 
-namespace blink {
-struct PictureInPictureControlInfo;
-}  // namespace blink
-
 namespace gfx {
 class Size;
 }  // namespace gfx
@@ -55,8 +49,6 @@
   // window was requested to be closed and destroyed by the system.
   virtual void OnWindowDestroyed() = 0;
 
-  virtual void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>&) = 0;
   virtual void EmbedSurface(const viz::SurfaceId& surface_id,
                             const gfx::Size& natural_size) = 0;
   virtual OverlayWindow* GetWindowForTesting() = 0;
@@ -81,9 +73,6 @@
   // call.
   virtual bool TogglePlayPause() = 0;
 
-  // Called when the user interacts with a custom control.
-  virtual void CustomControlPressed(const std::string& control_id) = 0;
-
  protected:
   // Use PictureInPictureWindowController::GetOrCreateForWebContents() to
   // create an instance.
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 8db2b82..2874b40c 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -225,7 +225,6 @@
   IPC_STRUCT_TRAITS_MEMBER(embedded_media_experience_enabled)
   IPC_STRUCT_TRAITS_MEMBER(immersive_mode_enabled)
   IPC_STRUCT_TRAITS_MEMBER(css_hex_alpha_color_enabled)
-  IPC_STRUCT_TRAITS_MEMBER(enable_media_download_in_product_help)
   IPC_STRUCT_TRAITS_MEMBER(scroll_top_left_interop_enabled)
   IPC_STRUCT_TRAITS_MEMBER(force_dark_mode_enabled)
 #endif  // defined(OS_ANDROID)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index bb5de85..b76f327 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -208,7 +208,6 @@
       video_fullscreen_detection_enabled(false),
       embedded_media_experience_enabled(false),
       css_hex_alpha_color_enabled(true),
-      enable_media_download_in_product_help(false),
       scroll_top_left_interop_enabled(true),
 #endif  // defined(OS_ANDROID)
 #if defined(OS_ANDROID)
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 798b963..da17655 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -255,7 +255,6 @@
   // Enable 8 (#RRGGBBAA) and 4 (#RGBA) value hex colors in CSS Android
   // WebView quirk (http://crbug.com/618472).
   bool css_hex_alpha_color_enabled;
-  bool enable_media_download_in_product_help;
   // Enable support for document.scrollingElement
   // WebView sets this to false to retain old documentElement behaviour
   // (http://crbug.com/761016).
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 979cd53c..ed5ea5b 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -366,7 +366,7 @@
 
 void BrowserTestBase::SimulateNetworkServiceCrash() {
   CHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
-  CHECK(!IsNetworkServiceRunningInProcess())
+  CHECK(!IsInProcessNetworkService())
       << "Can't crash the network service if it's running in-process!";
   network::mojom::NetworkServiceTestPtr network_service_test;
   ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 480a30f..b138d77 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -205,7 +205,7 @@
     return true;
 
   base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
-  *result = reader.ReadToValue(json);
+  *result = reader.ReadToValueDeprecated(json);
   if (!*result) {
     DLOG(ERROR) << reader.GetErrorMessage();
     return false;
@@ -2988,13 +2988,6 @@
   return static_cast<content::WebContentsImpl*>(guest)->GetOuterWebContents();
 }
 
-bool IsNetworkServiceRunningInProcess() {
-  return base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-         (base::CommandLine::ForCurrentProcess()->HasSwitch(
-              switches::kSingleProcess) ||
-          base::FeatureList::IsEnabled(features::kNetworkServiceInProcess));
-}
-
 int LoadBasicRequest(network::mojom::NetworkContext* network_context,
                      const GURL& url,
                      int process_id,
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 5ce1fc1f8..575dccf 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -1543,10 +1543,6 @@
 
 WebContents* GetEmbedderForGuest(content::WebContents* guest);
 
-// Returns true if the network service is enabled and it's running in the
-// browser process.
-bool IsNetworkServiceRunningInProcess();
-
 // Load the given |url| with |network_context| and return the |net::Error| code.
 int LoadBasicRequest(network::mojom::NetworkContext* network_context,
                      const GURL& url,
diff --git a/content/public/test/content_mock_cert_verifier.cc b/content/public/test/content_mock_cert_verifier.cc
index 5eb4358..e83f654 100644
--- a/content/public/test/content_mock_cert_verifier.cc
+++ b/content/public/test/content_mock_cert_verifier.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
@@ -28,7 +29,7 @@
   verifier_->set_default_result(default_result);
 
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      IsNetworkServiceRunningInProcess()) {
+      IsInProcessNetworkService()) {
     return;
   }
 
@@ -52,7 +53,7 @@
   verifier_->AddResultForCertAndHost(cert, host_pattern, verify_result, rv);
 
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      IsNetworkServiceRunningInProcess()) {
+      IsInProcessNetworkService()) {
     return;
   }
 
@@ -84,7 +85,7 @@
   // Check here instead of the constructor since some tests may set the feature
   // flag in their constructor.
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      IsNetworkServiceRunningInProcess()) {
+      IsInProcessNetworkService()) {
     return;
   }
 
@@ -96,14 +97,14 @@
 }
 
 void ContentMockCertVerifier::SetUpInProcessBrowserTestFixture() {
-  if (IsNetworkServiceRunningInProcess()) {
+  if (IsInProcessNetworkService()) {
     network::NetworkContext::SetCertVerifierForTesting(
         mock_cert_verifier_.get());
   }
 }
 
 void ContentMockCertVerifier::TearDownInProcessBrowserTestFixture() {
-  if (IsNetworkServiceRunningInProcess())
+  if (IsInProcessNetworkService())
     network::NetworkContext::SetCertVerifierForTesting(nullptr);
 }
 
diff --git a/content/public/test/fake_download_item.cc b/content/public/test/fake_download_item.cc
index 6565484..1cba8b4 100644
--- a/content/public/test/fake_download_item.cc
+++ b/content/public/test/fake_download_item.cc
@@ -217,6 +217,10 @@
   last_modified_time_ = last_modified_time;
 }
 
+void FakeDownloadItem::SetHash(const std::string& hash) {
+  hash_ = hash;
+}
+
 const std::string& FakeDownloadItem::GetLastModifiedTime() const {
   return last_modified_time_;
 }
@@ -367,8 +371,7 @@
 }
 
 const std::string& FakeDownloadItem::GetHash() const {
-  NOTREACHED();
-  return dummy_string;
+  return hash_;
 }
 
 void FakeDownloadItem::DeleteFile(const base::Callback<void(bool)>& callback) {
diff --git a/content/public/test/fake_download_item.h b/content/public/test/fake_download_item.h
index cf364c8..255bb35 100644
--- a/content/public/test/fake_download_item.h
+++ b/content/public/test/fake_download_item.h
@@ -135,6 +135,7 @@
   void SetIsDone(bool is_done);
   void SetETag(const std::string& etag);
   void SetLastModifiedTime(const std::string& last_modified_time);
+  void SetHash(const std::string& hash);
 
  private:
   base::ObserverList<Observer>::Unchecked observers_;
@@ -163,6 +164,7 @@
   bool is_done_ = false;
   std::string etag_;
   std::string last_modified_time_;
+  std::string hash_;
 
   // The members below are to be returned by methods, which return by reference.
   std::string dummy_string;
diff --git a/content/renderer/manifest/manifest_parser.cc b/content/renderer/manifest/manifest_parser.cc
index bb10b54b..ee5c3ba 100644
--- a/content/renderer/manifest/manifest_parser.cc
+++ b/content/renderer/manifest/manifest_parser.cc
@@ -63,9 +63,10 @@
   std::string error_msg;
   int error_line = 0;
   int error_column = 0;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      data_, base::JSON_PARSE_RFC, nullptr, &error_msg, &error_line,
-      &error_column);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          data_, base::JSON_PARSE_RFC, nullptr, &error_msg, &error_line,
+          &error_column);
 
   if (!value) {
     AddErrorInfo(error_msg, true, error_line, error_column);
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index d7d9255c..0ab79a2 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -16,7 +16,6 @@
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
 #include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_scoped_user_gesture.h"
@@ -120,13 +119,6 @@
                                                            delegate_id, muted));
 }
 
-void RendererWebMediaPlayerDelegate::DidSetPictureInPictureCustomControls(
-    int delegate_id,
-    const std::vector<blink::PictureInPictureControlInfo>& controls) {
-  Send(new MediaPlayerDelegateHostMsg_OnSetPictureInPictureCustomControls(
-      routing_id(), delegate_id, controls));
-}
-
 void RendererWebMediaPlayerDelegate::DidPause(int player_id) {
   DVLOG(2) << __func__ << "(" << player_id << ")";
   DCHECK(id_map_.Lookup(player_id));
@@ -247,8 +239,6 @@
                         OnMediaDelegateBecamePersistentVideo)
     IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_EndPictureInPictureMode,
                         OnPictureInPictureModeEnded)
-    IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_ClickPictureInPictureControl,
-                        OnPictureInPictureControlClicked)
     IPC_MESSAGE_UNHANDLED(return false)
   IPC_END_MESSAGE_MAP()
   return true;
@@ -360,14 +350,6 @@
     observer->OnPictureInPictureModeEnded();
 }
 
-void RendererWebMediaPlayerDelegate::OnPictureInPictureControlClicked(
-    int player_id,
-    const std::string& control_id) {
-  Observer* observer = id_map_.Lookup(player_id);
-  if (observer)
-    observer->OnPictureInPictureControlClicked(control_id);
-}
-
 void RendererWebMediaPlayerDelegate::ScheduleUpdateTask() {
   if (!pending_update_task_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h
index 1f7242c3..d9ef984 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.h
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -65,9 +65,6 @@
       blink::WebFullscreenVideoStatus fullscreen_video_status) override;
   void DidPlayerSizeChange(int delegate_id, const gfx::Size& size) override;
   void DidPlayerMutedStatusChange(int delegate_id, bool muted) override;
-  void DidSetPictureInPictureCustomControls(
-      int delegate_id,
-      const std::vector<blink::PictureInPictureControlInfo>& controls) override;
 
   // content::RenderFrameObserver overrides.
   void WasHidden() override;
@@ -98,8 +95,6 @@
   void OnMediaDelegateVolumeMultiplierUpdate(int player_id, double multiplier);
   void OnMediaDelegateBecamePersistentVideo(int player_id, bool value);
   void OnPictureInPictureModeEnded(int player_id);
-  void OnPictureInPictureControlClicked(int player_id,
-                                        const std::string& control_id);
 
   // Schedules UpdateTask() to run soon.
   void ScheduleUpdateTask();
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
index 8c2cf76..a52fcaa75e 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -49,7 +49,6 @@
   MOCK_METHOD1(OnVolumeMultiplierUpdate, void(double));
   MOCK_METHOD1(OnBecamePersistentVideo, void(bool));
   MOCK_METHOD0(OnPictureInPictureModeEnded, void());
-  MOCK_METHOD1(OnPictureInPictureControlClicked, void(const std::string&));
 };
 
 class RendererWebMediaPlayerDelegateTest : public content::RenderViewTest {
diff --git a/content/renderer/media/stream/media_stream_audio_processor_options.cc b/content/renderer/media/stream/media_stream_audio_processor_options.cc
index 304ad8ac..eec15bd 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_options.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor_options.cc
@@ -177,7 +177,8 @@
   if (!audio_processing_platform_config_json)
     return;
   std::unique_ptr<base::Value> config;
-  config = base::JSONReader::Read(*audio_processing_platform_config_json);
+  config =
+      base::JSONReader::ReadDeprecated(*audio_processing_platform_config_json);
   if (!config) {
     LOG(ERROR) << "Failed to parse platform config JSON.";
     return;
diff --git a/content/renderer/media/stream/webmediaplayer_ms.cc b/content/renderer/media/stream/webmediaplayer_ms.cc
index 87dd4633..173ee38 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms.cc
@@ -655,11 +655,6 @@
   DCHECK(bridge_->GetSurfaceId().is_valid());
 }
 
-void WebMediaPlayerMS::SetPictureInPictureCustomControls(
-    const std::vector<blink::PictureInPictureControlInfo>& controls) {
-  delegate_->DidSetPictureInPictureCustomControls(delegate_id_, controls);
-}
-
 void WebMediaPlayerMS::SetSinkId(
     const blink::WebString& sink_id,
     std::unique_ptr<blink::WebSetSinkIdCallbacks> web_callback) {
@@ -939,11 +934,6 @@
   client_->PictureInPictureStopped();
 }
 
-void WebMediaPlayerMS::OnPictureInPictureControlClicked(
-    const std::string& control_id) {
-  NOTIMPLEMENTED();
-}
-
 bool WebMediaPlayerMS::CopyVideoTextureToPlatformTexture(
     gpu::gles2::GLES2Interface* gl,
     unsigned target,
diff --git a/content/renderer/media/stream/webmediaplayer_ms.h b/content/renderer/media/stream/webmediaplayer_ms.h
index 7b95d0e7..76bd654 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.h
+++ b/content/renderer/media/stream/webmediaplayer_ms.h
@@ -117,8 +117,6 @@
   void SetRate(double rate) override;
   void SetVolume(double volume) override;
   void OnRequestPictureInPicture() override;
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>&) override;
   void SetSinkId(
       const blink::WebString& sink_id,
       std::unique_ptr<blink::WebSetSinkIdCallbacks> web_callback) override;
@@ -184,7 +182,6 @@
   void OnVolumeMultiplierUpdate(double multiplier) override;
   void OnBecamePersistentVideo(bool value) override;
   void OnPictureInPictureModeEnded() override;
-  void OnPictureInPictureControlClicked(const std::string& control_id) override;
 
   void OnFirstFrameReceived(media::VideoRotation video_rotation,
                             bool is_opaque);
diff --git a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
index 6023862..18f7dcd 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
@@ -26,7 +26,6 @@
 #include "media/base/video_frame.h"
 #include "media/video/mock_gpu_memory_buffer_video_frame_pool.h"
 #include "media/video/mock_gpu_video_accelerator_factories.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
 #include "third_party/blink/public/platform/web_media_player.h"
@@ -113,10 +112,6 @@
     EXPECT_EQ(delegate_id_, delegate_id);
   }
 
-  MOCK_METHOD2(DidSetPictureInPictureCustomControls,
-               void(int,
-                    const std::vector<blink::PictureInPictureControlInfo>&));
-
   void DidPause(int delegate_id) override {
     EXPECT_EQ(delegate_id_, delegate_id);
     EXPECT_TRUE(playing_);
@@ -589,8 +584,6 @@
   void MediaRemotingStopped(
       blink::WebLocalizedString::Name error_msg) override {}
   void PictureInPictureStopped() override {}
-  void PictureInPictureControlClicked(
-      const blink::WebString& control_id) override {}
   void RequestPlay() override {}
   void RequestPause() override {}
 
diff --git a/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc b/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
index 2df724d..ebfe1f9 100644
--- a/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
+++ b/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
@@ -51,8 +51,6 @@
   void SetRate(double) override {}
   void SetVolume(double) override {}
   void OnRequestPictureInPicture() override {}
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>&) override {}
   blink::WebTimeRanges Buffered() const override {
     return blink::WebTimeRanges();
   }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 1c25f22..a2623e2 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6826,7 +6826,8 @@
   if (initiator_str.IsNull())
     return nullptr;
   std::unique_ptr<base::DictionaryValue> initiator =
-      base::DictionaryValue::From(base::JSONReader::Read(initiator_str.Utf8()));
+      base::DictionaryValue::From(
+          base::JSONReader::ReadDeprecated(initiator_str.Utf8()));
   if (!initiator)
     return nullptr;
   // TODO(kozy,caseq): the hack below is due to the fact that initiators include
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index ad39308..e961678 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -886,8 +886,6 @@
   settings->SetEmbeddedMediaExperienceEnabled(
       prefs.embedded_media_experience_enabled);
   settings->SetImmersiveModeEnabled(prefs.immersive_mode_enabled);
-  settings->SetMediaDownloadInProductHelpEnabled(
-      prefs.enable_media_download_in_product_help);
   settings->SetDoNotUpdateSelectionOnMutatingSelectionRange(
       prefs.do_not_update_selection_on_mutating_selection_range);
   WebRuntimeFeatures::EnableCSSHexAlphaColor(prefs.css_hex_alpha_color_enabled);
diff --git a/content/shell/browser/shell_devtools_bindings.cc b/content/shell/browser/shell_devtools_bindings.cc
index 5cd92cb..310d629 100644
--- a/content/shell/browser/shell_devtools_bindings.cc
+++ b/content/shell/browser/shell_devtools_bindings.cc
@@ -202,7 +202,8 @@
   std::string method;
   base::ListValue* params = nullptr;
   base::DictionaryValue* dict = nullptr;
-  std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> parsed_message =
+      base::JSONReader::ReadDeprecated(message);
   if (!parsed_message || !parsed_message->GetAsDictionary(&dict) ||
       !dict->GetString("method", &method)) {
     return;
diff --git a/content/shell/browser/web_test/devtools_protocol_test_bindings.cc b/content/shell/browser/web_test/devtools_protocol_test_bindings.cc
index a57ae4e..437842c 100644
--- a/content/shell/browser/web_test/devtools_protocol_test_bindings.cc
+++ b/content/shell/browser/web_test/devtools_protocol_test_bindings.cc
@@ -91,7 +91,8 @@
   std::string method;
   base::ListValue* params = nullptr;
   base::DictionaryValue* dict = nullptr;
-  std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> parsed_message =
+      base::JSONReader::ReadDeprecated(message);
   if (!parsed_message || !parsed_message->GetAsDictionary(&dict) ||
       !dict->GetString("method", &method)) {
     return;
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 cb39a60..0d9cd73 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
@@ -67,9 +67,6 @@
   void Close() override {}
   void ShowInactive() override {}
   void Hide() override {}
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>& controls)
-      override {}
   bool IsVisible() const override { return false; }
   bool IsAlwaysOnTop() const override { return false; }
   ui::Layer* GetLayer() override { return nullptr; }
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index 3abc7f9..9a1f101 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -450,12 +450,29 @@
 
 ObserveMessageFilter::~ObserveMessageFilter() = default;
 
+void ObserveMessageFilter::Wait() {
+  base::RunLoop loop;
+  quit_closure_ = loop.QuitClosure();
+  loop.Run();
+}
+
 bool ObserveMessageFilter::OnMessageReceived(const IPC::Message& message) {
-  if (message.type() == watch_message_id_)
+  if (message.type() == watch_message_id_) {
+    // Exit the Wait() method if it's being used, but in a fresh stack once the
+    // message is actually handled.
+    if (quit_closure_ && !received_) {
+      base::PostTask(FROM_HERE,
+                     base::BindOnce(&ObserveMessageFilter::QuitWait, this));
+    }
     received_ = true;
+  }
   return false;
 }
 
+void ObserveMessageFilter::QuitWait() {
+  std::move(quit_closure_).Run();
+}
+
 UnresponsiveRendererObserver::UnresponsiveRendererObserver(
     WebContents* web_contents)
     : WebContentsObserver(web_contents) {}
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index ae946e9..19a4cae0 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -256,15 +256,21 @@
 
   bool has_received_message() { return received_; }
 
+  // Spins a RunLoop until the message is observed.
+  void Wait();
+
  protected:
   ~ObserveMessageFilter() override;
 
- private:
   // BrowserMessageFilter:
   bool OnMessageReceived(const IPC::Message& message) override;
 
+ private:
+  void QuitWait();
+
   const uint32_t watch_message_id_;
   bool received_ = false;
+  base::OnceClosure quit_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(ObserveMessageFilter);
 };
diff --git a/content/test/fuzzer/renderer_tree_fuzzer.cc b/content/test/fuzzer/renderer_tree_fuzzer.cc
index ecb6290..b0efe74 100644
--- a/content/test/fuzzer/renderer_tree_fuzzer.cc
+++ b/content/test/fuzzer/renderer_tree_fuzzer.cc
@@ -111,8 +111,8 @@
     std::unique_ptr<NodeList> nodes(new NodeList());
 
     base::JSONReader reader;
-    std::unique_ptr<base::Value> value(
-        reader.Read(std::string(reinterpret_cast<const char*>(data), size)));
+    std::unique_ptr<base::Value> value(reader.ReadDeprecated(
+        std::string(reinterpret_cast<const char*>(data), size)));
     if (value) {
       nodes->ParseJson(*value);
     }
diff --git a/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py b/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py
index aa71200..5fc3a5de 100644
--- a/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py
@@ -28,12 +28,15 @@
 
 error_image_cloud_storage_bucket = 'chromium-browser-gpu-tests'
 
-goldctl_bin = os.path.abspath(os.path.join(
-    os.path.dirname(__file__), '..', '..', '..', '..', 'tools',
-    'skia_goldctl', 'goldctl'))
+chromium_root_dir = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..', '..', '..', '..'))
+goldctl_bin = os.path.join(
+    chromium_root_dir, 'tools', 'skia_goldctl', 'goldctl')
 if sys.platform == 'win32':
   goldctl_bin += '.exe'
 
+SKIA_GOLD_INSTANCE = 'chrome-gpu'
+
 class _ReferenceImageParameters(object):
   def __init__(self):
     # Parameters for cloud storage reference images.
@@ -438,14 +441,19 @@
     with open(json_temp_file, 'w+') as f:
       json.dump(gpu_keys, f)
     try:
-      subprocess.check_output([goldctl_bin, 'imgtest', 'add'] + mode +
+      if not self.GetParsedCommandLineOptions().no_luci_auth:
+        subprocess.check_output([goldctl_bin, 'auth', '--luci',
+                                 '--workdir', self._skia_gold_temp_dir],
+            stderr=subprocess.STDOUT)
+      cmd = ([goldctl_bin, 'imgtest', 'add'] + mode +
                             ['--test-name', image_name,
-                             '--instance', 'chrome-gpu',
+                             '--instance', SKIA_GOLD_INSTANCE,
                              '--keys-file', json_temp_file,
                              '--png-file', png_temp_file,
                              '--work-dir', self._skia_gold_temp_dir,
                              '--failure-file', failure_file] +
-                            build_id_args, stderr=subprocess.STDOUT)
+                            build_id_args)
+      subprocess.check_output(cmd, stderr=subprocess.STDOUT)
     except CalledProcessError as e:
       contents = ''
       try:
@@ -454,6 +462,7 @@
       except Exception:
         logging.error('Failed to read contents of goldctl failure file')
       logging.error('goldctl failed with output: %s', e.output)
+      self._MaybeOutputSkiaGoldLink()
       raise Exception('goldctl command failed: ' + contents)
 
   def _ValidateScreenshotSamplesWithSkiaGold(self, tab, page, screenshot,
@@ -474,8 +483,6 @@
       # An exception raised from self.fail() indicates a failure.
       image_name = self._UrlToImageName(url)
       if self.GetParsedCommandLineOptions().test_machine_name:
-        # TODO(https://crbug.com/850107): Generate a link to Skia Gold on
-        # failure.
         self._UploadTestResultToSkiaGold(
           image_name, screenshot,
           tab, page,
@@ -487,3 +494,19 @@
           self.GetParsedCommandLineOptions().generated_dir, image_name,
           screenshot, None)
       raise
+
+  def _MaybeOutputSkiaGoldLink(self):
+    # TODO(https://crbug.com/850107): Differentiate between an image mismatch
+    # and an infra/other failure, and only output the link on image mismatch.
+    skia_url = 'https://%s-gold.skia.org/search?' % SKIA_GOLD_INSTANCE
+    patch_issue = self.GetParsedCommandLineOptions().review_patch_issue
+    is_tryjob = patch_issue != None
+    # These URL formats were just taken from links on the Gold instance pointing
+    # to untriaged results.
+    if is_tryjob:
+      skia_url += 'issue=%s&unt=true&master=false' % patch_issue
+    else:
+      skia_url += 'blame=%s&unt=true&head=true&query=source_type%%3D%s' % (
+          self.GetParsedCommandLineOptions().build_revision,
+          SKIA_GOLD_INSTANCE)
+    logging.error('View and triage untriaged images at %s', skia_url)
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py
index 45a204ce..6de9baab 100644
--- a/content/test/gpu/gpu_tests/pixel_integration_test.py
+++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -100,6 +100,12 @@
       dest='use_skia_gold',
       action='store_true', default=False,
       help='Use the Skia team\'s Gold tool to handle image comparisons')
+    parser.add_option(
+      '--no-luci-auth',
+      action='store_true', default=False,
+      help='Don\'t use the service account provided by LUCI for authentication '
+           'for Skia Gold, instead relying on gsutil to be pre-authenticated. '
+           'Meant for testing locally instead of on the bots.')
 
   @classmethod
   def _CreateExpectations(cls):
@@ -286,7 +292,6 @@
             is_check_mode=True,
             build_id_args=build_id_args)
         except CalledProcessError:
-          # TODO(kbr): make a nice link from the failures to gold.skia.org.
           self.fail('Gold said the test failed, so fail.')
     finally:
       if do_page_action:
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index dfc9017..9b8ea8c 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -550,6 +550,8 @@
         ['mac', 'amd'], bug=905007)
     self.Fail('conformance/rendering/clipping-wide-points.html',
         ['mac', 'amd'], bug=642822)
+    self.Flaky('conformance/glsl/misc/shader-with-non-reserved-words.html',
+        ['mac', 'amd'], bug=929009)
     # TODO(kbr): uncomment the following exepectation after test has
     # been made more robust.
     # self.Fail('conformance/rendering/texture-switch-performance.html',
diff --git a/device/bluetooth/bluetooth_adapter_android.cc b/device/bluetooth/bluetooth_adapter_android.cc
index 5b95e2d..af5df55 100644
--- a/device/bluetooth/bluetooth_adapter_android.cc
+++ b/device/bluetooth/bluetooth_adapter_android.cc
@@ -283,13 +283,15 @@
   RemoveTimedOutDevices();
   if (IsDiscovering()) {
     ui_task_runner_->PostDelayedTask(
-        FROM_HERE, base::Bind(&BluetoothAdapterAndroid::PurgeTimedOutDevices,
-                              weak_ptr_factory_.GetWeakPtr()),
+        FROM_HERE,
+        base::BindOnce(&BluetoothAdapterAndroid::PurgeTimedOutDevices,
+                       weak_ptr_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kActivePollInterval));
   } else {
     ui_task_runner_->PostDelayedTask(
-        FROM_HERE, base::Bind(&BluetoothAdapterAndroid::RemoveTimedOutDevices,
-                              weak_ptr_factory_.GetWeakPtr()),
+        FROM_HERE,
+        base::BindOnce(&BluetoothAdapterAndroid::RemoveTimedOutDevices,
+                       weak_ptr_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kPassivePollInterval));
   }
 }
@@ -315,8 +317,9 @@
       // Using a delayed task in order to give the adapter some time
       // to settle before purging devices.
       ui_task_runner_->PostDelayedTask(
-          FROM_HERE, base::Bind(&BluetoothAdapterAndroid::PurgeTimedOutDevices,
-                                weak_ptr_factory_.GetWeakPtr()),
+          FROM_HERE,
+          base::BindOnce(&BluetoothAdapterAndroid::PurgeTimedOutDevices,
+                         weak_ptr_factory_.GetWeakPtr()),
           base::TimeDelta::FromMilliseconds(kPurgeDelay));
     }
   } else {
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index 6299846..fe0b73b 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -582,8 +582,8 @@
 
   ui_task_runner_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&BluetoothAdapterMac::PollAdapter,
-                 weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&BluetoothAdapterMac::PollAdapter,
+                     weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
 }
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
index 175a79e5..6dae000 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
@@ -129,16 +129,17 @@
   if (read_pending_ || write_pending_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
 
   if (!Java_ChromeBluetoothRemoteGattCharacteristic_readRemoteCharacteristic(
           AttachCurrentThread(), j_characteristic_)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(error_callback,
-                              BluetoothRemoteGattService::GATT_ERROR_FAILED));
+        FROM_HERE,
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_FAILED));
     return;
   }
 
@@ -154,8 +155,8 @@
   if (read_pending_ || write_pending_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
 
@@ -163,8 +164,9 @@
   if (!Java_ChromeBluetoothRemoteGattCharacteristic_writeRemoteCharacteristic(
           env, j_characteristic_, base::android::ToJavaByteArray(env, value))) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(error_callback,
-                              BluetoothRemoteGattService::GATT_ERROR_FAILED));
+        FROM_HERE,
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_FAILED));
     return;
   }
 
@@ -250,8 +252,9 @@
           AttachCurrentThread(), j_characteristic_, true)) {
     LOG(ERROR) << "Error enabling characteristic notification";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(error_callback,
-                              BluetoothRemoteGattService::GATT_ERROR_FAILED));
+        FROM_HERE,
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_FAILED));
     return;
   }
 
@@ -271,8 +274,8 @@
     LOG(ERROR) << "Error disabling characteristic notification";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   device::BluetoothRemoteGattService::GATT_ERROR_FAILED));
+        base::BindOnce(error_callback,
+                       device::BluetoothRemoteGattService::GATT_ERROR_FAILED));
     return;
   }
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
index 086b01e..aa74321 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -134,16 +134,16 @@
     VLOG(1) << *this << ": Characteristic not readable.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
     return;
   }
   if (HasPendingRead() || HasPendingWrite()) {
     VLOG(1) << *this << ": Characteristic read already in progress.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
   VLOG(1) << *this << ": Read characteristic.";
@@ -160,16 +160,16 @@
     VLOG(1) << *this << ": Characteristic not writable.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED));
     return;
   }
   if (HasPendingRead() || HasPendingWrite()) {
     VLOG(1) << *this << ": Characteristic write already in progress.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
   VLOG(1) << *this << ": Write characteristic.";
@@ -184,8 +184,8 @@
   if (write_type == CBCharacteristicWriteWithoutResponse) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&BluetoothRemoteGattCharacteristicMac::DidWriteValue,
-                   weak_ptr_factory_.GetWeakPtr(), nil));
+        base::BindOnce(&BluetoothRemoteGattCharacteristicMac::DidWriteValue,
+                       weak_ptr_factory_.GetWeakPtr(), nil));
   }
 }
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
index 773342f0..65211d0 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
@@ -85,8 +85,8 @@
   if (read_pending_ || write_pending_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
 
@@ -94,8 +94,8 @@
           AttachCurrentThread(), j_descriptor_)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
     return;
   }
 
@@ -111,8 +111,8 @@
   if (read_pending_ || write_pending_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
 
@@ -121,8 +121,8 @@
           env, j_descriptor_, base::android::ToJavaByteArray(env, new_value))) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
     return;
   }
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
index 84eaeb71..c6b09e1 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
@@ -101,8 +101,8 @@
     VLOG(1) << *this << ": Read failed, already in progress.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
   VLOG(1) << *this << ": Read value.";
@@ -119,8 +119,8 @@
     VLOG(1) << *this << ": Write failed, already in progress.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(error_callback,
-                   BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
+        base::BindOnce(error_callback,
+                       BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
   VLOG(1) << *this << ": Write value.";
diff --git a/device/bluetooth/bluetooth_socket_win.cc b/device/bluetooth/bluetooth_socket_win.cc
index dd9bfbd3..7152291 100644
--- a/device/bluetooth/bluetooth_socket_win.cc
+++ b/device/bluetooth/bluetooth_socket_win.cc
@@ -126,12 +126,11 @@
 
   socket_thread()->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(
-          &BluetoothSocketWin::DoConnect,
-          this,
+      base::BindOnce(
+          &BluetoothSocketWin::DoConnect, this,
           base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback),
-          base::Bind(
-              &BluetoothSocketWin::PostErrorCompletion, this, error_callback)));
+          base::Bind(&BluetoothSocketWin::PostErrorCompletion, this,
+                     error_callback)));
 }
 
 void BluetoothSocketWin::Listen(scoped_refptr<BluetoothAdapter> adapter,
@@ -147,12 +146,8 @@
   // TODO(xiyuan): Use |options.name|.
   socket_thread()->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothSocketWin::DoListen,
-                 this,
-                 uuid,
-                 rfcomm_channel,
-                 success_callback,
-                 error_callback));
+      base::BindOnce(&BluetoothSocketWin::DoListen, this, uuid, rfcomm_channel,
+                     success_callback, error_callback));
 }
 
 void BluetoothSocketWin::ResetData() {
@@ -171,11 +166,8 @@
   DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
 
   socket_thread()->task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&BluetoothSocketWin::DoAccept,
-                 this,
-                 success_callback,
-                 error_callback));
+      FROM_HERE, base::BindOnce(&BluetoothSocketWin::DoAccept, this,
+                                success_callback, error_callback));
 }
 
 void BluetoothSocketWin::DoConnect(
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
index 665c0637..88fb060 100644
--- a/device/bluetooth/bluetooth_task_manager_win.cc
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -278,8 +278,7 @@
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_ = bluetooth_task_runner;
   bluetooth_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::StartPolling, this));
 }
 
 void BluetoothTaskManagerWin::StartPolling() {
@@ -293,10 +292,9 @@
     // will not be present.
     AdapterState* state = new AdapterState();
     ui_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
-                 this,
-                 base::Owned(state)));
+        FROM_HERE,
+        base::BindOnce(&BluetoothTaskManagerWin::OnAdapterStateChanged, this,
+                       base::Owned(state)));
   }
 }
 
@@ -306,26 +304,21 @@
     const BluetoothAdapter::ErrorCallback& error_callback) {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::SetPowered,
-                 this,
-                 powered,
-                 callback,
-                 error_callback));
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::SetPowered, this,
+                                powered, callback, error_callback));
 }
 
 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
+      base::BindOnce(&BluetoothTaskManagerWin::StartDiscovery, this));
 }
 
 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::StopDiscovery, this));
 }
 
 void BluetoothTaskManagerWin::LogPollingError(const char* message,
@@ -405,9 +398,7 @@
 
   // Re-poll.
   bluetooth_task_runner_->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::PollAdapter,
-                 this),
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::PollAdapter, this),
       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
 }
 
@@ -416,10 +407,8 @@
   AdapterState* state = new AdapterState();
   GetAdapterState(classic_wrapper_.get(), state);
   ui_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
-                 this,
-                 base::Owned(state)));
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnAdapterStateChanged,
+                                this, base::Owned(state)));
 }
 
 void BluetoothTaskManagerWin::SetPowered(
@@ -447,8 +436,8 @@
   DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
   bool adapter_opened = classic_wrapper_->HasHandle();
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted, this,
-                            adapter_opened));
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnDiscoveryStarted,
+                                this, adapter_opened));
   if (!adapter_opened)
     return;
   discovering_ = true;
@@ -461,7 +450,7 @@
   discovering_ = false;
   ui_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
+      base::BindOnce(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
 }
 
 void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
@@ -469,7 +458,7 @@
   if (!discovering_ || !classic_wrapper_->HasHandle()) {
     ui_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
+        base::BindOnce(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
     return;
   }
 
@@ -483,9 +472,8 @@
   if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
     ++timeout_multiplier;
   bluetooth_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(
-          &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
+      FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::DiscoverDevices, this,
+                                timeout_multiplier));
 }
 
 void BluetoothTaskManagerWin::GetKnownDevices() {
@@ -888,7 +876,7 @@
       service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic),
       win_new_value);
 
-  ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, hr));
+  ui_task_runner_->PostTask(FROM_HERE, base::BindOnce(callback, hr));
 }
 
 void BluetoothTaskManagerWin::RegisterGattCharacteristicValueChangedEvent(
@@ -939,7 +927,7 @@
   }
 
   ui_task_runner_->PostTask(FROM_HERE,
-                            base::Bind(callback, user_event_handle, hr));
+                            base::BindOnce(callback, user_event_handle, hr));
 }
 
 void BluetoothTaskManagerWin::UnregisterGattCharacteristicValueChangedEvent(
@@ -963,8 +951,8 @@
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::GetGattIncludedCharacteristics, this,
-                 service_path, uuid, attribute_handle, callback));
+      base::BindOnce(&BluetoothTaskManagerWin::GetGattIncludedCharacteristics,
+                     this, service_path, uuid, attribute_handle, callback));
 }
 
 void BluetoothTaskManagerWin::PostGetGattIncludedDescriptors(
@@ -974,8 +962,8 @@
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::GetGattIncludedDescriptors, this,
-                 service_path, *characteristic, callback));
+      base::BindOnce(&BluetoothTaskManagerWin::GetGattIncludedDescriptors, this,
+                     service_path, *characteristic, callback));
 }
 
 void BluetoothTaskManagerWin::PostReadGattCharacteristicValue(
@@ -985,8 +973,8 @@
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::ReadGattCharacteristicValue, this,
-                 service_path, *characteristic, callback));
+      base::BindOnce(&BluetoothTaskManagerWin::ReadGattCharacteristicValue,
+                     this, service_path, *characteristic, callback));
 }
 
 void BluetoothTaskManagerWin::PostWriteGattCharacteristicValue(
@@ -997,8 +985,8 @@
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothTaskManagerWin::WriteGattCharacteristicValue, this,
-                 service_path, *characteristic, new_value, callback));
+      base::BindOnce(&BluetoothTaskManagerWin::WriteGattCharacteristicValue,
+                     this, service_path, *characteristic, new_value, callback));
 }
 
 void BluetoothTaskManagerWin::PostRegisterGattCharacteristicValueChangedEvent(
@@ -1010,7 +998,7 @@
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(
+      base::BindOnce(
           &BluetoothTaskManagerWin::RegisterGattCharacteristicValueChangedEvent,
           this, service_path, *characteristic, *ccc_descriptor, callback,
           registered_callback));
@@ -1020,9 +1008,10 @@
     PVOID event_handle) {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   bluetooth_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&BluetoothTaskManagerWin::
-                                UnregisterGattCharacteristicValueChangedEvent,
-                            this, event_handle));
+      FROM_HERE,
+      base::BindOnce(&BluetoothTaskManagerWin::
+                         UnregisterGattCharacteristicValueChangedEvent,
+                     this, event_handle));
 }
 
 }  // namespace device
diff --git a/device/bluetooth/test/bluetooth_test_android.cc b/device/bluetooth/test/bluetooth_test_android.cc
index c29e4b3d..99329ef 100644
--- a/device/bluetooth/test/bluetooth_test_android.cc
+++ b/device/bluetooth/test/bluetooth_test_android.cc
@@ -71,7 +71,7 @@
   // running the Runnable.
   runnable_ref.Reset(env, runnable);
   scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&RunJavaRunnable, runnable_ref));
+      FROM_HERE, base::BindOnce(&RunJavaRunnable, runnable_ref));
 }
 
 bool BluetoothTestAndroid::PlatformSupportsLowEnergy() {
diff --git a/device/fido/fido_authenticator.cc b/device/fido/fido_authenticator.cc
index fa28b30..feb8705 100644
--- a/device/fido/fido_authenticator.cc
+++ b/device/fido/fido_authenticator.cc
@@ -25,6 +25,13 @@
   NOTREACHED();
 }
 
+void FidoAuthenticator::GetPINToken(
+    std::string pin,
+    const pin::KeyAgreementResponse& peer_key,
+    FidoAuthenticator::GetPINTokenCallback callback) {
+  NOTREACHED();
+}
+
 void FidoAuthenticator::SetPIN(const std::string& pin,
                                pin::KeyAgreementResponse& peer_key,
                                FidoAuthenticator::SetPINCallback callback) {
diff --git a/device/fido/fido_authenticator.h b/device/fido/fido_authenticator.h
index d0a6743..634f7c81 100644
--- a/device/fido/fido_authenticator.h
+++ b/device/fido/fido_authenticator.h
@@ -28,6 +28,7 @@
 struct RetriesResponse;
 struct KeyAgreementResponse;
 struct EmptyResponse;
+class TokenResponse;
 }  // namespace pin
 
 // FidoAuthenticator is an authenticator from the WebAuthn Authenticator model
@@ -47,6 +48,9 @@
   using GetEphemeralKeyCallback =
       base::OnceCallback<void(CtapDeviceResponseCode,
                               base::Optional<pin::KeyAgreementResponse>)>;
+  using GetPINTokenCallback =
+      base::OnceCallback<void(CtapDeviceResponseCode,
+                              base::Optional<pin::TokenResponse>)>;
   using SetPINCallback =
       base::OnceCallback<void(CtapDeviceResponseCode,
                               base::Optional<pin::EmptyResponse>)>;
@@ -75,6 +79,12 @@
   // use in protecting transmitted PINs. It is only valid to call this method if
   // |Options| indicates that the authenticator supports PINs.
   virtual void GetEphemeralKey(GetEphemeralKeyCallback callback);
+  // GetPINToken uses the given PIN to request a PIN-token from an
+  // authenticator. It is only valid to call this method if |Options| indicates
+  // that the authenticator supports PINs.
+  virtual void GetPINToken(std::string pin,
+                           const pin::KeyAgreementResponse& peer_key,
+                           GetPINTokenCallback callback);
   // SetPIN sets a new PIN on a device that does not currently have one. The
   // length of |pin| must respect |pin::kMinLength| and |pin::kMaxLength|. It is
   // only valid to call this method if |Options| indicates that the
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc
index 41ce1a0..d2807351 100644
--- a/device/fido/fido_device_authenticator.cc
+++ b/device/fido/fido_device_authenticator.cc
@@ -183,6 +183,25 @@
   operation_->Start();
 }
 
+void FidoDeviceAuthenticator::GetPINToken(
+    std::string pin,
+    const pin::KeyAgreementResponse& peer_key,
+    GetPINTokenCallback callback) {
+  DCHECK(device_->SupportedProtocolIsInitialized())
+      << "InitializeAuthenticator() must be called first.";
+  DCHECK(Options());
+  DCHECK(Options()->client_pin_availability !=
+         AuthenticatorSupportedOptions::ClientPinAvailability::kNotSupported);
+
+  pin::TokenRequest request(pin, peer_key);
+  std::array<uint8_t, 32> shared_key = request.shared_key();
+  operation_ = std::make_unique<
+      Ctap2DeviceOperation<pin::TokenRequest, pin::TokenResponse>>(
+      device_.get(), std::move(request), std::move(callback),
+      base::BindOnce(&pin::TokenResponse::Parse, std::move(shared_key)));
+  operation_->Start();
+}
+
 void FidoDeviceAuthenticator::SetPIN(const std::string& pin,
                                      pin::KeyAgreementResponse& peer_key,
                                      SetPINCallback callback) {
diff --git a/device/fido/fido_device_authenticator.h b/device/fido/fido_device_authenticator.h
index 9a433163..31cf8aa 100644
--- a/device/fido/fido_device_authenticator.h
+++ b/device/fido/fido_device_authenticator.h
@@ -48,6 +48,9 @@
   void GetTouch(base::OnceCallback<void()> callback) override;
   void GetRetries(GetRetriesCallback callback) override;
   void GetEphemeralKey(GetEphemeralKeyCallback callback) override;
+  void GetPINToken(std::string pin,
+                   const pin::KeyAgreementResponse& peer_key,
+                   GetPINTokenCallback callback) override;
   void SetPIN(const std::string& pin,
               pin::KeyAgreementResponse& peer_key,
               SetPINCallback callback) override;
diff --git a/device/fido/pin.cc b/device/fido/pin.cc
index 26b7c03..ecdd059d 100644
--- a/device/fido/pin.cc
+++ b/device/fido/pin.cc
@@ -397,5 +397,104 @@
   return {static_cast<uint8_t>(CtapRequestCommand::kAuthenticatorReset)};
 }
 
+TokenRequest::TokenRequest(const std::string& pin,
+                           const KeyAgreementResponse& peer_key)
+    : cose_key_(CalculateSharedKey(peer_key, shared_key_.data())) {
+  DCHECK_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), shared_key_.size());
+  uint8_t digest[SHA256_DIGEST_LENGTH];
+  SHA256(reinterpret_cast<const uint8_t*>(pin.data()), pin.size(), digest);
+  memcpy(pin_hash_, digest, sizeof(pin_hash_));
+}
+
+TokenRequest::~TokenRequest() = default;
+
+const std::array<uint8_t, 32>& TokenRequest::shared_key() const {
+  return shared_key_;
+}
+
+std::vector<uint8_t> TokenRequest::EncodeAsCBOR() const {
+  EVP_CIPHER_CTX aes_ctx;
+  EVP_CIPHER_CTX_init(&aes_ctx);
+  const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0};
+
+  CHECK(EVP_EncryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr,
+                           shared_key_.data(), kZeroIV));
+  static_assert((sizeof(pin_hash_) % AES_BLOCK_SIZE) == 0,
+                "pin_hash_ is not a multiple of the AES block size");
+  uint8_t encrypted_pin[sizeof(pin_hash_) + AES_BLOCK_SIZE];
+  CHECK(EVP_Cipher(&aes_ctx, encrypted_pin, pin_hash_, sizeof(pin_hash_)));
+  EVP_CIPHER_CTX_cleanup(&aes_ctx);
+
+  return EncodePINCommand(
+      Subcommand::kGetPINToken,
+      [this, &encrypted_pin](cbor::Value::MapValue* map) {
+        map->emplace(static_cast<int>(CommandKeys::kKeyAgreement),
+                     std::move(this->cose_key_));
+        map->emplace(
+            static_cast<int>(CommandKeys::kPINHashEnc),
+            base::span<const uint8_t>(encrypted_pin, sizeof(pin_hash_)));
+      });
+}
+
+TokenResponse::TokenResponse() = default;
+TokenResponse::~TokenResponse() = default;
+TokenResponse::TokenResponse(const TokenResponse&) = default;
+
+base::Optional<TokenResponse> TokenResponse::Parse(
+    std::array<uint8_t, 32> shared_key,
+    base::span<const uint8_t> buffer) {
+  // The response status code (the first byte) has already been processed by
+  // this point.
+  if (buffer.empty()) {
+    return base::nullopt;
+  }
+
+  base::Optional<cbor::Value> decoded_response =
+      cbor::Reader::Read(buffer.subspan(1));
+  if (!decoded_response || !decoded_response->is_map()) {
+    return base::nullopt;
+  }
+  const auto& response_map = decoded_response->GetMap();
+
+  // The encrypted PIN-token is under key 2.
+  auto it = response_map.find(cbor::Value(2));
+  if (it == response_map.end() || !it->second.is_bytestring()) {
+    return base::nullopt;
+  }
+  const auto& encrypted_token = it->second.GetBytestring();
+  if (encrypted_token.size() % AES_BLOCK_SIZE != 0) {
+    return base::nullopt;
+  }
+
+  EVP_CIPHER_CTX aes_ctx;
+  EVP_CIPHER_CTX_init(&aes_ctx);
+  const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0};
+  CHECK(EVP_DecryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr,
+                           shared_key.data(), kZeroIV));
+  CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
+
+  TokenResponse ret;
+  ret.token_.resize(encrypted_token.size());
+  CHECK(EVP_Cipher(&aes_ctx, ret.token_.data(), encrypted_token.data(),
+                   encrypted_token.size()));
+  EVP_CIPHER_CTX_cleanup(&aes_ctx);
+
+  return ret;
+}
+
+std::vector<uint8_t> TokenResponse::PinAuth(
+    const std::array<uint8_t, 32> client_data_hash) {
+  std::vector<uint8_t> pin_auth;
+  pin_auth.resize(SHA256_DIGEST_LENGTH);
+
+  unsigned hmac_bytes;
+  CHECK(HMAC(EVP_sha256(), token_.data(), token_.size(),
+             client_data_hash.data(), client_data_hash.size(), pin_auth.data(),
+             &hmac_bytes));
+  DCHECK_EQ(pin_auth.size(), static_cast<size_t>(hmac_bytes));
+  pin_auth.resize(16);
+  return pin_auth;
+}
+
 }  // namespace pin
 }  // namespace device
diff --git a/device/fido/pin.h b/device/fido/pin.h
index 100237e..aa9efe46 100644
--- a/device/fido/pin.h
+++ b/device/fido/pin.h
@@ -11,11 +11,13 @@
 
 #include <stdint.h>
 
+#include <array>
 #include <string>
 #include <vector>
 
 #include "base/containers/span.h"
 #include "base/optional.h"
+#include "components/cbor/values.h"
 
 namespace device {
 namespace pin {
@@ -118,6 +120,49 @@
 
 using ResetResponse = EmptyResponse;
 
+// TokenRequest requests a pin-token from an authenticator. These tokens can be
+// used to show user-verification in other operations, e.g. when getting an
+// assertion.
+class TokenRequest {
+ public:
+  TokenRequest(const std::string& pin, const KeyAgreementResponse& peer_key);
+  ~TokenRequest();
+  TokenRequest(const TokenRequest&) = delete;
+
+  // shared_key returns the shared ECDH key that was used to encrypt the PIN.
+  // This is needed to decrypt the response.
+  const std::array<uint8_t, 32>& shared_key() const;
+
+  std::vector<uint8_t> EncodeAsCBOR() const;
+
+ private:
+  std::array<uint8_t, 32> shared_key_;
+  const cbor::Value::MapValue cose_key_;
+  uint8_t pin_hash_[16];
+};
+
+// TokenResponse represents the response to a pin-token request. In order to
+// decrypt a response, the shared key from the request is needed. Once a pin-
+// token has been decrypted, it can be used to calculate the pinAuth parameters
+// needed to show user-verification in future operations.
+class TokenResponse {
+ public:
+  ~TokenResponse();
+  TokenResponse(const TokenResponse&);
+
+  static base::Optional<TokenResponse> Parse(std::array<uint8_t, 32> shared_key,
+                                             base::span<const uint8_t> buffer);
+
+  // PinAuth returns a pinAuth parameter for a request that will use the given
+  // client-data hash.
+  std::vector<uint8_t> PinAuth(const std::array<uint8_t, 32> client_data_hash);
+
+ private:
+  TokenResponse();
+
+  std::vector<uint8_t> token_;
+};
+
 }  // namespace pin
 }  // namespace device
 
diff --git a/device/usb/usb_device_handle_android.cc b/device/usb/usb_device_handle_android.cc
index e7474117..c4855709 100644
--- a/device/usb/usb_device_handle_android.cc
+++ b/device/usb/usb_device_handle_android.cc
@@ -42,7 +42,8 @@
 void UsbDeviceHandleAndroid::CloseBlocking() {
   ReleaseFileDescriptor();
   task_runner()->PostTask(
-      FROM_HERE, base::Bind(&UsbDeviceHandleAndroid::CloseConnection, this));
+      FROM_HERE,
+      base::BindOnce(&UsbDeviceHandleAndroid::CloseConnection, this));
 }
 
 void UsbDeviceHandleAndroid::CloseConnection() {
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index 3b826ca1..9590eb2 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -242,7 +242,7 @@
   if (usb_unavailable_) {
     task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(callback, std::vector<scoped_refptr<UsbDevice>>()));
+        base::BindOnce(callback, std::vector<scoped_refptr<UsbDevice>>()));
     return;
   }
 
diff --git a/device/usb/usb_service_win.cc b/device/usb/usb_service_win.cc
index 65e08e1a5..ccba0aa 100644
--- a/device/usb/usb_service_win.cc
+++ b/device/usb/usb_service_win.cc
@@ -193,7 +193,7 @@
     if (!dev_info.is_valid()) {
       USB_PLOG(ERROR) << "Failed to set up device enumeration";
       service_task_runner_->PostTask(
-          FROM_HERE, base::Bind(&UsbServiceWin::HelperStarted, service_));
+          FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
       return;
     }
 
@@ -224,16 +224,16 @@
       }
 
       service_task_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(&UsbServiceWin::CreateDeviceObject, service_, device_path,
-                     hub_path, bus_number, port_number, service_name));
+          FROM_HERE, base::BindOnce(&UsbServiceWin::CreateDeviceObject,
+                                    service_, device_path, hub_path, bus_number,
+                                    port_number, service_name));
     }
 
     if (GetLastError() != ERROR_NO_MORE_ITEMS)
       USB_PLOG(ERROR) << "Failed to enumerate devices";
 
     service_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&UsbServiceWin::HelperStarted, service_));
+        FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
   }
 
   void EnumerateDevicePath(const std::string& device_path) {
@@ -273,9 +273,9 @@
     }
 
     service_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&UsbServiceWin::CreateDeviceObject, service_, device_path,
-                   hub_path, bus_number, port_number, service_name));
+        FROM_HERE, base::BindOnce(&UsbServiceWin::CreateDeviceObject, service_,
+                                  device_path, hub_path, bus_number,
+                                  port_number, service_name));
   }
 
  private:
@@ -299,8 +299,8 @@
 
   helper_ = std::make_unique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&BlockingTaskHelper::EnumerateDevices,
-                            base::Unretained(helper_.get())));
+      FROM_HERE, base::BindOnce(&BlockingTaskHelper::EnumerateDevices,
+                                base::Unretained(helper_.get())));
 }
 
 UsbServiceWin::~UsbServiceWin() {
@@ -318,8 +318,8 @@
 void UsbServiceWin::OnDeviceAdded(const GUID& class_guid,
                                   const std::string& device_path) {
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&BlockingTaskHelper::EnumerateDevicePath,
-                            base::Unretained(helper_.get()), device_path));
+      FROM_HERE, base::BindOnce(&BlockingTaskHelper::EnumerateDevicePath,
+                                base::Unretained(helper_.get()), device_path));
 }
 
 void UsbServiceWin::OnDeviceRemoved(const GUID& class_guid,
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 1598ad1..15db3b1 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -108,7 +108,7 @@
       ]
     }
 
-    if (enable_openvr || enable_oculus_vr) {
+    if (enable_openvr || enable_oculus_vr || enable_windows_mr) {
       sources += [
         "windows/compositor_base.cc",
         "windows/compositor_base.h",
@@ -127,7 +127,8 @@
         "windows/d3d11_texture_helper.cc",
         "windows/d3d11_texture_helper.h",
         "windows/flip_pixel_shader.h",
-        "windows/flip_vertex_shader.h",
+        "windows/geometry_shader.h",
+        "windows/vertex_shader.h",
       ]
     }
 
diff --git a/device/vr/buildflags/buildflags.gni b/device/vr/buildflags/buildflags.gni
index 67bb9faa..9f865cc1 100644
--- a/device/vr/buildflags/buildflags.gni
+++ b/device/vr/buildflags/buildflags.gni
@@ -13,7 +13,7 @@
 
   enable_openvr = is_win
 
-  enable_windows_mr = false
+  enable_windows_mr = is_win
 
   # To build with Oculus support, the Oculus SDK for Windows will need to be
   # installed in third_party/libovr/src.  See
@@ -27,6 +27,7 @@
   # the binary size impact is small and allows many VR tests to run on Linux
   enable_vr =
       enable_gvr_services || enable_openvr || enable_oculus_vr ||
+      enable_windows_mr ||
       (is_desktop_linux && (current_cpu == "x64" || current_cpu == "x86"))
 
   # Whether to include VR extras like test APKs in non-VR-specific targets
@@ -53,7 +54,8 @@
   # When enabled, host Desktop VR devices (OpenVR and Oculus) in a separate
   # process.  When disabled, and Oculus/OpenVR are enabled, they are hosted
   # in the browser process.
-  enable_isolated_xr_service = enable_oculus_vr || enable_openvr
+  enable_isolated_xr_service =
+      enable_oculus_vr || enable_openvr || enable_windows_mr
 }
 
 declare_args() {
diff --git a/device/vr/oculus/oculus_device.cc b/device/vr/oculus/oculus_device.cc
index 8d0ea2b..8a37118 100644
--- a/device/vr/oculus/oculus_device.cc
+++ b/device/vr/oculus/oculus_device.cc
@@ -179,6 +179,7 @@
                      base::Unretained(render_loop_.get()),
                      std::move(on_presentation_ended), std::move(options),
                      std::move(on_request_present_result)));
+  outstanding_session_requests_count_++;
 }
 
 void OculusDevice::EnsureInitialized(int render_process_id,
@@ -207,11 +208,13 @@
     mojom::XRRuntime::RequestSessionCallback callback,
     bool result,
     mojom::XRSessionPtr session) {
+  outstanding_session_requests_count_--;
   if (!result) {
     std::move(callback).Run(nullptr, nullptr);
 
     // Start magic window again.
-    StartOvrSession();
+    if (outstanding_session_requests_count_ == 0)
+      StartOvrSession();
     return;
   }
 
@@ -251,10 +254,14 @@
 }
 
 void OculusDevice::OnPresentationEnded() {
-  StartOvrSession();
+  // If we are no-longer presenting, and there are no outstanding requests to
+  // start presenting, start the Oculus API to allow magic-window.
+  if (outstanding_session_requests_count_ == 0)
+    StartOvrSession();
 }
 
 void OculusDevice::StartOvrSession() {
+  DCHECK(outstanding_session_requests_count_ == 0);
   ovrInitParams initParams = {ovrInit_RequestVersion | ovrInit_Invisible,
                               OVR_MINOR_VERSION, NULL, 0, 0};
   ovrResult result = ovr_Initialize(&initParams);
diff --git a/device/vr/oculus/oculus_device.h b/device/vr/oculus/oculus_device.h
index a55d1ad..a825d2d1 100644
--- a/device/vr/oculus/oculus_device.h
+++ b/device/vr/oculus/oculus_device.h
@@ -67,6 +67,7 @@
   void StartOvrSession();
   void StopOvrSession();
 
+  int outstanding_session_requests_count_ = 0;
   bool have_real_display_info_ = false;
   std::unique_ptr<XRCompositorCommon> render_loop_;
   ovrSession session_ = nullptr;
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc
index 803da47f..7d2bdb8 100644
--- a/device/vr/openvr/openvr_device.cc
+++ b/device/vr/openvr/openvr_device.cc
@@ -224,6 +224,7 @@
                                 base::Unretained(render_loop_.get()),
                                 std::move(on_presentation_ended),
                                 std::move(options), std::move(my_callback)));
+  outstanding_session_requests_count_++;
 }
 
 void OpenVRDevice::EnsureInitialized(int render_process_id,
@@ -251,7 +252,7 @@
 }
 
 void OpenVRDevice::OnPresentationEnded() {
-  if (!openvr_) {
+  if (!openvr_ && outstanding_session_requests_count_ == 0) {
     openvr_ = std::make_unique<OpenVRWrapper>(false /* presenting */);
     if (!openvr_->IsInitialized()) {
       openvr_ = nullptr;
@@ -264,6 +265,7 @@
     mojom::XRRuntime::RequestSessionCallback callback,
     bool result,
     mojom::XRSessionPtr session) {
+  outstanding_session_requests_count_--;
   if (!result) {
     OnPresentationEnded();
     std::move(callback).Run(nullptr, nullptr);
diff --git a/device/vr/openvr/openvr_device.h b/device/vr/openvr/openvr_device.h
index efa7a284..cbec7eb 100644
--- a/device/vr/openvr/openvr_device.h
+++ b/device/vr/openvr/openvr_device.h
@@ -71,6 +71,7 @@
   void OnPresentationEnded();
   bool EnsureValidDisplayInfo();
 
+  int outstanding_session_requests_count_ = 0;
   bool have_real_display_info_ = false;
   std::unique_ptr<XRCompositorCommon> render_loop_;
   std::unique_ptr<OpenVRWrapper> openvr_;
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc
index 9a81c7a..ed69fed 100644
--- a/device/vr/windows/compositor_base.cc
+++ b/device/vr/windows/compositor_base.cc
@@ -170,7 +170,10 @@
     return;
   }
 
-  DCHECK(!on_presentation_ended_);
+  // If on_presentation_ended_ is not already null, we won't call to notify the
+  // runtime that that session has completed.  This is ok because the XRRuntime
+  // knows it has requested a new session, and isn't expecting that callback to
+  // be called.
   on_presentation_ended_ = std::move(on_presentation_ended);
 
   device::mojom::XRPresentationProviderPtr presentation_provider;
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h
index e47690d4..f53a910 100644
--- a/device/vr/windows/compositor_base.h
+++ b/device/vr/windows/compositor_base.h
@@ -47,6 +47,10 @@
   XRCompositorCommon();
   ~XRCompositorCommon() override;
 
+  // on_presentation_ended will be called when this the compositor stops
+  // presenting to the headset. If new session request comes in, only the new
+  // callback will be called (since we haven't yet stopped presenting to the
+  // headset).
   void RequestSession(base::OnceCallback<void()> on_presentation_ended,
                       mojom::XRRuntimeSessionOptionsPtr options,
                       RequestSessionCallback callback);
diff --git a/device/vr/windows/d3d11_texture_helper.cc b/device/vr/windows/d3d11_texture_helper.cc
index 7adb677..3270f124 100644
--- a/device/vr/windows/d3d11_texture_helper.cc
+++ b/device/vr/windows/d3d11_texture_helper.cc
@@ -8,13 +8,23 @@
 
 namespace {
 #include "device/vr/windows/flip_pixel_shader.h"
-#include "device/vr/windows/flip_vertex_shader.h"
+#include "device/vr/windows/geometry_shader.h"
+#include "device/vr/windows/vertex_shader.h"
 
 constexpr int kAcquireWaitMS = 2000;
 
-// 2 position, 2 texture.
-const size_t kElementsPerVertex = 4;
-constexpr size_t kSizeOfVertex = sizeof(float) * kElementsPerVertex;
+struct Vertex2D {
+  float x;
+  float y;
+  float u;
+  float v;
+
+  // Which texture in a texture array to output this triangle to?  If we only
+  // have a single texture bound as the render target, this is ignored.
+  int target;
+};
+
+constexpr size_t kSizeOfVertex = sizeof(Vertex2D);
 
 // 2 triangles per eye
 constexpr size_t kNumVerticesPerLayer = 12;
@@ -197,8 +207,24 @@
 
 bool D3D11TextureHelper::EnsureRenderTargetView() {
   if (!render_state_.render_target_view_) {
+    D3D11_TEXTURE2D_DESC desc;
+    render_state_.target_texture_->GetDesc(&desc);
+
+    if (desc.ArraySize > 1) {
+      HRESULT hr = render_state_.d3d11_device_->CreateRenderTargetView(
+          render_state_.target_texture_.Get(), nullptr,
+          &render_state_.render_target_view_);
+      return SUCCEEDED(hr);
+    }
+
     D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
-    render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    // If the resource is unknown or typeless, use R8G8B8A8_UNORM, which is
+    // required for Oculus.  Otherwise, use the resource's native type.
+    render_target_view_desc.Format =
+        (desc.Format == DXGI_FORMAT_UNKNOWN ||
+         desc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS)
+            ? DXGI_FORMAT_R8G8B8A8_UNORM
+            : DXGI_FORMAT_UNKNOWN;
     render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
     render_target_view_desc.Texture2D.MipSlice = 0;
     HRESULT hr = render_state_.d3d11_device_->CreateRenderTargetView(
@@ -211,10 +237,17 @@
 }
 
 bool D3D11TextureHelper::EnsureShaders() {
-  if (!render_state_.flip_vertex_shader_) {
+  if (!render_state_.vertex_shader_) {
     HRESULT hr = render_state_.d3d11_device_->CreateVertexShader(
-        g_flip_vertex, _countof(g_flip_vertex), nullptr,
-        &render_state_.flip_vertex_shader_);
+        g_vertex, _countof(g_vertex), nullptr, &render_state_.vertex_shader_);
+    if (FAILED(hr))
+      return false;
+  }
+
+  if (!render_state_.geometry_shader_) {
+    HRESULT hr = render_state_.d3d11_device_->CreateGeometryShader(
+        g_geometry, _countof(g_geometry), nullptr,
+        &render_state_.geometry_shader_);
     if (FAILED(hr))
       return false;
   }
@@ -237,10 +270,12 @@
          D3D11_INPUT_PER_VERTEX_DATA, 0},
         {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0,
          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
+        {"TEXCOORD", 1, DXGI_FORMAT_R32_UINT, 0, D3D11_APPEND_ALIGNED_ELEMENT,
+         D3D11_INPUT_PER_VERTEX_DATA, 0},
     };
     HRESULT hr = render_state_.d3d11_device_->CreateInputLayout(
-        vertex_desc, std::size(vertex_desc), g_flip_vertex,
-        _countof(g_flip_vertex), &render_state_.input_layout_);
+        vertex_desc, std::size(vertex_desc), g_vertex, _countof(g_vertex),
+        &render_state_.input_layout_);
     if (FAILED(hr))
       return false;
   }
@@ -282,48 +317,57 @@
   return true;
 }
 
-void PushVertRect(std::vector<float>& data,
+void PushVertRect(std::vector<Vertex2D>& data,
                   const gfx::RectF& rect,
-                  const gfx::RectF& uv) {
-  data.push_back(rect.x() * 2 - 1);
-  data.push_back(rect.y() * 2 - 1);
-  data.push_back(uv.x());
-  data.push_back(uv.y());
+                  const gfx::RectF& uv,
+                  int target) {
+  Vertex2D vert;
+  vert.target = target;
 
-  data.push_back(rect.x() * 2 - 1);
-  data.push_back((rect.y() + rect.height()) * 2 - 1);
-  data.push_back(uv.x());
-  data.push_back(uv.y() + uv.height());
+  vert.x = rect.x() * 2 - 1;
+  vert.y = rect.y() * 2 - 1;
+  vert.u = uv.x();
+  vert.v = uv.y();
+  data.push_back(vert);
 
-  data.push_back((rect.x() + rect.width()) * 2 - 1);
-  data.push_back((rect.y() + rect.height()) * 2 - 1);
-  data.push_back(uv.x() + uv.width());
-  data.push_back(uv.y() + uv.height());
+  vert.x = rect.x() * 2 - 1;
+  vert.y = (rect.y() + rect.height()) * 2 - 1;
+  vert.u = uv.x();
+  vert.v = uv.y() + uv.height();
+  data.push_back(vert);
 
-  data.push_back(rect.x() * 2 - 1);
-  data.push_back(rect.y() * 2 - 1);
-  data.push_back(uv.x());
-  data.push_back(uv.y());
+  vert.x = (rect.x() + rect.width()) * 2 - 1;
+  vert.y = (rect.y() + rect.height()) * 2 - 1;
+  vert.u = uv.x() + uv.width();
+  vert.v = uv.y() + uv.height();
+  data.push_back(vert);
 
-  data.push_back((rect.x() + rect.width()) * 2 - 1);
-  data.push_back((rect.y() + rect.height()) * 2 - 1);
-  data.push_back(uv.x() + uv.width());
-  data.push_back(uv.y() + uv.height());
+  vert.x = rect.x() * 2 - 1;
+  vert.y = rect.y() * 2 - 1;
+  vert.u = uv.x();
+  vert.v = uv.y();
+  data.push_back(vert);
 
-  data.push_back((rect.x() + rect.width()) * 2 - 1);
-  data.push_back(rect.y() * 2 - 1);
-  data.push_back(uv.x() + uv.width());
-  data.push_back(uv.y());
+  vert.x = (rect.x() + rect.width()) * 2 - 1;
+  vert.y = (rect.y() + rect.height()) * 2 - 1;
+  vert.u = uv.x() + uv.width();
+  vert.v = uv.y() + uv.height();
+  data.push_back(vert);
+
+  vert.x = (rect.x() + rect.width()) * 2 - 1;
+  vert.y = rect.y() * 2 - 1;
+  vert.u = uv.x() + uv.width();
+  vert.v = uv.y();
+  data.push_back(vert);
 }
 
 bool D3D11TextureHelper::UpdateVertexBuffer(LayerData& layer) {
-  std::vector<float> vertex_data;
-  PushVertRect(vertex_data, target_left_, layer.left_);
-  PushVertRect(vertex_data, target_right_, layer.right_);
+  std::vector<Vertex2D> vertex_data;
+  PushVertRect(vertex_data, target_left_, layer.left_, 0);
+  PushVertRect(vertex_data, target_right_, layer.right_, 1);
   render_state_.d3d11_device_context_->UpdateSubresource(
       render_state_.vertex_buffer_.Get(), 0, nullptr, vertex_data.data(),
-      sizeof(float) * kElementsPerVertex,
-      vertex_data.size() / kElementsPerVertex);
+      sizeof(Vertex2D), vertex_data.size());
   return true;
 }
 
@@ -333,7 +377,7 @@
     return false;
 
   render_state_.d3d11_device_context_->VSSetShader(
-      render_state_.flip_vertex_shader_.Get(), nullptr, 0);
+      render_state_.vertex_shader_.Get(), nullptr, 0);
   render_state_.d3d11_device_context_->PSSetShader(
       render_state_.flip_pixel_shader_.Get(), nullptr, 0);
   render_state_.d3d11_device_context_->IASetInputLayout(
@@ -365,6 +409,10 @@
   render_state_.d3d11_device_context_->RSSetViewports(1, &viewport);
   render_state_.d3d11_device_context_->IASetPrimitiveTopology(
       D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+  // TODO(billorr): Optimize to avoid the geometry shader when not needed.
+  render_state_.d3d11_device_context_->GSSetShader(
+      render_state_.geometry_shader_.Get(), nullptr, 0);
   render_state_.d3d11_device_context_->Draw(kNumVerticesPerLayer, 0);
   return true;
 }
@@ -433,6 +481,11 @@
       !render_state_.overlay_.source_texture_)
     return false;
 
+  if (force_viewport_) {
+    target_size_ = default_size_;
+    return true;
+  }
+
   if (render_state_.source_.source_texture_ &&
       render_state_.overlay_.source_texture_) {
     target_left_ = gfx::RectF(0 /*x*/, 0 /*y*/, 0.5f /*width*/, 1 /*height*/);
@@ -506,6 +559,16 @@
   return render_state_.target_texture_;
 }
 
+void D3D11TextureHelper::DiscardView() {
+  if (render_state_.render_target_view_ &&
+      render_state_.d3d11_device_context_) {
+    Microsoft::WRL::ComPtr<ID3D11DeviceContext1> context1;
+    if (SUCCEEDED(render_state_.d3d11_device_context_.As(&context1))) {
+      context1->DiscardView(render_state_.render_target_view_.Get());
+    }
+  }
+}
+
 void D3D11TextureHelper::SetBackbuffer(
     Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer) {
   if (render_state_.target_texture_ != back_buffer) {
diff --git a/device/vr/windows/d3d11_texture_helper.h b/device/vr/windows/d3d11_texture_helper.h
index 5a50b4f..59fe1c8 100644
--- a/device/vr/windows/d3d11_texture_helper.h
+++ b/device/vr/windows/d3d11_texture_helper.h
@@ -40,10 +40,16 @@
 
   void AllocateBackBuffer();
   const Microsoft::WRL::ComPtr<ID3D11Texture2D>& GetBackbuffer();
+  void DiscardView();
 
   bool UpdateBackbufferSizes();
   gfx::RectF BackBufferLeft() { return target_left_; }
   gfx::RectF BackBufferRight() { return target_right_; }
+  void OverrideViewports(gfx::RectF left, gfx::RectF right) {
+    target_left_ = left;
+    target_right_ = right;
+    force_viewport_ = true;
+  }
   gfx::Size BackBufferSize() { return target_size_; }
   void SetBackbuffer(Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer);
   Microsoft::WRL::ComPtr<ID3D11Device> GetDevice();
@@ -86,7 +92,8 @@
 
     Microsoft::WRL::ComPtr<ID3D11RenderTargetView> render_target_view_;
     Microsoft::WRL::ComPtr<ID3D11PixelShader> flip_pixel_shader_;
-    Microsoft::WRL::ComPtr<ID3D11VertexShader> flip_vertex_shader_;
+    Microsoft::WRL::ComPtr<ID3D11VertexShader> vertex_shader_;
+    Microsoft::WRL::ComPtr<ID3D11GeometryShader> geometry_shader_;
 
     Microsoft::WRL::ComPtr<ID3D11InputLayout> input_layout_;
     Microsoft::WRL::ComPtr<ID3D11Buffer> vertex_buffer_;
@@ -104,6 +111,7 @@
   bool source_visible_ = true;
 
   bool bgra_ = false;
+  bool force_viewport_ = false;
 
   gfx::RectF target_left_;   // 0 to 1 in each direction
   gfx::RectF target_right_;  // 0 to 1 in each direction
diff --git a/device/vr/windows/flip_vertex_shader.h b/device/vr/windows/flip_vertex_shader.h
deleted file mode 100644
index d42aabb..0000000
--- a/device/vr/windows/flip_vertex_shader.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// DO NOT MODIFY.  Use generate_shaders.bat to modify, then re-add this warning.
-#ifndef DEVICE_VR_WINDOWS_FLIP_VERTEX_SHADER_H_
-#define DEVICE_VR_WINDOWS_FLIP_VERTEX_SHADER_H_
-
-#if 0
-//
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
-//
-//
-//
-// Input signature:
-//
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// POSITION                 0   xy          0     NONE   float   xy
-// TEXCOORD                 0   xy          1     NONE   float   xy
-//
-//
-// Output signature:
-//
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_POSITION              0   xyzw        0      POS   float   xyzw
-// TEXCOORD                 0   xy          1     NONE   float   xy
-//
-//
-// Runtime generated constant mappings:
-//
-// Target Reg                               Constant Description
-// ---------- --------------------------------------------------
-// c0                              Vertex Shader position offset
-//
-//
-// Level9 shader bytecode:
-//
-    vs_2_x
-    def c1, 1, 0, 0, 0
-    dcl_texcoord v0
-    dcl_texcoord1 v1
-    add oPos.xy, v0, c0
-    mov oPos.zw, c1.x
-    mov oT0.xy, v1
-
-// approximately 3 instruction slots used
-vs_4_0
-dcl_input v0.xy
-dcl_input v1.xy
-dcl_output_siv o0.xyzw, position
-dcl_output o1.xy
-mov o0.xy, v0.xyxx
-mov o0.zw, l(0,0,1.000000,1.000000)
-mov o1.xy, v1.xyxx
-ret 
-// Approximately 4 instruction slots used
-#endif
-
-const BYTE g_flip_vertex[] = {
-    68,  88,  66,  67,  43,  50,  141, 190, 122, 16,  49,  144, 252, 110, 105,
-    224, 82,  212, 172, 76,  1,   0,   0,   0,   216, 2,   0,   0,   6,   0,
-    0,   0,   56,  0,   0,   0,   200, 0,   0,   0,   88,  1,   0,   0,   212,
-    1,   0,   0,   44,  2,   0,   0,   128, 2,   0,   0,   65,  111, 110, 57,
-    136, 0,   0,   0,   136, 0,   0,   0,   0,   2,   254, 255, 96,  0,   0,
-    0,   40,  0,   0,   0,   0,   0,   36,  0,   0,   0,   36,  0,   0,   0,
-    36,  0,   0,   0,   36,  0,   1,   0,   36,  0,   0,   0,   0,   0,   1,
-    2,   254, 255, 81,  0,   0,   5,   1,   0,   15,  160, 0,   0,   128, 63,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   31,  0,   0,
-    2,   5,   0,   0,   128, 0,   0,   15,  144, 31,  0,   0,   2,   5,   0,
-    1,   128, 1,   0,   15,  144, 2,   0,   0,   3,   0,   0,   3,   192, 0,
-    0,   228, 144, 0,   0,   228, 160, 1,   0,   0,   2,   0,   0,   12,  192,
-    1,   0,   0,   160, 1,   0,   0,   2,   0,   0,   3,   224, 1,   0,   228,
-    144, 255, 255, 0,   0,   83,  72,  68,  82,  136, 0,   0,   0,   64,  0,
-    1,   0,   34,  0,   0,   0,   95,  0,   0,   3,   50,  16,  16,  0,   0,
-    0,   0,   0,   95,  0,   0,   3,   50,  16,  16,  0,   1,   0,   0,   0,
-    103, 0,   0,   4,   242, 32,  16,  0,   0,   0,   0,   0,   1,   0,   0,
-    0,   101, 0,   0,   3,   50,  32,  16,  0,   1,   0,   0,   0,   54,  0,
-    0,   5,   50,  32,  16,  0,   0,   0,   0,   0,   70,  16,  16,  0,   0,
-    0,   0,   0,   54,  0,   0,   8,   194, 32,  16,  0,   0,   0,   0,   0,
-    2,   64,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   128,
-    63,  0,   0,   128, 63,  54,  0,   0,   5,   50,  32,  16,  0,   1,   0,
-    0,   0,   70,  16,  16,  0,   1,   0,   0,   0,   62,  0,   0,   1,   83,
-    84,  65,  84,  116, 0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   82,  68,  69,  70,  80,  0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   28,  0,   0,   0,   0,   4,   254,
-    255, 0,   1,   0,   0,   28,  0,   0,   0,   77,  105, 99,  114, 111, 115,
-    111, 102, 116, 32,  40,  82,  41,  32,  72,  76,  83,  76,  32,  83,  104,
-    97,  100, 101, 114, 32,  67,  111, 109, 112, 105, 108, 101, 114, 32,  54,
-    46,  51,  46,  57,  54,  48,  48,  46,  49,  54,  51,  56,  52,  0,   171,
-    171, 73,  83,  71,  78,  76,  0,   0,   0,   2,   0,   0,   0,   8,   0,
-    0,   0,   56,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   3,
-    0,   0,   0,   0,   0,   0,   0,   3,   3,   0,   0,   65,  0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   1,   0,   0,
-    0,   3,   3,   0,   0,   80,  79,  83,  73,  84,  73,  79,  78,  0,   84,
-    69,  88,  67,  79,  79,  82,  68,  0,   171, 171, 79,  83,  71,  78,  80,
-    0,   0,   0,   2,   0,   0,   0,   8,   0,   0,   0,   56,  0,   0,   0,
-    0,   0,   0,   0,   1,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,
-    0,   15,  0,   0,   0,   68,  0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   3,   0,   0,   0,   1,   0,   0,   0,   3,   12,  0,   0,   83,
-    86,  95,  80,  79,  83,  73,  84,  73,  79,  78,  0,   84,  69,  88,  67,
-    79,  79,  82,  68,  0,   171, 171, 171};
-
-#endif  // DEVICE_VR_WINDOWS_FLIP_VERTEX_SHADER_H_
diff --git a/device/vr/windows/generate_shaders.bat b/device/vr/windows/generate_shaders.bat
index 9e3f93f..5a7acc5 100755
--- a/device/vr/windows/generate_shaders.bat
+++ b/device/vr/windows/generate_shaders.bat
@@ -20,8 +20,9 @@
 )

 

 ::              | Input file             | Entry point  | Type            | Output file           | Debug |

-call:BuildShader flip_vertex_shader.hlsl flip_vertex    vs_4_0_level_9_3  flip_vertex_shader.h    %debug%

+call:BuildShader vertex_shader.hlsl vertex    vs_4_0_level_9_3  vertex_shader.h    %debug%

 call:BuildShader flip_pixel_shader.hlsl  flip_pixel     ps_4_0_level_9_3  flip_pixel_shader.h     %debug%

+call:BuildShader geometry_shader.hlsl  geometry     gs_5_0  geometry_shader.h     %debug%

 

 echo.

 

@@ -57,4 +58,4 @@
     set /a errorCount=%errorCount%+1

 )

 

-exit /b
+exit /b

diff --git a/device/vr/windows/geometry_shader.h b/device/vr/windows/geometry_shader.h
new file mode 100644
index 0000000..0e27718
--- /dev/null
+++ b/device/vr/windows/geometry_shader.h
@@ -0,0 +1,128 @@
+// 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.
+
+// DO NOT MODIFY.  Use generate_shaders.bat to modify, then re-add this warning.
+#ifndef DEVICE_VR_WINDOWS_GEOMETRY_SHADER_H_
+#define DEVICE_VR_WINDOWS_GEOMETRY_SHADER_H_
+
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy
+// TEXCOORD                 1   x           2     NONE    uint   x
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy
+// SV_RenderTargetArrayIndex     0   x           2  RTINDEX    uint   x
+//
+gs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_input_siv v[3][0].xyzw, position
+dcl_input v[3][1].xy
+dcl_input v[3][2].x
+dcl_inputprimitive triangle
+dcl_stream m0
+dcl_outputtopology trianglestrip
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xy
+dcl_output_siv o2.x, rendertarget_array_index
+dcl_maxout 3
+mov o0.xyzw, v[0][0].xyzw
+mov o1.xy, v[0][1].xyxx
+mov o2.x, v[0][2].x
+emit_stream m0
+mov o0.xyzw, v[1][0].xyzw
+mov o1.xy, v[1][1].xyxx
+mov o2.x, v[1][2].x
+emit_stream m0
+mov o0.xyzw, v[2][0].xyzw
+mov o1.xy, v[2][1].xyxx
+mov o2.x, v[2][2].x
+emit_stream m0
+ret
+// Approximately 13 instruction slots used
+#endif
+
+const BYTE g_geometry[] = {
+    68,  88,  66,  67,  192, 67,  214, 18,  59,  16,  12,  193, 3,   224, 129,
+    54,  121, 194, 217, 87,  1,   0,   0,   0,   220, 3,   0,   0,   5,   0,
+    0,   0,   52,  0,   0,   0,   172, 0,   0,   0,   28,  1,   0,   0,   176,
+    1,   0,   0,   64,  3,   0,   0,   82,  68,  69,  70,  112, 0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   60,  0,   0,
+    0,   0,   5,   83,  71,  0,   1,   0,   0,   60,  0,   0,   0,   82,  68,
+    49,  49,  60,  0,   0,   0,   24,  0,   0,   0,   32,  0,   0,   0,   40,
+    0,   0,   0,   36,  0,   0,   0,   12,  0,   0,   0,   0,   0,   0,   0,
+    77,  105, 99,  114, 111, 115, 111, 102, 116, 32,  40,  82,  41,  32,  72,
+    76,  83,  76,  32,  83,  104, 97,  100, 101, 114, 32,  67,  111, 109, 112,
+    105, 108, 101, 114, 32,  54,  46,  51,  46,  57,  54,  48,  48,  46,  49,
+    54,  51,  56,  52,  0,   171, 171, 73,  83,  71,  78,  104, 0,   0,   0,
+    3,   0,   0,   0,   8,   0,   0,   0,   80,  0,   0,   0,   0,   0,   0,
+    0,   1,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,   15,  15,
+    0,   0,   92,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   3,
+    0,   0,   0,   1,   0,   0,   0,   3,   3,   0,   0,   92,  0,   0,   0,
+    1,   0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   2,   0,   0,
+    0,   1,   1,   0,   0,   83,  86,  95,  80,  79,  83,  73,  84,  73,  79,
+    78,  0,   84,  69,  88,  67,  79,  79,  82,  68,  0,   171, 171, 171, 79,
+    83,  71,  53,  140, 0,   0,   0,   3,   0,   0,   0,   8,   0,   0,   0,
+    0,   0,   0,   0,   92,  0,   0,   0,   0,   0,   0,   0,   1,   0,   0,
+    0,   3,   0,   0,   0,   0,   0,   0,   0,   15,  0,   0,   0,   0,   0,
+    0,   0,   104, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   3,
+    0,   0,   0,   1,   0,   0,   0,   3,   12,  0,   0,   0,   0,   0,   0,
+    113, 0,   0,   0,   0,   0,   0,   0,   4,   0,   0,   0,   1,   0,   0,
+    0,   2,   0,   0,   0,   1,   14,  0,   0,   83,  86,  95,  80,  79,  83,
+    73,  84,  73,  79,  78,  0,   84,  69,  88,  67,  79,  79,  82,  68,  0,
+    83,  86,  95,  82,  101, 110, 100, 101, 114, 84,  97,  114, 103, 101, 116,
+    65,  114, 114, 97,  121, 73,  110, 100, 101, 120, 0,   171, 83,  72,  69,
+    88,  136, 1,   0,   0,   80,  0,   2,   0,   98,  0,   0,   0,   106, 8,
+    0,   1,   97,  0,   0,   5,   242, 16,  32,  0,   3,   0,   0,   0,   0,
+    0,   0,   0,   1,   0,   0,   0,   95,  0,   0,   4,   50,  16,  32,  0,
+    3,   0,   0,   0,   1,   0,   0,   0,   95,  0,   0,   4,   18,  16,  32,
+    0,   3,   0,   0,   0,   2,   0,   0,   0,   93,  24,  0,   1,   143, 0,
+    0,   3,   0,   0,   17,  0,   0,   0,   0,   0,   92,  40,  0,   1,   103,
+    0,   0,   4,   242, 32,  16,  0,   0,   0,   0,   0,   1,   0,   0,   0,
+    101, 0,   0,   3,   50,  32,  16,  0,   1,   0,   0,   0,   103, 0,   0,
+    4,   18,  32,  16,  0,   2,   0,   0,   0,   4,   0,   0,   0,   94,  0,
+    0,   2,   3,   0,   0,   0,   54,  0,   0,   6,   242, 32,  16,  0,   0,
+    0,   0,   0,   70,  30,  32,  0,   0,   0,   0,   0,   0,   0,   0,   0,
+    54,  0,   0,   6,   50,  32,  16,  0,   1,   0,   0,   0,   70,  16,  32,
+    0,   0,   0,   0,   0,   1,   0,   0,   0,   54,  0,   0,   6,   18,  32,
+    16,  0,   2,   0,   0,   0,   10,  16,  32,  0,   0,   0,   0,   0,   2,
+    0,   0,   0,   117, 0,   0,   3,   0,   0,   17,  0,   0,   0,   0,   0,
+    54,  0,   0,   6,   242, 32,  16,  0,   0,   0,   0,   0,   70,  30,  32,
+    0,   1,   0,   0,   0,   0,   0,   0,   0,   54,  0,   0,   6,   50,  32,
+    16,  0,   1,   0,   0,   0,   70,  16,  32,  0,   1,   0,   0,   0,   1,
+    0,   0,   0,   54,  0,   0,   6,   18,  32,  16,  0,   2,   0,   0,   0,
+    10,  16,  32,  0,   1,   0,   0,   0,   2,   0,   0,   0,   117, 0,   0,
+    3,   0,   0,   17,  0,   0,   0,   0,   0,   54,  0,   0,   6,   242, 32,
+    16,  0,   0,   0,   0,   0,   70,  30,  32,  0,   2,   0,   0,   0,   0,
+    0,   0,   0,   54,  0,   0,   6,   50,  32,  16,  0,   1,   0,   0,   0,
+    70,  16,  32,  0,   2,   0,   0,   0,   1,   0,   0,   0,   54,  0,   0,
+    6,   18,  32,  16,  0,   2,   0,   0,   0,   10,  16,  32,  0,   2,   0,
+    0,   0,   2,   0,   0,   0,   117, 0,   0,   3,   0,   0,   17,  0,   0,
+    0,   0,   0,   62,  0,   0,   1,   83,  84,  65,  84,  148, 0,   0,   0,
+    13,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   3,   0,   0,   0,   5,   0,   0,   0,   3,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0};
+
+#endif  // DEVICE_VR_WINDOWS_GEOMETRY_SHADER_H_
diff --git a/device/vr/windows/geometry_shader.hlsl b/device/vr/windows/geometry_shader.hlsl
new file mode 100644
index 0000000..9f31637
--- /dev/null
+++ b/device/vr/windows/geometry_shader.hlsl
@@ -0,0 +1,30 @@
+// 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.
+struct VertexShaderOutput
+{
+  float4 pos : SV_POSITION;
+  float2 tex : TEXCOORD0;
+  uint idx : TEXCOORD1;
+};
+
+struct GeometryShaderOutput
+{
+  float4 pos : SV_POSITION;
+  float2 tex : TEXCOORD0;
+  uint idx : SV_RenderTargetArrayIndex;
+};
+
+[maxvertexcount(3)]
+void geometry(triangle VertexShaderOutput input[3], inout TriangleStream<GeometryShaderOutput> stream)
+{
+  GeometryShaderOutput output;
+  [unroll(3)]
+  for (int i = 0; i < 3; ++i)
+  {
+    output.pos = input[i].pos;
+    output.tex = input[i].tex;
+    output.idx = input[i].idx;
+    stream.Append(output);
+  }
+}
diff --git a/device/vr/windows/vertex_shader.h b/device/vr/windows/vertex_shader.h
new file mode 100644
index 0000000..3af620e
--- /dev/null
+++ b/device/vr/windows/vertex_shader.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// DO NOT MODIFY.  Use generate_shaders.bat to modify, then re-add this warning.
+#ifndef DEVICE_VR_WINDOWS_VERTEX_SHADER_H_
+#define DEVICE_VR_WINDOWS_VERTEX_SHADER_H_
+
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xy          0     NONE   float   xy
+// TEXCOORD                 0   xy          1     NONE   float   xy
+// TEXCOORD                 1   x           2     NONE    uint   x
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy
+// TEXCOORD                 1   x           2     NONE    uint   x
+//
+//
+// Runtime generated constant mappings:
+//
+// Target Reg                               Constant Description
+// ---------- --------------------------------------------------
+// c0                              Vertex Shader position offset
+//
+//
+// Level9 shader bytecode:
+//
+    vs_2_x
+    def c1, 1, 0, 0, 0
+    dcl_texcoord v0
+    dcl_texcoord1 v1
+    dcl_texcoord2 v2
+    add oPos.xy, v0, c0
+    mov oPos.zw, c1.x
+    mov oT0.xy, v1
+    mov oT1.x, v2.x
+
+// approximately 4 instruction slots used
+vs_4_0
+dcl_input v0.xy
+dcl_input v1.xy
+dcl_input v2.x
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xy
+dcl_output o2.x
+mov o0.xy, v0.xyxx
+mov o0.zw, l(0,0,1.000000,1.000000)
+mov o1.xy, v1.xyxx
+mov o2.x, v2.x
+ret
+// Approximately 5 instruction slots used
+#endif
+
+const BYTE g_vertex[] = {
+    68,  88,  66,  67,  19,  1,   203, 113, 23,  158, 27,  204, 22,  68,  213,
+    197, 130, 252, 251, 50,  1,   0,   0,   0,   76,  3,   0,   0,   6,   0,
+    0,   0,   56,  0,   0,   0,   224, 0,   0,   0,   156, 1,   0,   0,   24,
+    2,   0,   0,   112, 2,   0,   0,   220, 2,   0,   0,   65,  111, 110, 57,
+    160, 0,   0,   0,   160, 0,   0,   0,   0,   2,   254, 255, 120, 0,   0,
+    0,   40,  0,   0,   0,   0,   0,   36,  0,   0,   0,   36,  0,   0,   0,
+    36,  0,   0,   0,   36,  0,   1,   0,   36,  0,   0,   0,   0,   0,   1,
+    2,   254, 255, 81,  0,   0,   5,   1,   0,   15,  160, 0,   0,   128, 63,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   31,  0,   0,
+    2,   5,   0,   0,   128, 0,   0,   15,  144, 31,  0,   0,   2,   5,   0,
+    1,   128, 1,   0,   15,  144, 31,  0,   0,   2,   5,   0,   2,   128, 2,
+    0,   15,  144, 2,   0,   0,   3,   0,   0,   3,   192, 0,   0,   228, 144,
+    0,   0,   228, 160, 1,   0,   0,   2,   0,   0,   12,  192, 1,   0,   0,
+    160, 1,   0,   0,   2,   0,   0,   3,   224, 1,   0,   228, 144, 1,   0,
+    0,   2,   1,   0,   1,   224, 2,   0,   0,   144, 255, 255, 0,   0,   83,
+    72,  68,  82,  180, 0,   0,   0,   64,  0,   1,   0,   45,  0,   0,   0,
+    95,  0,   0,   3,   50,  16,  16,  0,   0,   0,   0,   0,   95,  0,   0,
+    3,   50,  16,  16,  0,   1,   0,   0,   0,   95,  0,   0,   3,   18,  16,
+    16,  0,   2,   0,   0,   0,   103, 0,   0,   4,   242, 32,  16,  0,   0,
+    0,   0,   0,   1,   0,   0,   0,   101, 0,   0,   3,   50,  32,  16,  0,
+    1,   0,   0,   0,   101, 0,   0,   3,   18,  32,  16,  0,   2,   0,   0,
+    0,   54,  0,   0,   5,   50,  32,  16,  0,   0,   0,   0,   0,   70,  16,
+    16,  0,   0,   0,   0,   0,   54,  0,   0,   8,   194, 32,  16,  0,   0,
+    0,   0,   0,   2,   64,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   128, 63,  0,   0,   128, 63,  54,  0,   0,   5,   50,  32,  16,
+    0,   1,   0,   0,   0,   70,  16,  16,  0,   1,   0,   0,   0,   54,  0,
+    0,   5,   18,  32,  16,  0,   2,   0,   0,   0,   10,  16,  16,  0,   2,
+    0,   0,   0,   62,  0,   0,   1,   83,  84,  65,  84,  116, 0,   0,   0,
+    5,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   4,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   82,  68,  69,  70,
+    80,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   28,  0,   0,   0,   0,   4,   254, 255, 0,   1,   0,   0,   28,  0,
+    0,   0,   77,  105, 99,  114, 111, 115, 111, 102, 116, 32,  40,  82,  41,
+    32,  72,  76,  83,  76,  32,  83,  104, 97,  100, 101, 114, 32,  67,  111,
+    109, 112, 105, 108, 101, 114, 32,  54,  46,  51,  46,  57,  54,  48,  48,
+    46,  49,  54,  51,  56,  52,  0,   171, 171, 73,  83,  71,  78,  100, 0,
+    0,   0,   3,   0,   0,   0,   8,   0,   0,   0,   80,  0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,
+    3,   3,   0,   0,   89,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   3,   0,   0,   0,   1,   0,   0,   0,   3,   3,   0,   0,   89,  0,
+    0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   2,
+    0,   0,   0,   1,   1,   0,   0,   80,  79,  83,  73,  84,  73,  79,  78,
+    0,   84,  69,  88,  67,  79,  79,  82,  68,  0,   171, 171, 79,  83,  71,
+    78,  104, 0,   0,   0,   3,   0,   0,   0,   8,   0,   0,   0,   80,  0,
+    0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   3,   0,   0,   0,   0,
+    0,   0,   0,   15,  0,   0,   0,   92,  0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   3,   0,   0,   0,   1,   0,   0,   0,   3,   12,  0,
+    0,   92,  0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+    0,   0,   2,   0,   0,   0,   1,   14,  0,   0,   83,  86,  95,  80,  79,
+    83,  73,  84,  73,  79,  78,  0,   84,  69,  88,  67,  79,  79,  82,  68,
+    0,   171, 171, 171};
+
+#endif  // DEVICE_VR_WINDOWS_VERTEX_SHADER_H_
diff --git a/device/vr/windows/flip_vertex_shader.hlsl b/device/vr/windows/vertex_shader.hlsl
similarity index 75%
rename from device/vr/windows/flip_vertex_shader.hlsl
rename to device/vr/windows/vertex_shader.hlsl
index 7221284..301d45f2 100644
--- a/device/vr/windows/flip_vertex_shader.hlsl
+++ b/device/vr/windows/vertex_shader.hlsl
@@ -4,22 +4,25 @@
 struct VertexShaderInput
 {
   float2 pos : POSITION;
-  float2 tex : TEXCOORD;
+  float2 tex : TEXCOORD0;
+  uint idx : TEXCOORD1;
 };
 
 struct PixelShaderInput
 {
   float4 pos : SV_POSITION;
   float2 tex : TEXCOORD0;
+  uint idx : TEXCOORD1;
 };
 
-PixelShaderInput flip_vertex(VertexShaderInput input)
+PixelShaderInput vertex(VertexShaderInput input)
 {
   PixelShaderInput output;
   float4 pos = float4(input.pos, 1.0f, 1.0f);
 
   output.pos = pos;
   output.tex = input.tex;
+  output.idx = input.idx;
 
   return output;
 }
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
index 3e1de369..8d94ab5 100644
--- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
+++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -111,15 +111,77 @@
 }
 
 bool MixedRealityRenderLoop::PreComposite() {
-  // Not yet implemented.
-  return false;
+  if (rendering_params_) {
+    Microsoft::WRL::ComPtr<
+        ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface>
+        surface;
+    if (FAILED(rendering_params_->get_Direct3D11BackBuffer(&surface)))
+      return false;
+    Microsoft::WRL::ComPtr<
+        Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>
+        dxgi_interface_access;
+    if (FAILED(surface.As(&dxgi_interface_access)))
+      return false;
+    Microsoft::WRL::ComPtr<ID3D11Resource> native_resource;
+    if (FAILED(dxgi_interface_access->GetInterface(
+            IID_PPV_ARGS(&native_resource))))
+      return false;
+
+    Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
+    if (FAILED(native_resource.As(&texture)))
+      return false;
+    texture_helper_.SetBackbuffer(texture);
+    D3D11_TEXTURE2D_DESC desc;
+    texture->GetDesc(&desc);
+
+    ABI::Windows::Foundation::Rect viewport;
+    if (FAILED(pose_->get_Viewport(&viewport)))
+      return false;
+
+    gfx::RectF override_viewport =
+        gfx::RectF(viewport.X / desc.Width, viewport.Y / desc.Height,
+                   viewport.Width / desc.Width, viewport.Height / desc.Height);
+
+    texture_helper_.OverrideViewports(override_viewport, override_viewport);
+    texture_helper_.SetDefaultSize(gfx::Size(desc.Width, desc.Height));
+  }
+  return true;
 }
 
 bool MixedRealityRenderLoop::SubmitCompositedFrame() {
-  // Not yet implemented.
-  return false;
+  ABI::Windows::Graphics::Holographic::HolographicFramePresentResult result;
+  if (FAILED(holographic_frame_->PresentUsingCurrentPrediction(&result)))
+    return false;
+  texture_helper_.DiscardView();
+  return true;
 }
 
+namespace {
+
+FARPROC LoadD3D11Function(const char* function_name) {
+  static HMODULE const handle = ::LoadLibrary(L"d3d11.dll");
+  return handle ? ::GetProcAddress(handle, function_name) : nullptr;
+}
+
+decltype(&::CreateDirect3D11DeviceFromDXGIDevice)
+GetCreateDirect3D11DeviceFromDXGIDeviceFunction() {
+  static decltype(&::CreateDirect3D11DeviceFromDXGIDevice) const function =
+      reinterpret_cast<decltype(&::CreateDirect3D11DeviceFromDXGIDevice)>(
+          LoadD3D11Function("CreateDirect3D11DeviceFromDXGIDevice"));
+  return function;
+}
+
+HRESULT WrapperCreateDirect3D11DeviceFromDXGIDevice(IDXGIDevice* in,
+                                                    IInspectable** out) {
+  *out = nullptr;
+  auto func = GetCreateDirect3D11DeviceFromDXGIDeviceFunction();
+  if (!func)
+    return E_FAIL;
+  return func(in, out);
+}
+
+}  // namespace
+
 bool MixedRealityRenderLoop::StartRuntime() {
   initializer_ = std::make_unique<base::win::ScopedWinrtInitializer>();
 
@@ -148,7 +210,7 @@
     return false;
 
   ComPtr<IInspectable> spInsp;
-  hr = CreateDirect3D11DeviceFromDXGIDevice(dxgi_device.Get(), &spInsp);
+  hr = WrapperCreateDirect3D11DeviceFromDXGIDevice(dxgi_device.Get(), &spInsp);
   if (FAILED(hr))
     return false;
 
@@ -167,6 +229,13 @@
   holographic_space_ = nullptr;
   origin_ = nullptr;
 
+  holographic_frame_ = nullptr;
+  prediction_ = nullptr;
+  poses_ = nullptr;
+  pose_ = nullptr;
+  rendering_params_ = nullptr;
+  camera_ = nullptr;
+
   if (window_)
     DestroyWindow(window_->hwnd());
   window_ = nullptr;
@@ -286,7 +355,7 @@
   DCHECK(decomposable);
 
   gfx::Quaternion world_to_eye_rotation = world_to_view_decomposed.quaternion;
-  return {world_to_eye_rotation, eye_in_world_space};
+  return {world_to_eye_rotation.inverse(), eye_in_world_space};
 }
 
 mojom::VRPosePtr GetMonoViewData(const HolographicStereoTransform& view) {
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.h b/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
index 28b0158..92f7ee6 100644
--- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
+++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
@@ -79,9 +79,14 @@
   Microsoft::WRL::ComPtr<
       ABI::Windows::Graphics::Holographic::IHolographicFramePrediction>
       prediction_;
+
+  // The set of all poses for this frame (there could be multiple headsets or
+  // external cameras).
   Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVectorView<
       ABI::Windows::Graphics::Holographic::HolographicCameraPose*>>
       poses_;
+
+  // We only support one headset at a time - this is the one pose.
   Microsoft::WRL::ComPtr<
       ABI::Windows::Graphics::Holographic::IHolographicCameraPose>
       pose_;
diff --git a/docs/chrome_os_logging.md b/docs/chrome_os_logging.md
index 07c2adba..cdbb6e2 100644
--- a/docs/chrome_os_logging.md
+++ b/docs/chrome_os_logging.md
@@ -10,10 +10,11 @@
   that are written very early in Chrome's startup process, before logging has
   been initialized.
 * `/var/log/chrome/chrome` contains messages that are written before a user has
-  logged in.
+  logged in. It also contains messages written after login on test images, where
+  chrome runs with `--disable-logging-redirect`.
 * `/home/chronos/user/log/chrome` contains messages that are written while a
-  user is logged in. Note that this path is within the user's encrypted home
-  directory and is only accessible while the user is logged in.
+  user is logged in on non-test images. Note that this path is within the user's
+  encrypted home directory and is only accessible while the user is logged in.
 
 All of the above files are actually symlinks. Older log files can be found
 alongside them in the same directories.
diff --git a/extensions/browser/api/alarms/alarms_api_unittest.cc b/extensions/browser/api/alarms/alarms_api_unittest.cc
index 09a6a2aae..d5aa621 100644
--- a/extensions/browser/api/alarms/alarms_api_unittest.cc
+++ b/extensions/browser/api/alarms/alarms_api_unittest.cc
@@ -692,7 +692,7 @@
         "[{\"name\": \"hello\", \"scheduledTime\": 10000, "
         "\"periodInMinutes\": 0.0001}]";
     std::unique_ptr<base::ListValue> value =
-        base::ListValue::From(base::JSONReader::Read(alarm_args));
+        base::ListValue::From(base::JSONReader::ReadDeprecated(alarm_args));
     alarm_manager_->ReadFromStorage(extension()->id(), test_data[i].is_unpacked,
                                     std::move(value));
 
diff --git a/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc b/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
index d82c63f..e9b213c 100644
--- a/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
+++ b/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
@@ -29,7 +29,8 @@
 
 bool ParseResult(const std::string& status, std::string* ip, double* latency) {
   // Parses the result and returns IP and latency.
-  std::unique_ptr<base::Value> parsed_value(base::JSONReader::Read(status));
+  std::unique_ptr<base::Value> parsed_value(
+      base::JSONReader::ReadDeprecated(status));
   if (!parsed_value)
     return false;
 
diff --git a/extensions/browser/api/messaging/extension_message_port.cc b/extensions/browser/api/messaging/extension_message_port.cc
index bd8bd697..e6b3258 100644
--- a/extensions/browser/api/messaging/extension_message_port.cc
+++ b/extensions/browser/api/messaging/extension_message_port.cc
@@ -171,17 +171,6 @@
 
 ExtensionMessagePort::~ExtensionMessagePort() {}
 
-void ExtensionMessagePort::RevalidatePort() {
-  // Only opener ports need to be revalidated, because these are created in the
-  // renderer before the browser knows about them.
-  DCHECK(!extension_process_);
-  DCHECK_LE(frames_.size(), 1U);
-
-  // If the port is unknown, the renderer will respond by closing the port.
-  SendToPort(std::make_unique<ExtensionMsg_ValidateMessagePort>(
-      MSG_ROUTING_NONE, port_id_));
-}
-
 void ExtensionMessagePort::RemoveCommonFrames(const MessagePort& port) {
   // Avoid overlap in the set of frames to make sure that it does not matter
   // when UnregisterFrame is called.
@@ -202,6 +191,22 @@
   return !frames_.empty();
 }
 
+void ExtensionMessagePort::RevalidatePort() {
+  // Checks whether the frames to which this port is tied at its construction
+  // are still aware of this port's existence. Frames that don't know about
+  // the port are removed from the set of frames. This should be used for opener
+  // ports because the frame may be navigated before the port was initialized.
+
+  // Only opener ports need to be revalidated, because these are created in the
+  // renderer before the browser knows about them.
+  DCHECK(!extension_process_);
+  DCHECK_LE(frames_.size(), 1U);
+
+  // If the port is unknown, the renderer will respond by closing the port.
+  SendToPort(std::make_unique<ExtensionMsg_ValidateMessagePort>(
+      MSG_ROUTING_NONE, port_id_));
+}
+
 void ExtensionMessagePort::DispatchOnConnect(
     const std::string& channel_name,
     std::unique_ptr<base::DictionaryValue> source_tab,
diff --git a/extensions/browser/api/messaging/extension_message_port.h b/extensions/browser/api/messaging/extension_message_port.h
index cc7582fd..a7520c7 100644
--- a/extensions/browser/api/messaging/extension_message_port.h
+++ b/extensions/browser/api/messaging/extension_message_port.h
@@ -46,16 +46,11 @@
                        content::RenderProcessHost* extension_process);
   ~ExtensionMessagePort() override;
 
-  // Checks whether the frames to which this port is tied at its construction
-  // are still aware of this port's existence. Frames that don't know about
-  // the port are removed from the set of frames. This should be used for opener
-  // ports because the frame may be navigated before the port was initialized.
-  void RevalidatePort();
-
   // MessagePort:
   void RemoveCommonFrames(const MessagePort& port) override;
   bool HasFrame(content::RenderFrameHost* rfh) const override;
   bool IsValidPort() override;
+  void RevalidatePort() override;
   void DispatchOnConnect(const std::string& channel_name,
                          std::unique_ptr<base::DictionaryValue> source_tab,
                          int source_frame_id,
diff --git a/extensions/browser/api/messaging/message_port.cc b/extensions/browser/api/messaging/message_port.cc
index 20eea06..ba8cdf9 100644
--- a/extensions/browser/api/messaging/message_port.cc
+++ b/extensions/browser/api/messaging/message_port.cc
@@ -15,6 +15,8 @@
   return false;
 }
 
+void MessagePort::RevalidatePort() {}
+
 void MessagePort::DispatchOnConnect(
     const std::string& channel_name,
     std::unique_ptr<base::DictionaryValue> source_tab,
diff --git a/extensions/browser/api/messaging/message_port.h b/extensions/browser/api/messaging/message_port.h
index 676a4b0..f1339d60 100644
--- a/extensions/browser/api/messaging/message_port.h
+++ b/extensions/browser/api/messaging/message_port.h
@@ -52,6 +52,10 @@
   // is not used and the channel is closed.
   virtual bool IsValidPort() = 0;
 
+  // Triggers the check of whether the port is still valid. If the port is
+  // determined to be invalid, the channel will be closed.
+  virtual void RevalidatePort();
+
   // Notifies the port that the channel has been opened.
   virtual void DispatchOnConnect(
       const std::string& channel_name,
diff --git a/extensions/browser/api/messaging/message_service.cc b/extensions/browser/api/messaging/message_service.cc
index 7d64865..347afaf 100644
--- a/extensions/browser/api/messaging/message_service.cc
+++ b/extensions/browser/api/messaging/message_service.cc
@@ -82,6 +82,7 @@
   std::unique_ptr<MessagePort> receiver;
   PortId receiver_port_id;
   MessagingEndpoint source_endpoint;
+  std::unique_ptr<MessagePort> opener_port;
   std::string target_extension_id;
   GURL source_url;
   std::string channel_name;
@@ -95,23 +96,23 @@
                     MessagePort* receiver,
                     const PortId& receiver_port_id,
                     const MessagingEndpoint& source_endpoint,
+                    std::unique_ptr<MessagePort> opener_port,
                     const std::string& target_extension_id,
                     const GURL& source_url,
                     const std::string& channel_name,
                     bool include_guest_process_info)
       : source_process_id(source_process_id),
         source_routing_id(source_routing_id),
+        source_tab(std::move(source_tab)),
         source_frame_id(source_frame_id),
         receiver(receiver),
         receiver_port_id(receiver_port_id),
         source_endpoint(source_endpoint),
+        opener_port(std::move(opener_port)),
         target_extension_id(target_extension_id),
         source_url(source_url),
         channel_name(channel_name),
-        include_guest_process_info(include_guest_process_info) {
-    if (source_tab)
-      this->source_tab = std::move(source_tab);
-  }
+        include_guest_process_info(include_guest_process_info) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
@@ -177,17 +178,22 @@
       content::RenderFrameHost::FromID(source_process_id, source_routing_id);
   if (!source_render_frame_host)
     return;
+
+  auto opener_port = std::make_unique<ExtensionMessagePort>(
+      weak_factory_.GetWeakPtr(), source_port_id,
+      source_endpoint.extension_id ? *source_endpoint.extension_id
+                                   : ExtensionId(),
+      source_render_frame_host, false /* include_child_frames */);
+  if (!opener_port->IsValidPort())
+    return;
+
   BrowserContext* context =
       source_render_frame_host->GetProcess()->GetBrowserContext();
-
   ExtensionRegistry* registry = ExtensionRegistry::Get(context);
   const Extension* target_extension =
       registry->enabled_extensions().GetByID(target_extension_id);
-  PortId receiver_port_id(source_port_id.context_id, source_port_id.port_number,
-                          false);
   if (!target_extension) {
-    DispatchOnDisconnect(source_render_frame_host, receiver_port_id,
-                         kReceivingEndDoesntExistError);
+    opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
@@ -226,8 +232,7 @@
       // Important: use kReceivingEndDoesntExistError here so that we don't
       // leak information about this extension to callers. This way it's
       // indistinguishable from the extension just not existing.
-      DispatchOnDisconnect(source_render_frame_host, receiver_port_id,
-                           kReceivingEndDoesntExistError);
+      opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
       return;
     }
   }
@@ -260,9 +265,9 @@
 
   std::unique_ptr<OpenChannelParams> params(new OpenChannelParams(
       source_process_id, source_routing_id, std::move(source_tab),
-      source_frame_id, nullptr, receiver_port_id, source_endpoint,
-      target_extension_id, source_url, channel_name,
-      include_guest_process_info));
+      source_frame_id, nullptr, source_port_id.GetOppositePortId(),
+      source_endpoint, std::move(opener_port), target_extension_id, source_url,
+      channel_name, include_guest_process_info));
 
   pending_incognito_channels_[params->receiver_port_id.GetChannelId()] =
       PendingMessagesQueue();
@@ -324,26 +329,30 @@
   if (!source)
     return;
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
   content::WebContents* web_contents =
       content::WebContents::FromRenderFrameHost(source);
+  if (!web_contents)
+    return;
   ExtensionWebContentsObserver* extension_web_contents_observer =
-      web_contents ?
-          ExtensionWebContentsObserver::GetForWebContents(web_contents) :
-          nullptr;
+      ExtensionWebContentsObserver::GetForWebContents(web_contents);
+  if (!extension_web_contents_observer)
+    return;
   const Extension* extension =
-      extension_web_contents_observer ?
-          extension_web_contents_observer->GetExtensionFromFrame(source, true) :
-          nullptr;
+      extension_web_contents_observer->GetExtensionFromFrame(source, true);
+  if (!extension)
+    return;
 
-  bool has_permission = extension &&
-                        extension->permissions_data()->HasAPIPermission(
-                            APIPermission::kNativeMessaging);
+  auto opener_port = std::make_unique<ExtensionMessagePort>(
+      weak_factory_.GetWeakPtr(), source_port_id, extension->id(), source,
+      false /* include_child_frames */);
+  if (!opener_port->IsValidPort())
+    return;
 
-  PortId receiver_port_id(source_port_id.context_id, source_port_id.port_number,
-                          false);
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+  bool has_permission = extension->permissions_data()->HasAPIPermission(
+      APIPermission::kNativeMessaging);
   if (!has_permission) {
-    DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
+    opener_port->DispatchOnDisconnect(kMissingPermissionError);
     return;
   }
 
@@ -352,19 +361,16 @@
       messaging_delegate_->IsNativeMessagingHostAllowed(
           source->GetProcess()->GetBrowserContext(), native_app_name);
   if (policy_permission == MessagingDelegate::PolicyPermission::DISALLOW) {
-    DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
+    opener_port->DispatchOnDisconnect(kProhibitedByPoliciesError);
     return;
   }
 
   std::unique_ptr<MessageChannel> channel = std::make_unique<MessageChannel>();
-  channel->opener.reset(
-      new ExtensionMessagePort(weak_factory_.GetWeakPtr(), source_port_id,
-                               extension->id(), source, false));
-  if (!channel->opener->IsValidPort())
-    return;
+  channel->opener = std::move(opener_port);
   channel->opener->OpenPort(source_process_id, source_routing_id);
 
   std::string error = kReceivingEndDoesntExistError;
+  const PortId receiver_port_id = source_port_id.GetOppositePortId();
   std::unique_ptr<MessagePort> receiver(
       messaging_delegate_->CreateReceiverForNativeApp(
           weak_factory_.GetWeakPtr(), source, extension->id(), receiver_port_id,
@@ -374,7 +380,7 @@
 
   if (!receiver.get()) {
     // Abandon the channel.
-    DispatchOnDisconnect(source, receiver_port_id, error);
+    channel->opener->DispatchOnDisconnect(error);
     return;
   }
 
@@ -387,8 +393,7 @@
 #else  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
   const char kNativeMessagingNotSupportedError[] =
       "Native Messaging is not supported on this platform.";
-  DispatchOnDisconnect(
-      source, receiver_port_id, kNativeMessagingNotSupportedError);
+  opener_port->DispatchOnDisconnect(kNativeMessagingNotSupportedError);
 #endif  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
 }
 
@@ -407,27 +412,30 @@
       content::RenderFrameHost::FromID(source_process_id, source_routing_id);
   if (!source)
     return;
+
+  auto opener_port = std::make_unique<ExtensionMessagePort>(
+      weak_factory_.GetWeakPtr(), source_port_id, extension_id, source,
+      false /* include_child_frames */);
+  if (!opener_port->IsValidPort())
+    return;
+
   content::BrowserContext* browser_context =
       source->GetProcess()->GetBrowserContext();
-
-  PortId receiver_port_id(source_port_id.context_id, source_port_id.port_number,
-                          false);
   content::WebContents* receiver_contents =
       messaging_delegate_->GetWebContentsByTabId(browser_context, tab_id);
   if (!receiver_contents || receiver_contents->GetController().NeedsReload()) {
     // The tab isn't loaded yet. Don't attempt to connect.
-    DispatchOnDisconnect(
-        source, receiver_port_id, kReceivingEndDoesntExistError);
+    opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
+  const PortId receiver_port_id = source_port_id.GetOppositePortId();
   std::unique_ptr<MessagePort> receiver =
       messaging_delegate_->CreateReceiverForTab(weak_factory_.GetWeakPtr(),
                                                 extension_id, receiver_port_id,
                                                 receiver_contents, frame_id);
   if (!receiver.get()) {
-    DispatchOnDisconnect(
-        source, receiver_port_id, kReceivingEndDoesntExistError);
+    opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
@@ -448,7 +456,8 @@
                                                  // for opening to tabs.
       -1,  // If there is no tab, then there is no frame either.
       receiver.release(), receiver_port_id,
-      MessagingEndpoint::ForExtension(extension_id), extension_id,
+      MessagingEndpoint::ForExtension(extension_id), std::move(opener_port),
+      extension_id,
       GURL(),  // Source URL doesn't make sense for opening to tabs.
       channel_name,
       false));  // Connections to tabs aren't webview guests.
@@ -463,39 +472,34 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty());
 
+  // Check whether the source got closed while in flight.
   content::RenderFrameHost* source =
       content::RenderFrameHost::FromID(params->source_process_id,
                                        params->source_routing_id);
   if (!source)
-    return;  // Closed while in flight.
+    return;
+  if (!params->opener_port->IsValidPort())
+    return;
 
   if (!params->receiver || !params->receiver->IsValidPort()) {
-    DispatchOnDisconnect(source, params->receiver_port_id,
-                         kReceivingEndDoesntExistError);
+    params->opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
-  std::unique_ptr<ExtensionMessagePort> opener(new ExtensionMessagePort(
-      weak_factory_.GetWeakPtr(), params->receiver_port_id.GetOppositePortId(),
-      params->source_endpoint.extension_id
-          ? *params->source_endpoint.extension_id
-          : ExtensionId(),
-      source, false));
-  if (!opener->IsValidPort())
-    return;
-  opener->OpenPort(params->source_process_id, params->source_routing_id);
-  opener->RevalidatePort();
+  params->opener_port->OpenPort(params->source_process_id,
+                                params->source_routing_id);
+  params->opener_port->RevalidatePort();
 
-  params->receiver->RemoveCommonFrames(*opener);
+  params->receiver->RemoveCommonFrames(*params->opener_port);
   if (!params->receiver->IsValidPort()) {
-    opener->DispatchOnDisconnect(kReceivingEndDoesntExistError);
+    params->opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
   std::unique_ptr<MessageChannel> channel_ptr =
       std::make_unique<MessageChannel>();
   MessageChannel* channel = channel_ptr.get();
-  channel->opener = std::move(opener);
+  channel->opener = std::move(params->opener_port);
   channel->receiver = std::move(params->receiver);
   AddChannel(std::move(channel_ptr), params->receiver_port_id);
 
@@ -596,7 +600,9 @@
                                    int routing_id,
                                    bool force_close,
                                    const std::string& error_message) {
-  // Note: The channel might be gone already, if the other side closed first.
+  // Note: The channel might be not yet created (if the opener became invalid
+  // before the channel initialization completed) or already gone (if the other
+  // side closed first).
   ChannelId channel_id = port_id.GetChannelId();
   auto it = channels_.find(channel_id);
   if (it == channels_.end()) {
@@ -767,17 +773,18 @@
   pending_messages.swap(pending_for_incognito->second);
   pending_incognito_channels_.erase(pending_for_incognito);
 
-  // Re-lookup the source process since it may no longer be valid.
+  // Check whether the source got closed while in flight.
   content::RenderFrameHost* source =
       content::RenderFrameHost::FromID(params->source_process_id,
                                        params->source_routing_id);
   if (!source) {
     return;
   }
+  if (!params->opener_port->IsValidPort())
+    return;
 
   if (!allowed) {
-    DispatchOnDisconnect(source, params->receiver_port_id,
-                         kReceivingEndDoesntExistError);
+    params->opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
@@ -801,8 +808,7 @@
   const Extension* target_extension =
       registry->enabled_extensions().GetByID(params->target_extension_id);
   if (!target_extension) {
-    DispatchOnDisconnect(source, params->receiver_port_id,
-                         kReceivingEndDoesntExistError);
+    params->opener_port->DispatchOnDisconnect(kReceivingEndDoesntExistError);
     return;
   }
 
@@ -837,18 +843,6 @@
                   true /* did_enqueue */);
 }
 
-void MessageService::DispatchOnDisconnect(content::RenderFrameHost* source,
-                                          const PortId& port_id,
-                                          const std::string& error_message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  ExtensionMessagePort port(weak_factory_.GetWeakPtr(),
-                            port_id.GetOppositePortId(), "", source, false);
-  if (!port.IsValidPort())
-    return;
-  port.DispatchOnDisconnect(error_message);
-}
-
 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue,
                                              const ChannelId& channel_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/extensions/browser/api/messaging/message_service.h b/extensions/browser/api/messaging/message_service.h
index 90c421a8..81d2df45 100644
--- a/extensions/browser/api/messaging/message_service.h
+++ b/extensions/browser/api/messaging/message_service.h
@@ -218,12 +218,6 @@
       PostMessage(port_id, message);
   }
 
-  // Immediate dispatches a disconnect to |source| for |port_id|. Sets source's
-  // runtime.lastMessage to |error_message|, if any.
-  void DispatchOnDisconnect(content::RenderFrameHost* source,
-                            const PortId& port_id,
-                            const std::string& error_message);
-
   void DispatchPendingMessages(const PendingMessagesQueue& queue,
                                const ChannelId& channel_id);
 
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos.cc b/extensions/browser/api/networking_private/networking_private_chromeos.cc
index 00d7289e..e904c73f 100644
--- a/extensions/browser/api/networking_private/networking_private_chromeos.cc
+++ b/extensions/browser/api/networking_private/networking_private_chromeos.cc
@@ -739,7 +739,9 @@
 
   std::vector<private_api::Certificate> user_cert_list;
   const std::vector<NetworkCertificateHandler::Certificate>& user_certs =
-      NetworkHandler::Get()->network_certificate_handler()->user_certificates();
+      NetworkHandler::Get()
+          ->network_certificate_handler()
+          ->client_certificates();
   for (const auto& cert : user_certs)
     result.user_certificates.push_back(GetCertDictionary(cert));
 
diff --git a/extensions/browser/api/storage/storage_frontend.cc b/extensions/browser/api/storage/storage_frontend.cc
index ffbd12a..8934733 100644
--- a/extensions/browser/api/storage/storage_frontend.cc
+++ b/extensions/browser/api/storage/storage_frontend.cc
@@ -63,7 +63,8 @@
   void OnSettingsChanged(const std::string& extension_id,
                          settings_namespace::Namespace settings_namespace,
                          const std::string& change_json) override {
-    std::unique_ptr<base::Value> changes = base::JSONReader::Read(change_json);
+    std::unique_ptr<base::Value> changes =
+        base::JSONReader::ReadDeprecated(change_json);
     DCHECK(changes);
     // TODO(devlin): crbug.com/645500 implies this can sometimes fail. If this
     // safeguard fixes it, that means there's an underlying problem (why are we
diff --git a/extensions/browser/api_test_utils.cc b/extensions/browser/api_test_utils.cc
index 561a9bd9c..7fa6f94 100644
--- a/extensions/browser/api_test_utils.cc
+++ b/extensions/browser/api_test_utils.cc
@@ -23,7 +23,7 @@
 namespace {
 
 std::unique_ptr<base::Value> ParseJSON(const std::string& data) {
-  return base::JSONReader::Read(data);
+  return base::JSONReader::ReadDeprecated(data);
 }
 
 std::unique_ptr<base::ListValue> ParseList(const std::string& data) {
diff --git a/extensions/browser/computed_hashes.cc b/extensions/browser/computed_hashes.cc
index dab6e435..714b9f3b 100644
--- a/extensions/browser/computed_hashes.cc
+++ b/extensions/browser/computed_hashes.cc
@@ -80,7 +80,8 @@
     return false;
 
   base::DictionaryValue* top_dictionary = NULL;
-  std::unique_ptr<base::Value> value(base::JSONReader::Read(contents));
+  std::unique_ptr<base::Value> value(
+      base::JSONReader::ReadDeprecated(contents));
   if (!value.get() || !value->GetAsDictionary(&top_dictionary))
     return false;
 
diff --git a/extensions/browser/content_verifier/content_hash.cc b/extensions/browser/content_verifier/content_hash.cc
index 13409ad..cae5db6 100644
--- a/extensions/browser/content_verifier/content_hash.cc
+++ b/extensions/browser/content_verifier/content_hash.cc
@@ -183,7 +183,7 @@
   // the right cookies).  TODO(asargent) - It would be a nice enhancement to
   // move to parsing this in a sandboxed helper (https://crbug.com/372878).
   std::unique_ptr<base::Value> parsed =
-      base::JSONReader::Read(*fetched_contents);
+      base::JSONReader::ReadDeprecated(*fetched_contents);
   if (!parsed) {
     ContentHash::DispatchFetchFailure(key, std::move(created_callback),
                                       is_cancelled);
diff --git a/extensions/browser/value_store/lazy_leveldb.cc b/extensions/browser/value_store/lazy_leveldb.cc
index f2acad0..8453860 100644
--- a/extensions/browser/value_store/lazy_leveldb.cc
+++ b/extensions/browser/value_store/lazy_leveldb.cc
@@ -101,7 +101,7 @@
     return ToValueStoreError(s);
 
   std::unique_ptr<base::Value> val =
-      base::JSONReader().ReadToValue(value_as_json);
+      base::JSONReader().ReadToValueDeprecated(value_as_json);
   if (!val)
     return ValueStore::Status(ValueStore::CORRUPTION, FixCorruption(&key),
                               kInvalidJson);
diff --git a/extensions/browser/value_store/leveldb_scoped_database.cc b/extensions/browser/value_store/leveldb_scoped_database.cc
index 11d7edf..129d2bc 100644
--- a/extensions/browser/value_store/leveldb_scoped_database.cc
+++ b/extensions/browser/value_store/leveldb_scoped_database.cc
@@ -79,7 +79,7 @@
        it->Next()) {
     leveldb::Slice descoped_key(it->key());
     descoped_key.remove_prefix(prefix.size());
-    std::unique_ptr<base::Value> value = json_reader.Read(
+    std::unique_ptr<base::Value> value = json_reader.ReadDeprecated(
         base::StringPiece(it->value().data(), it->value().size()));
     if (!value) {
       return ValueStore::Status(ValueStore::CORRUPTION,
diff --git a/extensions/browser/value_store/leveldb_value_store.cc b/extensions/browser/value_store/leveldb_value_store.cc
index 2b31c98..dd3ca2c9c 100644
--- a/extensions/browser/value_store/leveldb_value_store.cc
+++ b/extensions/browser/value_store/leveldb_value_store.cc
@@ -103,7 +103,7 @@
   std::unique_ptr<leveldb::Iterator> it(db()->NewIterator(read_options()));
   for (it->SeekToFirst(); it->Valid(); it->Next()) {
     std::string key = it->key().ToString();
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(
+    std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
         StringPiece(it->value().data(), it->value().size()));
     if (!value) {
       return ReadResult(Status(CORRUPTION,
diff --git a/extensions/browser/value_store/value_store_change_unittest.cc b/extensions/browser/value_store/value_store_change_unittest.cc
index bd221bf..a3e8ed4a 100644
--- a/extensions/browser/value_store/value_store_change_unittest.cc
+++ b/extensions/browser/value_store/value_store_change_unittest.cc
@@ -73,7 +73,8 @@
       "key.with.dots", value->CreateDeepCopy(), value->CreateDeepCopy()));
 
   std::string json = ValueStoreChange::ToJson(change_list);
-  std::unique_ptr<base::Value> from_json(base::JSONReader::Read(json));
+  std::unique_ptr<base::Value> from_json(
+      base::JSONReader::ReadDeprecated(json));
   ASSERT_TRUE(from_json.get());
 
   DictionaryBuilder v1(*value);
diff --git a/extensions/browser/verified_contents.cc b/extensions/browser/verified_contents.cc
index 9677b41..9d8032b 100644
--- a/extensions/browser/verified_contents.cc
+++ b/extensions/browser/verified_contents.cc
@@ -154,7 +154,7 @@
   if (!verified_contents->GetPayload(path, &payload))
     return nullptr;
 
-  std::unique_ptr<base::Value> value(base::JSONReader::Read(payload));
+  std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(payload));
   if (!value.get() || !value->is_dict())
     return nullptr;
   DictionaryValue* dictionary = static_cast<DictionaryValue*>(value.get());
@@ -318,7 +318,8 @@
   std::string contents;
   if (!base::ReadFileToString(path, &contents))
     return false;
-  std::unique_ptr<base::Value> value(base::JSONReader::Read(contents));
+  std::unique_ptr<base::Value> value(
+      base::JSONReader::ReadDeprecated(contents));
   if (!value.get() || !value->is_list())
     return false;
   ListValue* top_list = static_cast<ListValue*>(value.get());
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index b0b1f04..4b3a1d5 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -345,7 +345,8 @@
     "extension_types": ["platform_app", "extension"],
     "whitelist": [
       "63ED55E43214C211F82122ED56407FF1A807F2A3",   // Media Router Dev
-      "226CF815E39A363090A1E547D53063472B8279FA"    // Media Router Stable
+      "226CF815E39A363090A1E547D53063472B8279FA",   // Media Router Stable
+      "A3E3DE9E9F16B41D4A2FAD106BD6CA76B94A0C94"    // Chrome Camera App Prod
     ]
   },
   "networking.config": {
diff --git a/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc b/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc
index b64b9ae..0076e3d0 100644
--- a/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc
+++ b/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc
@@ -42,7 +42,7 @@
 
 static std::unique_ptr<base::Value> ParsePermissionJSON(
     const std::string& json) {
-  std::unique_ptr<base::Value> result(base::JSONReader::Read(json));
+  std::unique_ptr<base::Value> result(base::JSONReader::ReadDeprecated(json));
   EXPECT_TRUE(result) << "Invalid JSON string: " << json;
   return result;
 }
diff --git a/extensions/common/extension_api.cc b/extensions/common/extension_api.cc
index a161b59..0951291 100644
--- a/extensions/common/extension_api.cc
+++ b/extensions/common/extension_api.cc
@@ -40,10 +40,11 @@
     const base::StringPiece& schema) {
   std::string error_message;
   std::unique_ptr<base::Value> result(
-      base::JSONReader::ReadAndReturnError(schema,
-                                           base::JSON_PARSE_RFC,  // options
-                                           NULL,                  // error code
-                                           &error_message));
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          schema,
+          base::JSON_PARSE_RFC,  // options
+          NULL,                  // error code
+          &error_message));
 
   // Tracking down http://crbug.com/121424
   char buf[128];
diff --git a/extensions/common/features/json_feature_provider_source.cc b/extensions/common/features/json_feature_provider_source.cc
index f24aeeb..b337c2fd 100644
--- a/extensions/common/features/json_feature_provider_source.cc
+++ b/extensions/common/features/json_feature_provider_source.cc
@@ -25,8 +25,9 @@
       ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
   int error_code = 0;
   std::string error_message;
-  std::unique_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
-      features_file, base::JSON_PARSE_RFC, &error_code, &error_message));
+  std::unique_ptr<base::Value> value(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          features_file, base::JSON_PARSE_RFC, &error_code, &error_message));
   DCHECK(value) << "Could not load features: " << name_ << " " << error_message;
 
   std::unique_ptr<base::DictionaryValue> value_as_dict;
diff --git a/extensions/renderer/bindings/api_binding_test_util.cc b/extensions/renderer/bindings/api_binding_test_util.cc
index 120dc400..5e53c2a 100644
--- a/extensions/renderer/bindings/api_binding_test_util.cc
+++ b/extensions/renderer/bindings/api_binding_test_util.cc
@@ -57,7 +57,7 @@
 
 std::unique_ptr<base::Value> ValueFromString(base::StringPiece str) {
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(ReplaceSingleQuotes(str));
+      base::JSONReader::ReadDeprecated(ReplaceSingleQuotes(str));
   EXPECT_TRUE(value) << str;
   return value;
 }
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index bc25c52..be331a4d 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -886,6 +886,13 @@
                                      extension_id);
   }
 
+  // TODO(yoichio): This is temporary switch to have chrome internal extensions
+  // use the old web APIs.
+  // After completion of the migration, we should remove this.
+  // See crbug.com/924031 for detail.
+  if (extension_id == extension_misc::kPdfExtensionId)
+    blink::WebRuntimeFeatures::EnableHTMLImports(true);
+
   InitOriginPermissions(extension);
 
   UpdateActiveExtensions();
diff --git a/google_apis/drive/base_requests.cc b/google_apis/drive/base_requests.cc
index b855e656..4f8d2dc 100644
--- a/google_apis/drive/base_requests.cc
+++ b/google_apis/drive/base_requests.cc
@@ -176,8 +176,9 @@
 std::unique_ptr<base::Value> ParseJson(const std::string& json) {
   int error_code = -1;
   std::string error_message;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, &error_code, &error_message);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_PARSE_RFC, &error_code, &error_message);
 
   if (!value.get()) {
     std::string trimmed_json;
diff --git a/google_apis/drive/drive_api_requests_unittest.cc b/google_apis/drive/drive_api_requests_unittest.cc
index b5682e0e..1aa847c59 100644
--- a/google_apis/drive/drive_api_requests_unittest.cc
+++ b/google_apis/drive/drive_api_requests_unittest.cc
@@ -2022,13 +2022,13 @@
             http_request_.relative_url);
   EXPECT_EQ("application/json", http_request_.headers["Content-Type"]);
 
-  std::unique_ptr<base::Value> expected = base::JSONReader::Read(
+  std::unique_ptr<base::Value> expected = base::JSONReader::ReadDeprecated(
       "{\"additionalRoles\":[\"commenter\"], \"role\":\"reader\", "
       "\"type\":\"user\",\"value\":\"user@example.com\"}");
   ASSERT_TRUE(expected);
 
   std::unique_ptr<base::Value> result =
-      base::JSONReader::Read(http_request_.content);
+      base::JSONReader::ReadDeprecated(http_request_.content);
   EXPECT_TRUE(http_request_.has_content);
   EXPECT_EQ(*expected, *result);
 
@@ -2055,11 +2055,11 @@
             http_request_.relative_url);
   EXPECT_EQ("application/json", http_request_.headers["Content-Type"]);
 
-  expected = base::JSONReader::Read(
+  expected = base::JSONReader::ReadDeprecated(
       "{\"role\":\"writer\", \"type\":\"domain\",\"value\":\"example.com\"}");
   ASSERT_TRUE(expected);
 
-  result = base::JSONReader::Read(http_request_.content);
+  result = base::JSONReader::ReadDeprecated(http_request_.content);
   EXPECT_TRUE(http_request_.has_content);
   EXPECT_EQ(*expected, *result);
 }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index f6315f5..52da1db8 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -49,7 +49,7 @@
 
 std::unique_ptr<const GaiaAuthConsumer::ClientOAuthResult>
 ExtractOAuth2TokenPairResponse(const std::string& data) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value.get() || value->type() != base::Value::Type::DICTIONARY)
     return nullptr;
 
@@ -89,7 +89,7 @@
   if (response_code == net::HTTP_INTERNAL_SERVER_ERROR)
     return GaiaAuthConsumer::TokenRevocationStatus::kServerError;
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value.get() || value->type() != base::Value::Type::DICTIONARY)
     return GaiaAuthConsumer::TokenRevocationStatus::kUnknownError;
 
diff --git a/google_apis/gaia/gaia_auth_util.cc b/google_apis/gaia/gaia_auth_util.cc
index 75d69c8..f4ef70e 100644
--- a/google_apis/gaia/gaia_auth_util.cc
+++ b/google_apis/gaia/gaia_auth_util.cc
@@ -123,7 +123,7 @@
     signed_out_accounts->clear();
 
   // Parse returned data and make sure we have data.
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value)
     return false;
 
diff --git a/google_apis/gaia/gaia_oauth_client.cc b/google_apis/gaia/gaia_oauth_client.cc
index 3c8a451..410580a 100644
--- a/google_apis/gaia/gaia_oauth_client.cc
+++ b/google_apis/gaia/gaia_oauth_client.cc
@@ -452,7 +452,8 @@
   std::unique_ptr<base::DictionaryValue> response_dict;
   if (response_code == net::HTTP_OK && body) {
     std::string data = std::move(*body);
-    std::unique_ptr<base::Value> message_value = base::JSONReader::Read(data);
+    std::unique_ptr<base::Value> message_value =
+        base::JSONReader::ReadDeprecated(data);
     if (message_value.get() && message_value->is_dict()) {
       response_dict.reset(
           static_cast<base::DictionaryValue*>(message_value.release()));
diff --git a/google_apis/gaia/gaia_oauth_client_unittest.cc b/google_apis/gaia/gaia_oauth_client_unittest.cc
index 0d42eac..3583d24 100644
--- a/google_apis/gaia/gaia_oauth_client_unittest.cc
+++ b/google_apis/gaia/gaia_oauth_client_unittest.cc
@@ -428,7 +428,7 @@
   FlushNetwork();
 
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(kDummyFullUserInfoResult);
+      base::JSONReader::ReadDeprecated(kDummyFullUserInfoResult);
   DCHECK(value);
   ASSERT_TRUE(value->is_dict());
   base::DictionaryValue* expected_result;
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
index 036d84d..7e0e085 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
@@ -151,7 +151,7 @@
   if (!data)
     return nullptr;
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(*data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(*data);
   if (!value.get() || value->type() != base::Value::Type::DICTIONARY)
     value.reset();
 
diff --git a/google_apis/gaia/oauth2_id_token_decoder.cc b/google_apis/gaia/oauth2_id_token_decoder.cc
index bcc85d3..fb769425 100644
--- a/google_apis/gaia/oauth2_id_token_decoder.cc
+++ b/google_apis/gaia/oauth2_id_token_decoder.cc
@@ -42,7 +42,7 @@
     return nullptr;
   }
   std::unique_ptr<base::Value> decoded_payload =
-      base::JSONReader::Read(payload);
+      base::JSONReader::ReadDeprecated(payload);
   if (!decoded_payload.get() ||
       decoded_payload->type() != base::Value::Type::DICTIONARY) {
     VLOG(1) << "Invalid id_token: paylod is not a well-formed JSON";
diff --git a/google_apis/gaia/oauth2_mint_token_flow.cc b/google_apis/gaia/oauth2_mint_token_flow.cc
index a99a51b..1f689652 100644
--- a/google_apis/gaia/oauth2_mint_token_flow.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow.cc
@@ -70,7 +70,8 @@
   if (body)
     response_body = std::move(*body);
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response_body);
   base::DictionaryValue* response;
   if (!value.get() || !value->GetAsDictionary(&response)) {
     int http_response_code = -1;
@@ -191,7 +192,8 @@
   std::string response_body;
   if (body)
     response_body = std::move(*body);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response_body);
   base::DictionaryValue* dict = NULL;
   if (!value.get() || !value->GetAsDictionary(&dict)) {
     ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
diff --git a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
index c714b1a..e004277 100644
--- a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
@@ -175,7 +175,7 @@
 
   // Helper to parse the given string to DictionaryValue.
   static base::DictionaryValue* ParseJson(const std::string& str) {
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+    std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
     EXPECT_TRUE(value.get());
     EXPECT_EQ(base::Value::Type::DICTIONARY, value->type());
     return static_cast<base::DictionaryValue*>(value.release());
diff --git a/google_apis/gaia/oauth_multilogin_result.cc b/google_apis/gaia/oauth_multilogin_result.cc
index 6076fec6..e14ce465 100644
--- a/google_apis/gaia/oauth_multilogin_result.cc
+++ b/google_apis/gaia/oauth_multilogin_result.cc
@@ -162,7 +162,7 @@
 OAuthMultiloginResult::OAuthMultiloginResult(const std::string& raw_data) {
   base::StringPiece data = StripXSSICharacters(raw_data);
   std::unique_ptr<base::DictionaryValue> dictionary_value =
-      base::DictionaryValue::From(base::JSONReader::Read(data));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(data));
   if (!dictionary_value) {
     error_ = GoogleServiceAuthError(
         GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE);
diff --git a/google_apis/gaia/oauth_multilogin_result_unittest.cc b/google_apis/gaia/oauth_multilogin_result_unittest.cc
index 971cd6a8..bf1cdaff 100644
--- a/google_apis/gaia/oauth_multilogin_result_unittest.cc
+++ b/google_apis/gaia/oauth_multilogin_result_unittest.cc
@@ -75,7 +75,7 @@
       )";
 
   std::unique_ptr<base::DictionaryValue> dictionary_value =
-      base::DictionaryValue::From(base::JSONReader::Read(data));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(data));
   result.TryParseCookiesFromValue(dictionary_value.get());
 
   base::Time time_now = base::Time::Now();
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 3065b8b9..65ad9b35 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -245,6 +245,8 @@
 #define glBlitFramebufferCHROMIUM GLES2_GET_FUN(BlitFramebufferCHROMIUM)
 #define glRenderbufferStorageMultisampleCHROMIUM \
   GLES2_GET_FUN(RenderbufferStorageMultisampleCHROMIUM)
+#define glRenderbufferStorageMultisampleAdvancedAMD \
+  GLES2_GET_FUN(RenderbufferStorageMultisampleAdvancedAMD)
 #define glRenderbufferStorageMultisampleEXT \
   GLES2_GET_FUN(RenderbufferStorageMultisampleEXT)
 #define glFramebufferTexture2DMultisampleEXT \
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 7fe7fed..502c077c 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -3073,6 +3073,16 @@
     'pepper_name': 'RenderbufferStorageMultisampleEXT',
     'trace_level': 1,
   },
+  'RenderbufferStorageMultisampleAdvancedAMD': {
+    'cmd_comment':
+        '// GL_AMD_framebuffer_multisample_advanced\n',
+    'decoder_func': 'DoRenderbufferStorageMultisampleAdvancedAMD',
+    'gl_test_func': 'glRenderbufferStorageMultisampleAdvancedAMD',
+    'unit_test': False,
+    'extension': 'amd_framebuffer_multisample_advanced',
+    'extension_flag': 'amd_framebuffer_multisample_advanced',
+    'trace_level': 1,
+  },
   'RenderbufferStorageMultisampleEXT': {
     'cmd_comment':
         '// GL_EXT_multisampled_render_to_texture\n',
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index ca386c6..ff6b83d 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1142,6 +1142,16 @@
   gles2::GetGLContext()->RenderbufferStorageMultisampleCHROMIUM(
       target, samples, internalformat, width, height);
 }
+void GL_APIENTRY
+GLES2RenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                               GLsizei samples,
+                                               GLsizei storageSamples,
+                                               GLenum internalformat,
+                                               GLsizei width,
+                                               GLsizei height) {
+  gles2::GetGLContext()->RenderbufferStorageMultisampleAdvancedAMD(
+      target, samples, storageSamples, internalformat, width, height);
+}
 void GL_APIENTRY GLES2RenderbufferStorageMultisampleEXT(GLenum target,
                                                         GLsizei samples,
                                                         GLenum internalformat,
@@ -2848,6 +2858,11 @@
             glRenderbufferStorageMultisampleCHROMIUM),
     },
     {
+        "glRenderbufferStorageMultisampleAdvancedAMD",
+        reinterpret_cast<GLES2FunctionPointer>(
+            glRenderbufferStorageMultisampleAdvancedAMD),
+    },
+    {
         "glRenderbufferStorageMultisampleEXT",
         reinterpret_cast<GLES2FunctionPointer>(
             glRenderbufferStorageMultisampleEXT),
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index e0c0ca8..bcf11633 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -2270,6 +2270,19 @@
   }
 }
 
+void RenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                               GLsizei samples,
+                                               GLsizei storageSamples,
+                                               GLenum internalformat,
+                                               GLsizei width,
+                                               GLsizei height) {
+  gles2::cmds::RenderbufferStorageMultisampleAdvancedAMD* c =
+      GetCmdSpace<gles2::cmds::RenderbufferStorageMultisampleAdvancedAMD>();
+  if (c) {
+    c->Init(target, samples, storageSamples, internalformat, width, height);
+  }
+}
+
 void RenderbufferStorageMultisampleEXT(GLenum target,
                                        GLsizei samples,
                                        GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 60200cb..037d8f47 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -808,6 +808,13 @@
                                             GLsizei width,
                                             GLsizei height) override;
 
+void RenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                               GLsizei samples,
+                                               GLsizei storageSamples,
+                                               GLenum internalformat,
+                                               GLsizei width,
+                                               GLsizei height) override;
+
 void RenderbufferStorageMultisampleEXT(GLenum target,
                                        GLsizei samples,
                                        GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index bfbcd6b7..13b3676 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -2818,6 +2818,45 @@
   CheckGLError();
 }
 
+void GLES2Implementation::RenderbufferStorageMultisampleAdvancedAMD(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix()
+                     << "] glRenderbufferStorageMultisampleAdvancedAMD("
+                     << GLES2Util::GetStringRenderBufferTarget(target) << ", "
+                     << samples << ", " << storageSamples << ", "
+                     << GLES2Util::GetStringRenderBufferFormat(internalformat)
+                     << ", " << width << ", " << height << ")");
+  if (samples < 0) {
+    SetGLError(GL_INVALID_VALUE, "glRenderbufferStorageMultisampleAdvancedAMD",
+               "samples < 0");
+    return;
+  }
+  if (storageSamples < 0) {
+    SetGLError(GL_INVALID_VALUE, "glRenderbufferStorageMultisampleAdvancedAMD",
+               "storageSamples < 0");
+    return;
+  }
+  if (width < 0) {
+    SetGLError(GL_INVALID_VALUE, "glRenderbufferStorageMultisampleAdvancedAMD",
+               "width < 0");
+    return;
+  }
+  if (height < 0) {
+    SetGLError(GL_INVALID_VALUE, "glRenderbufferStorageMultisampleAdvancedAMD",
+               "height < 0");
+    return;
+  }
+  helper_->RenderbufferStorageMultisampleAdvancedAMD(
+      target, samples, storageSamples, internalformat, width, height);
+  CheckGLError();
+}
+
 void GLES2Implementation::RenderbufferStorageMultisampleEXT(
     GLenum target,
     GLsizei samples,
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 6ddbda8e..b14a3e39 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -2528,6 +2528,18 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, RenderbufferStorageMultisampleAdvancedAMD) {
+  struct Cmds {
+    cmds::RenderbufferStorageMultisampleAdvancedAMD cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_RENDERBUFFER, 2, 3, GL_RGBA4, 5, 6);
+
+  gl_->RenderbufferStorageMultisampleAdvancedAMD(GL_RENDERBUFFER, 2, 3,
+                                                 GL_RGBA4, 5, 6);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, RenderbufferStorageMultisampleEXT) {
   struct Cmds {
     cmds::RenderbufferStorageMultisampleEXT cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 9daed65b..f56e7d3d 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -596,6 +596,12 @@
                                                     GLenum internalformat,
                                                     GLsizei width,
                                                     GLsizei height) = 0;
+virtual void RenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                                       GLsizei samples,
+                                                       GLsizei storageSamples,
+                                                       GLenum internalformat,
+                                                       GLsizei width,
+                                                       GLsizei height) = 0;
 virtual void RenderbufferStorageMultisampleEXT(GLenum target,
                                                GLsizei samples,
                                                GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 35b35b1..38e915f 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -579,6 +579,12 @@
                                             GLenum internalformat,
                                             GLsizei width,
                                             GLsizei height) override;
+void RenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                               GLsizei samples,
+                                               GLsizei storageSamples,
+                                               GLenum internalformat,
+                                               GLsizei width,
+                                               GLsizei height) override;
 void RenderbufferStorageMultisampleEXT(GLenum target,
                                        GLsizei samples,
                                        GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index bb14269..a85eebf 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -779,6 +779,13 @@
     GLenum /* internalformat */,
     GLsizei /* width */,
     GLsizei /* height */) {}
+void GLES2InterfaceStub::RenderbufferStorageMultisampleAdvancedAMD(
+    GLenum /* target */,
+    GLsizei /* samples */,
+    GLsizei /* storageSamples */,
+    GLenum /* internalformat */,
+    GLsizei /* width */,
+    GLsizei /* height */) {}
 void GLES2InterfaceStub::RenderbufferStorageMultisampleEXT(
     GLenum /* target */,
     GLsizei /* samples */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 428d60e..709896a2 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -579,6 +579,12 @@
                                             GLenum internalformat,
                                             GLsizei width,
                                             GLsizei height) override;
+void RenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                               GLsizei samples,
+                                               GLsizei storageSamples,
+                                               GLenum internalformat,
+                                               GLsizei width,
+                                               GLsizei height) override;
 void RenderbufferStorageMultisampleEXT(GLenum target,
                                        GLsizei samples,
                                        GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index b14f102..3feb2c49 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1651,6 +1651,19 @@
                                               width, height);
 }
 
+void GLES2TraceImplementation::RenderbufferStorageMultisampleAdvancedAMD(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  TRACE_EVENT_BINARY_EFFICIENT0(
+      "gpu", "GLES2Trace::RenderbufferStorageMultisampleAdvancedAMD");
+  gl_->RenderbufferStorageMultisampleAdvancedAMD(
+      target, samples, storageSamples, internalformat, width, height);
+}
+
 void GLES2TraceImplementation::RenderbufferStorageMultisampleEXT(
     GLenum target,
     GLsizei samples,
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index 41836d0..7e10e4f 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -11349,6 +11349,81 @@
     offsetof(RenderbufferStorageMultisampleCHROMIUM, height) == 20,
     "offset of RenderbufferStorageMultisampleCHROMIUM height should be 20");
 
+// GL_AMD_framebuffer_multisample_advanced
+struct RenderbufferStorageMultisampleAdvancedAMD {
+  typedef RenderbufferStorageMultisampleAdvancedAMD ValueType;
+  static const CommandId kCmdId = kRenderbufferStorageMultisampleAdvancedAMD;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLsizei _samples,
+            GLsizei _storageSamples,
+            GLenum _internalformat,
+            GLsizei _width,
+            GLsizei _height) {
+    SetHeader();
+    target = _target;
+    samples = _samples;
+    storageSamples = _storageSamples;
+    internalformat = _internalformat;
+    width = _width;
+    height = _height;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLsizei _samples,
+            GLsizei _storageSamples,
+            GLenum _internalformat,
+            GLsizei _width,
+            GLsizei _height) {
+    static_cast<ValueType*>(cmd)->Init(_target, _samples, _storageSamples,
+                                       _internalformat, _width, _height);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t samples;
+  int32_t storageSamples;
+  uint32_t internalformat;
+  int32_t width;
+  int32_t height;
+};
+
+static_assert(sizeof(RenderbufferStorageMultisampleAdvancedAMD) == 28,
+              "size of RenderbufferStorageMultisampleAdvancedAMD should be 28");
+static_assert(
+    offsetof(RenderbufferStorageMultisampleAdvancedAMD, header) == 0,
+    "offset of RenderbufferStorageMultisampleAdvancedAMD header should be 0");
+static_assert(
+    offsetof(RenderbufferStorageMultisampleAdvancedAMD, target) == 4,
+    "offset of RenderbufferStorageMultisampleAdvancedAMD target should be 4");
+static_assert(
+    offsetof(RenderbufferStorageMultisampleAdvancedAMD, samples) == 8,
+    "offset of RenderbufferStorageMultisampleAdvancedAMD samples should be 8");
+static_assert(offsetof(RenderbufferStorageMultisampleAdvancedAMD,
+                       storageSamples) == 12,
+              "offset of RenderbufferStorageMultisampleAdvancedAMD "
+              "storageSamples should be 12");
+static_assert(offsetof(RenderbufferStorageMultisampleAdvancedAMD,
+                       internalformat) == 16,
+              "offset of RenderbufferStorageMultisampleAdvancedAMD "
+              "internalformat should be 16");
+static_assert(
+    offsetof(RenderbufferStorageMultisampleAdvancedAMD, width) == 20,
+    "offset of RenderbufferStorageMultisampleAdvancedAMD width should be 20");
+static_assert(
+    offsetof(RenderbufferStorageMultisampleAdvancedAMD, height) == 24,
+    "offset of RenderbufferStorageMultisampleAdvancedAMD height should be 24");
+
 // GL_EXT_multisampled_render_to_texture
 struct RenderbufferStorageMultisampleEXT {
   typedef RenderbufferStorageMultisampleEXT ValueType;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 23dbbe7..206f4da 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -3813,6 +3813,26 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, RenderbufferStorageMultisampleAdvancedAMD) {
+  cmds::RenderbufferStorageMultisampleAdvancedAMD& cmd =
+      *GetBufferAs<cmds::RenderbufferStorageMultisampleAdvancedAMD>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLsizei>(12),
+              static_cast<GLsizei>(13), static_cast<GLenum>(14),
+              static_cast<GLsizei>(15), static_cast<GLsizei>(16));
+  EXPECT_EQ(static_cast<uint32_t>(
+                cmds::RenderbufferStorageMultisampleAdvancedAMD::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLsizei>(12), cmd.samples);
+  EXPECT_EQ(static_cast<GLsizei>(13), cmd.storageSamples);
+  EXPECT_EQ(static_cast<GLenum>(14), cmd.internalformat);
+  EXPECT_EQ(static_cast<GLsizei>(15), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(16), cmd.height);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, RenderbufferStorageMultisampleEXT) {
   cmds::RenderbufferStorageMultisampleEXT& cmd =
       *GetBufferAs<cmds::RenderbufferStorageMultisampleEXT>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 1731b16d..b3dd9b3 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -241,126 +241,127 @@
   OP(WaitSync)                                             /* 482 */ \
   OP(BlitFramebufferCHROMIUM)                              /* 483 */ \
   OP(RenderbufferStorageMultisampleCHROMIUM)               /* 484 */ \
-  OP(RenderbufferStorageMultisampleEXT)                    /* 485 */ \
-  OP(FramebufferTexture2DMultisampleEXT)                   /* 486 */ \
-  OP(TexStorage2DEXT)                                      /* 487 */ \
-  OP(GenQueriesEXTImmediate)                               /* 488 */ \
-  OP(DeleteQueriesEXTImmediate)                            /* 489 */ \
-  OP(QueryCounterEXT)                                      /* 490 */ \
-  OP(BeginQueryEXT)                                        /* 491 */ \
-  OP(BeginTransformFeedback)                               /* 492 */ \
-  OP(EndQueryEXT)                                          /* 493 */ \
-  OP(EndTransformFeedback)                                 /* 494 */ \
-  OP(SetDisjointValueSyncCHROMIUM)                         /* 495 */ \
-  OP(InsertEventMarkerEXT)                                 /* 496 */ \
-  OP(PushGroupMarkerEXT)                                   /* 497 */ \
-  OP(PopGroupMarkerEXT)                                    /* 498 */ \
-  OP(GenVertexArraysOESImmediate)                          /* 499 */ \
-  OP(DeleteVertexArraysOESImmediate)                       /* 500 */ \
-  OP(IsVertexArrayOES)                                     /* 501 */ \
-  OP(BindVertexArrayOES)                                   /* 502 */ \
-  OP(FramebufferParameteri)                                /* 503 */ \
-  OP(BindImageTexture)                                     /* 504 */ \
-  OP(DispatchCompute)                                      /* 505 */ \
-  OP(GetProgramInterfaceiv)                                /* 506 */ \
-  OP(GetProgramResourceIndex)                              /* 507 */ \
-  OP(GetProgramResourceName)                               /* 508 */ \
-  OP(GetProgramResourceiv)                                 /* 509 */ \
-  OP(GetProgramResourceLocation)                           /* 510 */ \
-  OP(MemoryBarrierEXT)                                     /* 511 */ \
-  OP(MemoryBarrierByRegion)                                /* 512 */ \
-  OP(SwapBuffers)                                          /* 513 */ \
-  OP(GetMaxValueInBufferCHROMIUM)                          /* 514 */ \
-  OP(EnableFeatureCHROMIUM)                                /* 515 */ \
-  OP(MapBufferRange)                                       /* 516 */ \
-  OP(UnmapBuffer)                                          /* 517 */ \
-  OP(FlushMappedBufferRange)                               /* 518 */ \
-  OP(ResizeCHROMIUM)                                       /* 519 */ \
-  OP(GetRequestableExtensionsCHROMIUM)                     /* 520 */ \
-  OP(RequestExtensionCHROMIUM)                             /* 521 */ \
-  OP(GetProgramInfoCHROMIUM)                               /* 522 */ \
-  OP(GetUniformBlocksCHROMIUM)                             /* 523 */ \
-  OP(GetTransformFeedbackVaryingsCHROMIUM)                 /* 524 */ \
-  OP(GetUniformsES3CHROMIUM)                               /* 525 */ \
-  OP(DescheduleUntilFinishedCHROMIUM)                      /* 526 */ \
-  OP(GetTranslatedShaderSourceANGLE)                       /* 527 */ \
-  OP(PostSubBufferCHROMIUM)                                /* 528 */ \
-  OP(CopyTextureCHROMIUM)                                  /* 529 */ \
-  OP(CopySubTextureCHROMIUM)                               /* 530 */ \
-  OP(DrawArraysInstancedANGLE)                             /* 531 */ \
-  OP(DrawElementsInstancedANGLE)                           /* 532 */ \
-  OP(VertexAttribDivisorANGLE)                             /* 533 */ \
-  OP(ProduceTextureDirectCHROMIUMImmediate)                /* 534 */ \
-  OP(CreateAndConsumeTextureINTERNALImmediate)             /* 535 */ \
-  OP(BindUniformLocationCHROMIUMBucket)                    /* 536 */ \
-  OP(BindTexImage2DCHROMIUM)                               /* 537 */ \
-  OP(BindTexImage2DWithInternalformatCHROMIUM)             /* 538 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                            /* 539 */ \
-  OP(TraceBeginCHROMIUM)                                   /* 540 */ \
-  OP(TraceEndCHROMIUM)                                     /* 541 */ \
-  OP(DiscardFramebufferEXTImmediate)                       /* 542 */ \
-  OP(LoseContextCHROMIUM)                                  /* 543 */ \
-  OP(InsertFenceSyncCHROMIUM)                              /* 544 */ \
-  OP(UnpremultiplyAndDitherCopyCHROMIUM)                   /* 545 */ \
-  OP(DrawBuffersEXTImmediate)                              /* 546 */ \
-  OP(DiscardBackbufferCHROMIUM)                            /* 547 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)                         /* 548 */ \
-  OP(ScheduleCALayerSharedStateCHROMIUM)                   /* 549 */ \
-  OP(ScheduleCALayerCHROMIUM)                              /* 550 */ \
-  OP(ScheduleCALayerInUseQueryCHROMIUMImmediate)           /* 551 */ \
-  OP(CommitOverlayPlanesCHROMIUM)                          /* 552 */ \
-  OP(FlushDriverCachesCHROMIUM)                            /* 553 */ \
-  OP(ScheduleDCLayerCHROMIUM)                              /* 554 */ \
-  OP(SetActiveURLCHROMIUM)                                 /* 555 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)                         /* 556 */ \
-  OP(MatrixLoadIdentityCHROMIUM)                           /* 557 */ \
-  OP(GenPathsCHROMIUM)                                     /* 558 */ \
-  OP(DeletePathsCHROMIUM)                                  /* 559 */ \
-  OP(IsPathCHROMIUM)                                       /* 560 */ \
-  OP(PathCommandsCHROMIUM)                                 /* 561 */ \
-  OP(PathParameterfCHROMIUM)                               /* 562 */ \
-  OP(PathParameteriCHROMIUM)                               /* 563 */ \
-  OP(PathStencilFuncCHROMIUM)                              /* 564 */ \
-  OP(StencilFillPathCHROMIUM)                              /* 565 */ \
-  OP(StencilStrokePathCHROMIUM)                            /* 566 */ \
-  OP(CoverFillPathCHROMIUM)                                /* 567 */ \
-  OP(CoverStrokePathCHROMIUM)                              /* 568 */ \
-  OP(StencilThenCoverFillPathCHROMIUM)                     /* 569 */ \
-  OP(StencilThenCoverStrokePathCHROMIUM)                   /* 570 */ \
-  OP(StencilFillPathInstancedCHROMIUM)                     /* 571 */ \
-  OP(StencilStrokePathInstancedCHROMIUM)                   /* 572 */ \
-  OP(CoverFillPathInstancedCHROMIUM)                       /* 573 */ \
-  OP(CoverStrokePathInstancedCHROMIUM)                     /* 574 */ \
-  OP(StencilThenCoverFillPathInstancedCHROMIUM)            /* 575 */ \
-  OP(StencilThenCoverStrokePathInstancedCHROMIUM)          /* 576 */ \
-  OP(BindFragmentInputLocationCHROMIUMBucket)              /* 577 */ \
-  OP(ProgramPathFragmentInputGenCHROMIUM)                  /* 578 */ \
-  OP(CoverageModulationCHROMIUM)                           /* 579 */ \
-  OP(BlendBarrierKHR)                                      /* 580 */ \
-  OP(ApplyScreenSpaceAntialiasingCHROMIUM)                 /* 581 */ \
-  OP(BindFragDataLocationIndexedEXTBucket)                 /* 582 */ \
-  OP(BindFragDataLocationEXTBucket)                        /* 583 */ \
-  OP(GetFragDataIndexEXT)                                  /* 584 */ \
-  OP(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate) /* 585 */ \
-  OP(OverlayPromotionHintCHROMIUM)                         /* 586 */ \
-  OP(SwapBuffersWithBoundsCHROMIUMImmediate)               /* 587 */ \
-  OP(SetDrawRectangleCHROMIUM)                             /* 588 */ \
-  OP(SetEnableDCLayersCHROMIUM)                            /* 589 */ \
-  OP(InitializeDiscardableTextureCHROMIUM)                 /* 590 */ \
-  OP(UnlockDiscardableTextureCHROMIUM)                     /* 591 */ \
-  OP(LockDiscardableTextureCHROMIUM)                       /* 592 */ \
-  OP(TexStorage2DImageCHROMIUM)                            /* 593 */ \
-  OP(SetColorSpaceMetadataCHROMIUM)                        /* 594 */ \
-  OP(WindowRectanglesEXTImmediate)                         /* 595 */ \
-  OP(CreateGpuFenceINTERNAL)                               /* 596 */ \
-  OP(WaitGpuFenceCHROMIUM)                                 /* 597 */ \
-  OP(DestroyGpuFenceCHROMIUM)                              /* 598 */ \
-  OP(SetReadbackBufferShadowAllocationINTERNAL)            /* 599 */ \
-  OP(FramebufferTextureMultiviewLayeredANGLE)              /* 600 */ \
-  OP(MaxShaderCompilerThreadsKHR)                          /* 601 */ \
-  OP(CreateAndTexStorage2DSharedImageINTERNALImmediate)    /* 602 */ \
-  OP(BeginSharedImageAccessDirectCHROMIUM)                 /* 603 */ \
-  OP(EndSharedImageAccessDirectCHROMIUM)                   /* 604 */
+  OP(RenderbufferStorageMultisampleAdvancedAMD)            /* 485 */ \
+  OP(RenderbufferStorageMultisampleEXT)                    /* 486 */ \
+  OP(FramebufferTexture2DMultisampleEXT)                   /* 487 */ \
+  OP(TexStorage2DEXT)                                      /* 488 */ \
+  OP(GenQueriesEXTImmediate)                               /* 489 */ \
+  OP(DeleteQueriesEXTImmediate)                            /* 490 */ \
+  OP(QueryCounterEXT)                                      /* 491 */ \
+  OP(BeginQueryEXT)                                        /* 492 */ \
+  OP(BeginTransformFeedback)                               /* 493 */ \
+  OP(EndQueryEXT)                                          /* 494 */ \
+  OP(EndTransformFeedback)                                 /* 495 */ \
+  OP(SetDisjointValueSyncCHROMIUM)                         /* 496 */ \
+  OP(InsertEventMarkerEXT)                                 /* 497 */ \
+  OP(PushGroupMarkerEXT)                                   /* 498 */ \
+  OP(PopGroupMarkerEXT)                                    /* 499 */ \
+  OP(GenVertexArraysOESImmediate)                          /* 500 */ \
+  OP(DeleteVertexArraysOESImmediate)                       /* 501 */ \
+  OP(IsVertexArrayOES)                                     /* 502 */ \
+  OP(BindVertexArrayOES)                                   /* 503 */ \
+  OP(FramebufferParameteri)                                /* 504 */ \
+  OP(BindImageTexture)                                     /* 505 */ \
+  OP(DispatchCompute)                                      /* 506 */ \
+  OP(GetProgramInterfaceiv)                                /* 507 */ \
+  OP(GetProgramResourceIndex)                              /* 508 */ \
+  OP(GetProgramResourceName)                               /* 509 */ \
+  OP(GetProgramResourceiv)                                 /* 510 */ \
+  OP(GetProgramResourceLocation)                           /* 511 */ \
+  OP(MemoryBarrierEXT)                                     /* 512 */ \
+  OP(MemoryBarrierByRegion)                                /* 513 */ \
+  OP(SwapBuffers)                                          /* 514 */ \
+  OP(GetMaxValueInBufferCHROMIUM)                          /* 515 */ \
+  OP(EnableFeatureCHROMIUM)                                /* 516 */ \
+  OP(MapBufferRange)                                       /* 517 */ \
+  OP(UnmapBuffer)                                          /* 518 */ \
+  OP(FlushMappedBufferRange)                               /* 519 */ \
+  OP(ResizeCHROMIUM)                                       /* 520 */ \
+  OP(GetRequestableExtensionsCHROMIUM)                     /* 521 */ \
+  OP(RequestExtensionCHROMIUM)                             /* 522 */ \
+  OP(GetProgramInfoCHROMIUM)                               /* 523 */ \
+  OP(GetUniformBlocksCHROMIUM)                             /* 524 */ \
+  OP(GetTransformFeedbackVaryingsCHROMIUM)                 /* 525 */ \
+  OP(GetUniformsES3CHROMIUM)                               /* 526 */ \
+  OP(DescheduleUntilFinishedCHROMIUM)                      /* 527 */ \
+  OP(GetTranslatedShaderSourceANGLE)                       /* 528 */ \
+  OP(PostSubBufferCHROMIUM)                                /* 529 */ \
+  OP(CopyTextureCHROMIUM)                                  /* 530 */ \
+  OP(CopySubTextureCHROMIUM)                               /* 531 */ \
+  OP(DrawArraysInstancedANGLE)                             /* 532 */ \
+  OP(DrawElementsInstancedANGLE)                           /* 533 */ \
+  OP(VertexAttribDivisorANGLE)                             /* 534 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate)                /* 535 */ \
+  OP(CreateAndConsumeTextureINTERNALImmediate)             /* 536 */ \
+  OP(BindUniformLocationCHROMIUMBucket)                    /* 537 */ \
+  OP(BindTexImage2DCHROMIUM)                               /* 538 */ \
+  OP(BindTexImage2DWithInternalformatCHROMIUM)             /* 539 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                            /* 540 */ \
+  OP(TraceBeginCHROMIUM)                                   /* 541 */ \
+  OP(TraceEndCHROMIUM)                                     /* 542 */ \
+  OP(DiscardFramebufferEXTImmediate)                       /* 543 */ \
+  OP(LoseContextCHROMIUM)                                  /* 544 */ \
+  OP(InsertFenceSyncCHROMIUM)                              /* 545 */ \
+  OP(UnpremultiplyAndDitherCopyCHROMIUM)                   /* 546 */ \
+  OP(DrawBuffersEXTImmediate)                              /* 547 */ \
+  OP(DiscardBackbufferCHROMIUM)                            /* 548 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)                         /* 549 */ \
+  OP(ScheduleCALayerSharedStateCHROMIUM)                   /* 550 */ \
+  OP(ScheduleCALayerCHROMIUM)                              /* 551 */ \
+  OP(ScheduleCALayerInUseQueryCHROMIUMImmediate)           /* 552 */ \
+  OP(CommitOverlayPlanesCHROMIUM)                          /* 553 */ \
+  OP(FlushDriverCachesCHROMIUM)                            /* 554 */ \
+  OP(ScheduleDCLayerCHROMIUM)                              /* 555 */ \
+  OP(SetActiveURLCHROMIUM)                                 /* 556 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)                         /* 557 */ \
+  OP(MatrixLoadIdentityCHROMIUM)                           /* 558 */ \
+  OP(GenPathsCHROMIUM)                                     /* 559 */ \
+  OP(DeletePathsCHROMIUM)                                  /* 560 */ \
+  OP(IsPathCHROMIUM)                                       /* 561 */ \
+  OP(PathCommandsCHROMIUM)                                 /* 562 */ \
+  OP(PathParameterfCHROMIUM)                               /* 563 */ \
+  OP(PathParameteriCHROMIUM)                               /* 564 */ \
+  OP(PathStencilFuncCHROMIUM)                              /* 565 */ \
+  OP(StencilFillPathCHROMIUM)                              /* 566 */ \
+  OP(StencilStrokePathCHROMIUM)                            /* 567 */ \
+  OP(CoverFillPathCHROMIUM)                                /* 568 */ \
+  OP(CoverStrokePathCHROMIUM)                              /* 569 */ \
+  OP(StencilThenCoverFillPathCHROMIUM)                     /* 570 */ \
+  OP(StencilThenCoverStrokePathCHROMIUM)                   /* 571 */ \
+  OP(StencilFillPathInstancedCHROMIUM)                     /* 572 */ \
+  OP(StencilStrokePathInstancedCHROMIUM)                   /* 573 */ \
+  OP(CoverFillPathInstancedCHROMIUM)                       /* 574 */ \
+  OP(CoverStrokePathInstancedCHROMIUM)                     /* 575 */ \
+  OP(StencilThenCoverFillPathInstancedCHROMIUM)            /* 576 */ \
+  OP(StencilThenCoverStrokePathInstancedCHROMIUM)          /* 577 */ \
+  OP(BindFragmentInputLocationCHROMIUMBucket)              /* 578 */ \
+  OP(ProgramPathFragmentInputGenCHROMIUM)                  /* 579 */ \
+  OP(CoverageModulationCHROMIUM)                           /* 580 */ \
+  OP(BlendBarrierKHR)                                      /* 581 */ \
+  OP(ApplyScreenSpaceAntialiasingCHROMIUM)                 /* 582 */ \
+  OP(BindFragDataLocationIndexedEXTBucket)                 /* 583 */ \
+  OP(BindFragDataLocationEXTBucket)                        /* 584 */ \
+  OP(GetFragDataIndexEXT)                                  /* 585 */ \
+  OP(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate) /* 586 */ \
+  OP(OverlayPromotionHintCHROMIUM)                         /* 587 */ \
+  OP(SwapBuffersWithBoundsCHROMIUMImmediate)               /* 588 */ \
+  OP(SetDrawRectangleCHROMIUM)                             /* 589 */ \
+  OP(SetEnableDCLayersCHROMIUM)                            /* 590 */ \
+  OP(InitializeDiscardableTextureCHROMIUM)                 /* 591 */ \
+  OP(UnlockDiscardableTextureCHROMIUM)                     /* 592 */ \
+  OP(LockDiscardableTextureCHROMIUM)                       /* 593 */ \
+  OP(TexStorage2DImageCHROMIUM)                            /* 594 */ \
+  OP(SetColorSpaceMetadataCHROMIUM)                        /* 595 */ \
+  OP(WindowRectanglesEXTImmediate)                         /* 596 */ \
+  OP(CreateGpuFenceINTERNAL)                               /* 597 */ \
+  OP(WaitGpuFenceCHROMIUM)                                 /* 598 */ \
+  OP(DestroyGpuFenceCHROMIUM)                              /* 599 */ \
+  OP(SetReadbackBufferShadowAllocationINTERNAL)            /* 600 */ \
+  OP(FramebufferTextureMultiviewLayeredANGLE)              /* 601 */ \
+  OP(MaxShaderCompilerThreadsKHR)                          /* 602 */ \
+  OP(CreateAndTexStorage2DSharedImageINTERNALImmediate)    /* 603 */ \
+  OP(BeginSharedImageAccessDirectCHROMIUM)                 /* 604 */ \
+  OP(EndSharedImageAccessDirectCHROMIUM)                   /* 605 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/gles2_cmd_buffer_functions.txt b/gpu/command_buffer/gles2_cmd_buffer_functions.txt
index a022738..cdb6f88 100644
--- a/gpu/command_buffer/gles2_cmd_buffer_functions.txt
+++ b/gpu/command_buffer/gles2_cmd_buffer_functions.txt
@@ -242,6 +242,7 @@
 GL_APICALL void         GL_APIENTRY glWaitSync (GLsync sync, GLbitfieldSyncFlushFlags flags, GLuint64 timeout);
 GL_APICALL void         GL_APIENTRY glBlitFramebufferCHROMIUM (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenumBlitFilter filter);
 GL_APICALL void         GL_APIENTRY glRenderbufferStorageMultisampleCHROMIUM (GLenumRenderBufferTarget target, GLsizei samples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
+GL_APICALL void         GL_APIENTRY glRenderbufferStorageMultisampleAdvancedAMD (GLenumRenderBufferTarget target, GLsizei samples, GLsizei storageSamples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
 GL_APICALL void         GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenumRenderBufferTarget target, GLsizei samples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
 GL_APICALL void         GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenumFramebufferTarget target, GLenumAttachment attachment, GLenumTextureTarget textarget, GLidTexture texture, GLint level, GLsizei samples);
 GL_APICALL void         GL_APIENTRY glTexStorage2DEXT (GLenumTextureBindTarget target, GLsizei levels, GLenumTextureInternalFormatStorage internalFormat, GLsizei width, GLsizei height);
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index d994024..ec8aceae 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -1566,6 +1566,11 @@
   if (gfx::HasExtension(extensions, "GL_NV_internalformat_sample_query")) {
     feature_flags_.nv_internalformat_sample_query = true;
   }
+
+  if (gfx::HasExtension(extensions,
+                        "GL_AMD_framebuffer_multisample_advanced")) {
+    feature_flags_.amd_framebuffer_multisample_advanced = true;
+  }
 }
 
 void FeatureInfo::InitializeFloatAndHalfFloatFeatures(
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 2435708..44a4060 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -144,6 +144,7 @@
     bool webgl_multi_draw = false;
     bool webgl_multi_draw_instanced = false;
     bool nv_internalformat_sample_query = false;
+    bool amd_framebuffer_multisample_advanced = false;
   };
 
   FeatureInfo();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index e3f5d83c..3392288 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -792,6 +792,13 @@
                                             GLsizei width,
                                             GLsizei height,
                                             ForcedMultisampleMode mode);
+  void RenderbufferStorageMultisampleHelperAMD(GLenum target,
+                                               GLsizei samples,
+                                               GLsizei storageSamples,
+                                               GLenum internal_format,
+                                               GLsizei width,
+                                               GLsizei height,
+                                               ForcedMultisampleMode mode);
   bool RegenerateRenderbufferIfNeeded(Renderbuffer* renderbuffer);
 
   PathManager* path_manager() { return group_->path_manager(); }
@@ -1930,6 +1937,14 @@
       GLenum target, GLsizei samples, GLenum internalformat,
       GLsizei width, GLsizei height);
 
+  // Handler for glRenderbufferStorageMultisampleAdvancedAMD.
+  void DoRenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                                   GLsizei samples,
+                                                   GLsizei storageSamples,
+                                                   GLenum internalformat,
+                                                   GLsizei width,
+                                                   GLsizei height);
+
   // Handler for glRenderbufferStorageMultisampleEXT
   // (multisampled_render_to_texture).
   void DoRenderbufferStorageMultisampleEXT(
@@ -1950,6 +1965,12 @@
                                               GLsizei width,
                                               GLsizei height);
 
+  // validation for multisample AMD extension.
+  bool ValidateRenderbufferStorageMultisampleAMD(GLsizei samples,
+                                                 GLsizei storageSamples,
+                                                 GLenum internalformat,
+                                                 GLsizei width,
+                                                 GLsizei height);
   // Verifies that the currently bound multisample renderbuffer is valid
   // Very slow! Only done on platforms with driver bugs that return invalid
   // buffers under memory pressure
@@ -9271,6 +9292,18 @@
   }
 }
 
+void GLES2DecoderImpl::RenderbufferStorageMultisampleHelperAMD(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internal_format,
+    GLsizei width,
+    GLsizei height,
+    ForcedMultisampleMode mode) {
+  api()->glRenderbufferStorageMultisampleAdvancedAMDFn(
+      target, samples, storageSamples, internal_format, width, height);
+}
+
 bool GLES2DecoderImpl::RegenerateRenderbufferIfNeeded(
     Renderbuffer* renderbuffer) {
   if (!renderbuffer->RegenerateAndBindBackingObjectIfNeeded(workarounds())) {
@@ -9319,6 +9352,36 @@
   return true;
 }
 
+bool GLES2DecoderImpl::ValidateRenderbufferStorageMultisampleAMD(
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  if (samples > renderbuffer_manager()->max_samples()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRenderbufferStorageMultisample",
+                       "samples too large");
+    return false;
+  }
+
+  if (width > renderbuffer_manager()->max_renderbuffer_size() ||
+      height > renderbuffer_manager()->max_renderbuffer_size()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRenderbufferStorageMultisample",
+                       "dimensions too large");
+    return false;
+  }
+
+  uint32_t estimated_size = 0;
+  if (!renderbuffer_manager()->ComputeEstimatedRenderbufferSize(
+          width, height, samples, internalformat, &estimated_size)) {
+    LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glRenderbufferStorageMultisample",
+                       "dimensions too large");
+    return false;
+  }
+
+  return true;
+}
+
 void GLES2DecoderImpl::DoRenderbufferStorageMultisampleCHROMIUM(
     GLenum target, GLsizei samples, GLenum internalformat,
     GLsizei width, GLsizei height) {
@@ -9360,6 +9423,51 @@
   }
 }
 
+void GLES2DecoderImpl::DoRenderbufferStorageMultisampleAdvancedAMD(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  Renderbuffer* renderbuffer = GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+  if (!renderbuffer) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+                       "glRenderbufferStorageMultisampleAdvancedAMD",
+                       "no renderbuffer bound");
+    return;
+  }
+
+  if (!ValidateRenderbufferStorageMultisampleAMD(
+          samples, storageSamples, internalformat, width, height)) {
+    return;
+  }
+
+  GLenum impl_format =
+      renderbuffer_manager()->InternalRenderbufferFormatToImplFormat(
+          internalformat);
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(
+      "glRenderbufferStorageMultisampleAdvancedAMD");
+  RenderbufferStorageMultisampleHelperAMD(
+      target, samples, storageSamples, impl_format, width, height, kDoNotForce);
+  GLenum error =
+      LOCAL_PEEK_GL_ERROR("glRenderbufferStorageMultisampleAdvancedAMD");
+  if (error == GL_NO_ERROR) {
+    if (workarounds().validate_multisample_buffer_allocation) {
+      if (!VerifyMultisampleRenderbufferIntegrity(renderbuffer->service_id(),
+                                                  impl_format)) {
+        LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY,
+                           "glRenderbufferStorageMultisampleAdvancedAMD",
+                           "out of memory");
+        return;
+      }
+    }
+
+    renderbuffer_manager()->SetInfoAndInvalidate(renderbuffer, samples,
+                                                 internalformat, width, height);
+  }
+}
+
 // This is the handler for multisampled_render_to_texture extensions.
 void GLES2DecoderImpl::DoRenderbufferStorageMultisampleEXT(
     GLenum target, GLsizei samples, GLenum internalformat,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 8ae2168..a3d5b92 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -4313,6 +4313,62 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleRenderbufferStorageMultisampleAdvancedAMD(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile gles2::cmds::RenderbufferStorageMultisampleAdvancedAMD& c =
+      *static_cast<const volatile gles2::cmds::
+                       RenderbufferStorageMultisampleAdvancedAMD*>(cmd_data);
+  if (!features().amd_framebuffer_multisample_advanced) {
+    return error::kUnknownCommand;
+  }
+
+  GLenum target = static_cast<GLenum>(c.target);
+  GLsizei samples = static_cast<GLsizei>(c.samples);
+  GLsizei storageSamples = static_cast<GLsizei>(c.storageSamples);
+  GLenum internalformat = static_cast<GLenum>(c.internalformat);
+  GLsizei width = static_cast<GLsizei>(c.width);
+  GLsizei height = static_cast<GLsizei>(c.height);
+  if (!validators_->render_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM(
+        "glRenderbufferStorageMultisampleAdvancedAMD", target, "target");
+    return error::kNoError;
+  }
+  if (samples < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,
+                       "glRenderbufferStorageMultisampleAdvancedAMD",
+                       "samples < 0");
+    return error::kNoError;
+  }
+  if (storageSamples < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,
+                       "glRenderbufferStorageMultisampleAdvancedAMD",
+                       "storageSamples < 0");
+    return error::kNoError;
+  }
+  if (!validators_->render_buffer_format.IsValid(internalformat)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM(
+        "glRenderbufferStorageMultisampleAdvancedAMD", internalformat,
+        "internalformat");
+    return error::kNoError;
+  }
+  if (width < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,
+                       "glRenderbufferStorageMultisampleAdvancedAMD",
+                       "width < 0");
+    return error::kNoError;
+  }
+  if (height < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,
+                       "glRenderbufferStorageMultisampleAdvancedAMD",
+                       "height < 0");
+    return error::kNoError;
+  }
+  DoRenderbufferStorageMultisampleAdvancedAMD(target, samples, storageSamples,
+                                              internalformat, width, height);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleRenderbufferStorageMultisampleEXT(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
index 781d677..27f3ce31 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
@@ -736,6 +736,12 @@
                                                       GLenum internalformat,
                                                       GLsizei width,
                                                       GLsizei height);
+error::Error DoRenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                                         GLsizei samples,
+                                                         GLsizei storageSamples,
+                                                         GLenum internalformat,
+                                                         GLsizei width,
+                                                         GLsizei height);
 error::Error DoRenderbufferStorageMultisampleEXT(GLenum target,
                                                  GLsizei samples,
                                                  GLenum internalformat,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index bab7a390..7e937e0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -3182,6 +3182,20 @@
   return error::kNoError;
 }
 
+error::Error
+GLES2DecoderPassthroughImpl::DoRenderbufferStorageMultisampleAdvancedAMD(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  DCHECK(feature_info_->feature_flags().amd_framebuffer_multisample_advanced);
+  api()->glRenderbufferStorageMultisampleAdvancedAMDFn(
+      target, samples, storageSamples, internalformat, width, height);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderPassthroughImpl::DoRenderbufferStorageMultisampleEXT(
     GLenum target,
     GLsizei samples,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 2c46446..fbc06f55 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -3701,6 +3701,31 @@
 }
 
 error::Error
+GLES2DecoderPassthroughImpl::HandleRenderbufferStorageMultisampleAdvancedAMD(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile gles2::cmds::RenderbufferStorageMultisampleAdvancedAMD& c =
+      *static_cast<const volatile gles2::cmds::
+                       RenderbufferStorageMultisampleAdvancedAMD*>(cmd_data);
+  if (!features().amd_framebuffer_multisample_advanced) {
+    return error::kUnknownCommand;
+  }
+
+  GLenum target = static_cast<GLenum>(c.target);
+  GLsizei samples = static_cast<GLsizei>(c.samples);
+  GLsizei storageSamples = static_cast<GLsizei>(c.storageSamples);
+  GLenum internalformat = static_cast<GLenum>(c.internalformat);
+  GLsizei width = static_cast<GLsizei>(c.width);
+  GLsizei height = static_cast<GLsizei>(c.height);
+  error::Error error = DoRenderbufferStorageMultisampleAdvancedAMD(
+      target, samples, storageSamples, internalformat, width, height);
+  if (error != error::kNoError) {
+    return error;
+  }
+  return error::kNoError;
+}
+
+error::Error
 GLES2DecoderPassthroughImpl::HandleRenderbufferStorageMultisampleEXT(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index 7b4ccdb..3304a16 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -111,6 +111,7 @@
     options.fGlyphCacheTextureMaximumBytes = glyph_cache_max_texture_bytes_;
     options.fPersistentCache = cache;
     options.fAvoidStencilBuffers = workarounds.avoid_stencil_buffers;
+    options.fDisallowGLSLBinaryCaching = workarounds.disable_program_disk_cache;
     owned_gr_context_ = GrContext::MakeGL(std::move(interface), options);
     gr_context_ = owned_gr_context_.get();
     if (!gr_context_) {
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index 3d34489..38abaf01 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -50,6 +50,47 @@
   enumerator->EndVideoEncodeAcceleratorSupportedProfile();
 }
 
+const char* ImageDecodeAcceleratorTypeToString(
+    gpu::ImageDecodeAcceleratorType type) {
+  switch (type) {
+    case gpu::ImageDecodeAcceleratorType::kJpeg:
+      return "JPEG";
+    case gpu::ImageDecodeAcceleratorType::kUnknown:
+      return "Unknown";
+  }
+}
+
+const char* ImageDecodeAcceleratorSubsamplingToString(
+    gpu::ImageDecodeAcceleratorSubsampling subsampling) {
+  switch (subsampling) {
+    case gpu::ImageDecodeAcceleratorSubsampling::k420:
+      return "4:2:0";
+    case gpu::ImageDecodeAcceleratorSubsampling::k422:
+      return "4:2:2";
+  }
+}
+
+void EnumerateImageDecodeAcceleratorSupportedProfile(
+    const gpu::ImageDecodeAcceleratorSupportedProfile& profile,
+    gpu::GPUInfo::Enumerator* enumerator) {
+  enumerator->BeginImageDecodeAcceleratorSupportedProfile();
+  enumerator->AddString("imageType",
+                        ImageDecodeAcceleratorTypeToString(profile.image_type));
+  enumerator->AddString("minEncodedDimensions",
+                        profile.min_encoded_dimensions.ToString());
+  enumerator->AddString("maxEncodedDimensions",
+                        profile.max_encoded_dimensions.ToString());
+  std::string subsamplings;
+  for (size_t i = 0; i < profile.subsamplings.size(); i++) {
+    if (i > 0)
+      subsamplings += ", ";
+    subsamplings +=
+        ImageDecodeAcceleratorSubsamplingToString(profile.subsamplings[i]);
+  }
+  enumerator->AddString("subsamplings", subsamplings);
+  enumerator->EndImageDecodeAcceleratorSupportedProfile();
+}
+
 #if defined(OS_WIN)
 void EnumerateOverlayCapability(const gpu::OverlayCapability& cap,
                                 gpu::GPUInfo::Enumerator* enumerator) {
@@ -104,6 +145,24 @@
 VideoDecodeAcceleratorCapabilities::~VideoDecodeAcceleratorCapabilities() =
     default;
 
+ImageDecodeAcceleratorSupportedProfile::ImageDecodeAcceleratorSupportedProfile()
+    : image_type(ImageDecodeAcceleratorType::kUnknown) {}
+
+ImageDecodeAcceleratorSupportedProfile::ImageDecodeAcceleratorSupportedProfile(
+    const ImageDecodeAcceleratorSupportedProfile& other) = default;
+
+ImageDecodeAcceleratorSupportedProfile::ImageDecodeAcceleratorSupportedProfile(
+    ImageDecodeAcceleratorSupportedProfile&& other) = default;
+
+ImageDecodeAcceleratorSupportedProfile::
+    ~ImageDecodeAcceleratorSupportedProfile() = default;
+
+ImageDecodeAcceleratorSupportedProfile& ImageDecodeAcceleratorSupportedProfile::
+operator=(const ImageDecodeAcceleratorSupportedProfile& other) = default;
+
+ImageDecodeAcceleratorSupportedProfile& ImageDecodeAcceleratorSupportedProfile::
+operator=(ImageDecodeAcceleratorSupportedProfile&& other) = default;
+
 GPUInfo::GPUDevice::GPUDevice()
     : vendor_id(0),
       device_id(0),
@@ -201,10 +260,15 @@
     VideoEncodeAcceleratorSupportedProfiles
         video_encode_accelerator_supported_profiles;
     bool jpeg_decode_accelerator_supported;
+
+    ImageDecodeAcceleratorSupportedProfiles
+        image_decode_accelerator_supported_profiles;
+
 #if defined(USE_X11)
     VisualID system_visual;
     VisualID rgba_visual;
 #endif
+
     bool oop_rasterization_supported;
   };
 
@@ -265,6 +329,8 @@
     EnumerateVideoEncodeAcceleratorSupportedProfile(profile, enumerator);
   enumerator->AddBool("jpegDecodeAcceleratorSupported",
       jpeg_decode_accelerator_supported);
+  for (const auto& profile : image_decode_accelerator_supported_profiles)
+    EnumerateImageDecodeAcceleratorSupportedProfile(profile, enumerator);
 #if defined(USE_X11)
   enumerator->AddInt64("systemVisual", system_visual);
   enumerator->AddInt64("rgbaVisual", rgba_visual);
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 30c56560..88420f3 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -113,6 +113,45 @@
 using VideoEncodeAcceleratorSupportedProfiles =
     std::vector<VideoEncodeAcceleratorSupportedProfile>;
 
+enum class ImageDecodeAcceleratorType {
+  kJpeg = 0,
+  kUnknown = 1,
+  kMaxValue = kUnknown,
+};
+
+enum class ImageDecodeAcceleratorSubsampling {
+  k420 = 0,
+  k422 = 1,
+  kMaxValue = k422,
+};
+
+// Specification of an image decoding profile supported by a hardware decoder.
+struct GPU_EXPORT ImageDecodeAcceleratorSupportedProfile {
+  ImageDecodeAcceleratorSupportedProfile();
+  ImageDecodeAcceleratorSupportedProfile(
+      const ImageDecodeAcceleratorSupportedProfile& other);
+  ImageDecodeAcceleratorSupportedProfile(
+      ImageDecodeAcceleratorSupportedProfile&& other);
+  ~ImageDecodeAcceleratorSupportedProfile();
+  ImageDecodeAcceleratorSupportedProfile& operator=(
+      const ImageDecodeAcceleratorSupportedProfile& other);
+  ImageDecodeAcceleratorSupportedProfile& operator=(
+      ImageDecodeAcceleratorSupportedProfile&& other);
+
+  // Fields common to all image types.
+  // Type of image to which this profile applies, e.g., JPEG.
+  ImageDecodeAcceleratorType image_type;
+  // Minimum and maximum supported pixel dimensions of the encoded image.
+  gfx::Size min_encoded_dimensions;
+  gfx::Size max_encoded_dimensions;
+
+  // Fields specific to |image_type| == kJpeg.
+  // The supported chroma subsampling formats, e.g. 4:2:0.
+  std::vector<ImageDecodeAcceleratorSubsampling> subsamplings;
+};
+using ImageDecodeAcceleratorSupportedProfiles =
+    std::vector<ImageDecodeAcceleratorSupportedProfile>;
+
 #if defined(OS_WIN)
 // Common overlay formats that we're interested in. Must match the OverlayFormat
 // enum in //tools/metrics/histograms/enums.xml. Mapped to corresponding DXGI
@@ -294,6 +333,9 @@
       video_encode_accelerator_supported_profiles;
   bool jpeg_decode_accelerator_supported;
 
+  ImageDecodeAcceleratorSupportedProfiles
+      image_decode_accelerator_supported_profiles;
+
 #if defined(USE_X11)
   VisualID system_visual;
   VisualID rgba_visual;
@@ -335,6 +377,11 @@
     virtual void BeginVideoEncodeAcceleratorSupportedProfile() = 0;
     virtual void EndVideoEncodeAcceleratorSupportedProfile() = 0;
 
+    // Markers indicating that an ImageDecodeAcceleratorSupportedProfile is
+    // being described.
+    virtual void BeginImageDecodeAcceleratorSupportedProfile() = 0;
+    virtual void EndImageDecodeAcceleratorSupportedProfile() = 0;
+
     // Markers indicating that "auxiliary" attributes of the GPUInfo
     // (according to the DevTools protocol) are being described.
     virtual void BeginAuxAttributes() = 0;
diff --git a/gpu/ipc/common/gpu_info.mojom b/gpu/ipc/common/gpu_info.mojom
index 654b3d1..fb42f07 100644
--- a/gpu/ipc/common/gpu_info.mojom
+++ b/gpu/ipc/common/gpu_info.mojom
@@ -76,6 +76,26 @@
   uint32 max_framerate_denominator;
 };
 
+// gpu::ImageDecodeAcceleratorType
+enum ImageDecodeAcceleratorType {
+  kJpeg,
+  kUnknown,
+};
+
+// gpu::ImageDecodeAcceleratorSubsampling
+enum ImageDecodeAcceleratorSubsampling {
+  k420,
+  k422,
+};
+
+// gpu::ImageDecodeAcceleratorSupportedProfile
+struct ImageDecodeAcceleratorSupportedProfile {
+  ImageDecodeAcceleratorType image_type;
+  gfx.mojom.Size min_encoded_dimensions;
+  gfx.mojom.Size max_encoded_dimensions;
+  array<ImageDecodeAcceleratorSubsampling> subsamplings;
+};
+
 // gpu::OverlayFormat
 [EnableIf=is_win]
 enum OverlayFormat {
@@ -142,6 +162,10 @@
   array<VideoEncodeAcceleratorSupportedProfile>
     video_encode_accelerator_supported_profiles;
   bool jpeg_decode_accelerator_supported;
+
+  array<ImageDecodeAcceleratorSupportedProfile>
+    image_decode_accelerator_supported_profiles;
+
   uint64 system_visual;
   uint64 rgba_visual;
   bool oop_rasterization_supported;
diff --git a/gpu/ipc/common/gpu_info.typemap b/gpu/ipc/common/gpu_info.typemap
index 946138f..4ff5fe2 100644
--- a/gpu/ipc/common/gpu_info.typemap
+++ b/gpu/ipc/common/gpu_info.typemap
@@ -21,4 +21,5 @@
   "gpu.mojom.VideoDecodeAcceleratorSupportedProfile=gpu::VideoDecodeAcceleratorSupportedProfile",
   "gpu.mojom.VideoDecodeAcceleratorCapabilities=gpu::VideoDecodeAcceleratorCapabilities",
   "gpu.mojom.VideoEncodeAcceleratorSupportedProfile=gpu::VideoEncodeAcceleratorSupportedProfile",
+  "gpu.mojom.ImageDecodeAcceleratorSupportedProfile=gpu::ImageDecodeAcceleratorSupportedProfile",
 ]
diff --git a/gpu/ipc/common/gpu_info_struct_traits.cc b/gpu/ipc/common/gpu_info_struct_traits.cc
index 117dd3e7..26148ba 100644
--- a/gpu/ipc/common/gpu_info_struct_traits.cc
+++ b/gpu/ipc/common/gpu_info_struct_traits.cc
@@ -5,6 +5,7 @@
 #include "gpu/ipc/common/gpu_info_struct_traits.h"
 #include "build/build_config.h"
 
+#include "base/logging.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
 
 namespace mojo {
@@ -218,6 +219,77 @@
          data.ReadMaxResolution(&out->max_resolution);
 }
 
+// static
+gpu::mojom::ImageDecodeAcceleratorType EnumTraits<
+    gpu::mojom::ImageDecodeAcceleratorType,
+    gpu::ImageDecodeAcceleratorType>::ToMojom(gpu::ImageDecodeAcceleratorType
+                                                  image_type) {
+  switch (image_type) {
+    case gpu::ImageDecodeAcceleratorType::kJpeg:
+      return gpu::mojom::ImageDecodeAcceleratorType::kJpeg;
+    case gpu::ImageDecodeAcceleratorType::kUnknown:
+      return gpu::mojom::ImageDecodeAcceleratorType::kUnknown;
+  }
+}
+
+// static
+bool EnumTraits<gpu::mojom::ImageDecodeAcceleratorType,
+                gpu::ImageDecodeAcceleratorType>::
+    FromMojom(gpu::mojom::ImageDecodeAcceleratorType input,
+              gpu::ImageDecodeAcceleratorType* out) {
+  switch (input) {
+    case gpu::mojom::ImageDecodeAcceleratorType::kJpeg:
+      *out = gpu::ImageDecodeAcceleratorType::kJpeg;
+      return true;
+    case gpu::mojom::ImageDecodeAcceleratorType::kUnknown:
+      *out = gpu::ImageDecodeAcceleratorType::kUnknown;
+      return true;
+  }
+  NOTREACHED() << "Invalid ImageDecodeAcceleratorType: " << input;
+  return false;
+}
+
+// static
+gpu::mojom::ImageDecodeAcceleratorSubsampling
+EnumTraits<gpu::mojom::ImageDecodeAcceleratorSubsampling,
+           gpu::ImageDecodeAcceleratorSubsampling>::
+    ToMojom(gpu::ImageDecodeAcceleratorSubsampling subsampling) {
+  switch (subsampling) {
+    case gpu::ImageDecodeAcceleratorSubsampling::k420:
+      return gpu::mojom::ImageDecodeAcceleratorSubsampling::k420;
+    case gpu::ImageDecodeAcceleratorSubsampling::k422:
+      return gpu::mojom::ImageDecodeAcceleratorSubsampling::k422;
+  }
+}
+
+// static
+bool EnumTraits<gpu::mojom::ImageDecodeAcceleratorSubsampling,
+                gpu::ImageDecodeAcceleratorSubsampling>::
+    FromMojom(gpu::mojom::ImageDecodeAcceleratorSubsampling input,
+              gpu::ImageDecodeAcceleratorSubsampling* out) {
+  switch (input) {
+    case gpu::mojom::ImageDecodeAcceleratorSubsampling::k420:
+      *out = gpu::ImageDecodeAcceleratorSubsampling::k420;
+      return true;
+    case gpu::mojom::ImageDecodeAcceleratorSubsampling::k422:
+      *out = gpu::ImageDecodeAcceleratorSubsampling::k422;
+      return true;
+  }
+  NOTREACHED() << "Invalid ImageDecodeAcceleratorSubsampling: " << input;
+  return false;
+}
+
+// static
+bool StructTraits<gpu::mojom::ImageDecodeAcceleratorSupportedProfileDataView,
+                  gpu::ImageDecodeAcceleratorSupportedProfile>::
+    Read(gpu::mojom::ImageDecodeAcceleratorSupportedProfileDataView data,
+         gpu::ImageDecodeAcceleratorSupportedProfile* out) {
+  return data.ReadImageType(&out->image_type) &&
+         data.ReadMinEncodedDimensions(&out->min_encoded_dimensions) &&
+         data.ReadMaxEncodedDimensions(&out->max_encoded_dimensions) &&
+         data.ReadSubsamplings(&out->subsamplings);
+}
+
 #if defined(OS_WIN)
 // static
 gpu::mojom::OverlayFormat
@@ -322,7 +394,9 @@
          data.ReadVideoDecodeAcceleratorCapabilities(
              &out->video_decode_accelerator_capabilities) &&
          data.ReadVideoEncodeAcceleratorSupportedProfiles(
-             &out->video_encode_accelerator_supported_profiles);
+             &out->video_encode_accelerator_supported_profiles) &&
+         data.ReadImageDecodeAcceleratorSupportedProfiles(
+             &out->image_decode_accelerator_supported_profiles);
 }
 
 }  // namespace mojo
diff --git a/gpu/ipc/common/gpu_info_struct_traits.h b/gpu/ipc/common/gpu_info_struct_traits.h
index ab0a82a..926f8ea 100644
--- a/gpu/ipc/common/gpu_info_struct_traits.h
+++ b/gpu/ipc/common/gpu_info_struct_traits.h
@@ -141,6 +141,52 @@
   }
 };
 
+template <>
+struct EnumTraits<gpu::mojom::ImageDecodeAcceleratorType,
+                  gpu::ImageDecodeAcceleratorType> {
+  static gpu::mojom::ImageDecodeAcceleratorType ToMojom(
+      gpu::ImageDecodeAcceleratorType image_type);
+  static bool FromMojom(gpu::mojom::ImageDecodeAcceleratorType input,
+                        gpu::ImageDecodeAcceleratorType* out);
+};
+
+template <>
+struct EnumTraits<gpu::mojom::ImageDecodeAcceleratorSubsampling,
+                  gpu::ImageDecodeAcceleratorSubsampling> {
+  static gpu::mojom::ImageDecodeAcceleratorSubsampling ToMojom(
+      gpu::ImageDecodeAcceleratorSubsampling subsampling);
+  static bool FromMojom(gpu::mojom::ImageDecodeAcceleratorSubsampling input,
+                        gpu::ImageDecodeAcceleratorSubsampling* out);
+};
+
+template <>
+struct StructTraits<gpu::mojom::ImageDecodeAcceleratorSupportedProfileDataView,
+                    gpu::ImageDecodeAcceleratorSupportedProfile> {
+  static bool Read(
+      gpu::mojom::ImageDecodeAcceleratorSupportedProfileDataView data,
+      gpu::ImageDecodeAcceleratorSupportedProfile* out);
+
+  static gpu::ImageDecodeAcceleratorType image_type(
+      const gpu::ImageDecodeAcceleratorSupportedProfile& input) {
+    return input.image_type;
+  }
+
+  static const gfx::Size& min_encoded_dimensions(
+      const gpu::ImageDecodeAcceleratorSupportedProfile& input) {
+    return input.min_encoded_dimensions;
+  }
+
+  static const gfx::Size& max_encoded_dimensions(
+      const gpu::ImageDecodeAcceleratorSupportedProfile& input) {
+    return input.max_encoded_dimensions;
+  }
+
+  static std::vector<gpu::ImageDecodeAcceleratorSubsampling> subsamplings(
+      const gpu::ImageDecodeAcceleratorSupportedProfile& input) {
+    return input.subsamplings;
+  }
+};
+
 #if defined(OS_WIN)
 template <>
 struct EnumTraits<gpu::mojom::OverlayFormat, gpu::OverlayFormat> {
@@ -323,6 +369,11 @@
     return input.jpeg_decode_accelerator_supported;
   }
 
+  static std::vector<gpu::ImageDecodeAcceleratorSupportedProfile>
+  image_decode_accelerator_supported_profiles(const gpu::GPUInfo& input) {
+    return input.image_decode_accelerator_supported_profiles;
+  }
+
   static uint64_t system_visual(const gpu::GPUInfo& input) {
 #if defined(USE_X11)
     return input.system_visual;
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index ebf60ad5..c87ddfb8 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -97,8 +97,7 @@
        gpu::kGpuFeatureStatusEnabled) ||
       features::IsUsingSkiaRenderer();
   const bool disable_disk_cache =
-      gpu_preferences_.disable_gpu_shader_disk_cache ||
-      gpu_driver_bug_workarounds_.disable_program_disk_cache;
+      gpu_preferences_.disable_gpu_shader_disk_cache;
   if (enable_gr_shader_cache && !disable_disk_cache)
     gr_shader_cache_.emplace(gpu_preferences.gpu_program_cache_size, this);
 }
diff --git a/gpu/tools/compositor_model_bench/render_tree.cc b/gpu/tools/compositor_model_bench/render_tree.cc
index d74b45f9..4b805dd4 100644
--- a/gpu/tools/compositor_model_bench/render_tree.cc
+++ b/gpu/tools/compositor_model_bench/render_tree.cc
@@ -456,9 +456,10 @@
 
   int error_code = 0;
   std::string error_message;
-  std::unique_ptr<base::DictionaryValue> root = base::DictionaryValue::From(
-      JSONReader::ReadAndReturnError(contents, base::JSON_ALLOW_TRAILING_COMMAS,
-                                     &error_code, &error_message));
+  std::unique_ptr<base::DictionaryValue> root =
+      base::DictionaryValue::From(JSONReader::ReadAndReturnErrorDeprecated(
+          contents, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
+          &error_message));
   if (!root) {
     if (error_code) {
       LOG(ERROR) << "Failed to parse JSON file " << path.LossyDisplayName()
diff --git a/headless/lib/browser/headless_devtools_client_impl.cc b/headless/lib/browser/headless_devtools_client_impl.cc
index 1e94c0d..a61b18d7 100644
--- a/headless/lib/browser/headless_devtools_client_impl.cc
+++ b/headless/lib/browser/headless_devtools_client_impl.cc
@@ -131,7 +131,8 @@
 
 void HeadlessDevToolsClientImpl::SendRawDevToolsMessage(
     const std::string& json_message) {
-  std::unique_ptr<base::Value> message = base::JSONReader::Read(json_message);
+  std::unique_ptr<base::Value> message =
+      base::JSONReader::ReadDeprecated(json_message);
   if (!message->is_dict()) {
     LOG(ERROR) << "Malformed raw message";
     return;
@@ -153,7 +154,7 @@
     const std::string& json_message) {
   // LOG(ERROR) << "[RECV] " << json_message;
   std::unique_ptr<base::Value> message =
-      base::JSONReader::Read(json_message, base::JSON_PARSE_RFC);
+      base::JSONReader::ReadDeprecated(json_message, base::JSON_PARSE_RFC);
   if (!message || !message->is_dict()) {
     NOTREACHED() << "Badly formed reply " << json_message;
     return;
diff --git a/headless/public/domains/types_unittest.cc b/headless/public/domains/types_unittest.cc
index 40ee31c..f8e0819 100644
--- a/headless/public/domains/types_unittest.cc
+++ b/headless/public/domains/types_unittest.cc
@@ -26,7 +26,7 @@
 
 TEST(TypesTest, IntegerPropertyParseError) {
   const char json[] = "{\"entryId\": \"foo\"}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
@@ -52,7 +52,7 @@
 
 TEST(TypesTest, BooleanPropertyParseError) {
   const char json[] = "{\"suppressed\": \"foo\"}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
@@ -76,7 +76,7 @@
 
 TEST(TypesTest, DoublePropertyParseError) {
   const char json[] = "{\"latitude\": \"foo\"}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
@@ -99,7 +99,7 @@
 
 TEST(TypesTest, StringPropertyParseError) {
   const char json[] = "{\"url\": false}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
@@ -124,7 +124,7 @@
 
 TEST(TypesTest, EnumPropertyParseError) {
   const char json[] = "{\"type\": false}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
@@ -162,7 +162,7 @@
 
 TEST(TypesTest, ArrayPropertyParseError) {
   const char json[] = "{\"nodeIds\": true}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
@@ -191,7 +191,7 @@
 
 TEST(TypesTest, ObjectPropertyParseError) {
   const char json[] = "{\"result\": 42}";
-  std::unique_ptr<base::Value> object = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> object = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(object);
 
 #if DCHECK_IS_ON()
diff --git a/headless/test/headless_js_bindings_browsertest.cc b/headless/test/headless_js_bindings_browsertest.cc
index 2f62c0ac..c9265ea 100644
--- a/headless/test/headless_js_bindings_browsertest.cc
+++ b/headless/test/headless_js_bindings_browsertest.cc
@@ -145,7 +145,7 @@
 
   void OnMessageFromJS(const std::string& json_message) {
     std::unique_ptr<base::Value> message =
-        base::JSONReader::Read(json_message, base::JSON_PARSE_RFC);
+        base::JSONReader::ReadDeprecated(json_message, base::JSON_PARSE_RFC);
     const base::Value* method_value = message->FindKey("method");
     if (!method_value) {
       FinishAsynchronousTest();
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index b2b7c63a9..ed4bcdd 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -104,7 +104,8 @@
   // runtime::Observer implementation.
   void OnBindingCalled(const runtime::BindingCalledParams& params) override {
     std::string json_message = params.GetPayload();
-    std::unique_ptr<base::Value> message = base::JSONReader::Read(json_message);
+    std::unique_ptr<base::Value> message =
+        base::JSONReader::ReadDeprecated(json_message);
     const base::DictionaryValue* message_dict;
     const base::DictionaryValue* params_dict;
     std::string method;
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 2218537..7459d53 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -214,6 +214,15 @@
       <message name="IDS_IOS_SUGGEST_PASSWORD" desc="Button title in the keyboard accessory bar to show a dialog with a generated password. [Length: 20em] [iOS only]">
         Suggest  Password...
       </message>
+      <message name="IDS_IOS_SUGGESTED_PASSWORD" desc="Text that shows a suggested generated password at user's request [Length: unlimited] [iOS only]">
+        Chrome Suggested Password: <ph name="SUGGESTED_PASSWORD">$1<ex>Ax#f4gH*k7</ex></ph>
+      </message>
+      <message name="IDS_IOS_SUGGESTED_PASSWORD_HINT" desc="Text shown alongside a suggested password to tell user that generated passwords are recorded by chrome. [Length: unlimited] [iOS only]">
+        Chrome will remember this password for you. You don't have to remember it.
+      </message>
+      <message name="IDS_IOS_USE_SUGGESTED_PASSWORD" desc="Button title in a suggested password popup asking user if they want to use the suggested password. [Length: 20em] [iOS only]">
+        Use Suggested Password
+      </message>
       <message name="IDS_IOS_APPLICATION_SHORTCUT_NEWINCOGNITOTAB_TITLE" desc="Message when opening a New Incognito Tab from springboard force touch static shortcuts. [Length: unlimited] [iOS only]." meaning="3D Touch entry to create a new Incognito tab.">
         New Incognito Tab
       </message>
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index 155716b6..fc61776 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -76,6 +76,8 @@
 using autofill::PasswordForm;
 using base::SysNSStringToUTF16;
 using base::SysUTF16ToNSString;
+using l10n_util::GetNSString;
+using l10n_util::GetNSStringF;
 using password_manager::AccountSelectFillData;
 using password_manager::FillData;
 using password_manager::GetPageURLAndCheckTrustLevel;
@@ -408,8 +410,7 @@
                        fieldIdentifier:fieldIdentifier
                              fieldType:fieldType]) {
     // Add "Suggest Password...".
-    NSString* suggestPassword =
-        l10n_util::GetNSString(IDS_IOS_SUGGEST_PASSWORD);
+    NSString* suggestPassword = GetNSString(IDS_IOS_SUGGEST_PASSWORD);
     [suggestions
         addObject:
             [FormSuggestion
@@ -424,7 +425,7 @@
   // option in the new passwords UI.
   if (!autofill::features::IsPasswordManualFallbackEnabled()) {
     // Add "Show all".
-    NSString* showAll = l10n_util::GetNSString(IDS_IOS_SHOW_ALL_PASSWORDS);
+    NSString* showAll = GetNSString(IDS_IOS_SHOW_ALL_PASSWORDS);
     [suggestions
         addObject:
             [FormSuggestion
@@ -679,35 +680,39 @@
     return NO;
   if (![fieldType isEqualToString:@"password"])
     return NO;
-  if (![self hasFormForGenerationForFormName:formName])
+  const NewPasswordFormGenerationData* generation_data =
+      [self getFormForGenerationFromFormName:formName];
+  if (!generation_data)
     return NO;
 
-  // TODO(crbug.com/886583): validate field against _formGenerationData
+  NSString* newPasswordIdentifier =
+      SysUTF16ToNSString(generation_data->new_password_element);
+  if ([fieldIdentifier isEqualToString:newPasswordIdentifier])
+    return YES;
 
-  return YES;
+  // Don't show password generation if the field is 'confirm password'.
+  return NO;
 }
 
-- (BOOL)hasFormForGenerationForFormName:(NSString*)formName {
-  const base::string16 name = SysNSStringToUTF16(formName);
-  return _formGenerationData.find(name) != _formGenerationData.end();
-}
-
-- (const NewPasswordFormGenerationData)getFormForGenerationFromFormName:
+- (const NewPasswordFormGenerationData*)getFormForGenerationFromFormName:
     (NSString*)formName {
   const base::string16 name = SysNSStringToUTF16(formName);
-  return _formGenerationData[name];
+  if (_formGenerationData.find(name) != _formGenerationData.end()) {
+    return &_formGenerationData[name];
+  }
+  return nullptr;
 }
 
 - (void)generatePasswordForFormName:(NSString*)formName
                   completionHandler:(void (^)(BOOL))completionHandler {
-  if (![self hasFormForGenerationForFormName:formName])
-    return;
-  const NewPasswordFormGenerationData form =
+  const NewPasswordFormGenerationData* generation_data =
       [self getFormForGenerationFromFormName:formName];
+  if (!generation_data)
+    return;
   NSString* newPasswordIdentifier =
-      SysUTF16ToNSString(form.new_password_element);
+      SysUTF16ToNSString(generation_data->new_password_element);
   NSString* confirmPasswordIdentifier =
-      SysUTF16ToNSString(form.confirmation_password_element);
+      SysUTF16ToNSString(generation_data->confirmation_password_element);
   [self generatePasswordForFormName:formName
               newPasswordIdentifier:newPasswordIdentifier
           confirmPasswordIdentifier:confirmPasswordIdentifier
@@ -725,13 +730,8 @@
       _passwordGenerationManager->GeneratePassword([self lastCommittedURL], 0,
                                                    0, 0, nullptr);
 
-  NSString* displayPassword = SysUTF16ToNSString(generatedPassword);
-
-  // TODO(crbug.com/886583): i18n
-  NSString* title = [NSString
-      stringWithFormat:@"Chrome Suggested Password: %@", displayPassword];
-  NSString* message = @"Chrome will remember this password for you. You don't "
-                      @"have to remember it.";
+  NSString* title = GetNSStringF(IDS_IOS_SUGGESTED_PASSWORD, generatedPassword);
+  NSString* message = GetNSString(IDS_IOS_SUGGESTED_PASSWORD_HINT);
 
   // TODO(crbug.com/886583): add eg tests
   self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
@@ -745,28 +745,28 @@
       IsIPadIdiom() ? UIAlertControllerStyleAlert
                     : UIAlertControllerStyleActionSheet;
 
+  NSString* nsPassword = SysUTF16ToNSString(generatedPassword);
+
   __weak PasswordController* weakSelf = self;
-  // TODO(crbug.com/886583): i18n
   [self.actionSheetCoordinator
-      addItemWithTitle:@"Use Suggested Password"
+      addItemWithTitle:GetNSString(IDS_IOS_USE_SUGGESTED_PASSWORD)
                 action:^{
                   [weakSelf
                       injectGeneratedPasswordForFormName:formName
                                    newPasswordIdentifier:newPasswordIdentifier
                                confirmPasswordIdentifier:
                                    confirmPasswordIdentifier
-                                       generatedPassword:displayPassword
+                                       generatedPassword:nsPassword
                                        completionHandler:completionHandler];
                 }
                  style:UIAlertActionStyleDefault];
 
-  [self.actionSheetCoordinator
-      addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
-                action:^{
-                  if (completionHandler)
-                    completionHandler(NO);
-                }
-                 style:UIAlertActionStyleCancel];
+  [self.actionSheetCoordinator addItemWithTitle:GetNSString(IDS_CANCEL)
+                                         action:^{
+                                           if (completionHandler)
+                                             completionHandler(NO);
+                                         }
+                                          style:UIAlertActionStyleCancel];
 
   [self.actionSheetCoordinator start];
 }
@@ -774,14 +774,14 @@
 - (void)injectGeneratedPasswordForFormName:(NSString*)formName
                          generatedPassword:(NSString*)generatedPassword
                          completionHandler:(void (^)(BOOL))completionHandler {
-  if (![self hasFormForGenerationForFormName:formName])
-    return;
-  const autofill::NewPasswordFormGenerationData form =
+  const autofill::NewPasswordFormGenerationData* generation_data =
       [self getFormForGenerationFromFormName:formName];
+  if (!generation_data)
+    return;
   NSString* newPasswordIdentifier =
-      SysUTF16ToNSString(form.new_password_element);
+      SysUTF16ToNSString(generation_data->new_password_element);
   NSString* confirmPasswordIdentifier =
-      SysUTF16ToNSString(form.confirmation_password_element);
+      SysUTF16ToNSString(generation_data->confirmation_password_element);
   [self injectGeneratedPasswordForFormName:formName
                      newPasswordIdentifier:newPasswordIdentifier
                  confirmPasswordIdentifier:confirmPasswordIdentifier
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
index 56d647f..a09f88d 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -126,13 +126,12 @@
   syncer::SyncService* sync_service_;
   PersonalDataManager* personal_data_manager_;
   AutocompleteHistoryManager* autocomplete_history_manager_;
+  ios::ChromeBrowserState* browser_state_;
   web::WebState* web_state_;
   __weak id<AutofillClientIOSBridge> bridge_;
   identity::IdentityManager* identity_manager_;
   std::unique_ptr<payments::PaymentsClient> payments_client_;
   std::unique_ptr<FormDataImporter> form_data_importer_;
-  LegacyStrikeDatabase* legacy_strike_database_;
-  StrikeDatabase* strike_database_;
   scoped_refptr<AutofillWebDataService> autofill_web_data_service_;
   infobars::InfoBarManager* infobar_manager_;
   password_manager::PasswordGenerationManager* password_generation_manager_;
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
index 412ae3f3..03f78cbf 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -74,6 +74,7 @@
           browser_state->GetOriginalChromeBrowserState())),
       autocomplete_history_manager_(
           AutocompleteHistoryManagerFactory::GetForBrowserState(browser_state)),
+      browser_state_(browser_state),
       web_state_(web_state),
       bridge_(bridge),
       identity_manager_(IdentityManagerFactory::GetForBrowserState(
@@ -90,8 +91,6 @@
           payments_client_.get(),
           personal_data_manager_,
           GetApplicationContext()->GetApplicationLocale())),
-      legacy_strike_database_(LegacyStrikeDatabaseFactory::GetForBrowserState(
-          browser_state->GetOriginalChromeBrowserState())),
       infobar_manager_(infobar_manager),
       password_generation_manager_(password_generation_manager),
       unmask_controller_(browser_state->GetPrefs(),
@@ -140,11 +139,13 @@
 }
 
 LegacyStrikeDatabase* ChromeAutofillClientIOS::GetLegacyStrikeDatabase() {
-  return legacy_strike_database_;
+  return LegacyStrikeDatabaseFactory::GetForBrowserState(
+      browser_state_->GetOriginalChromeBrowserState());
 }
 
 StrikeDatabase* ChromeAutofillClientIOS::GetStrikeDatabase() {
-  return strike_database_;
+  return StrikeDatabaseFactory::GetForBrowserState(
+      browser_state_->GetOriginalChromeBrowserState());
 }
 
 ukm::UkmRecorder* ChromeAutofillClientIOS::GetUkmRecorder() {
diff --git a/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm b/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm
index 79c9154..108f3d6a 100644
--- a/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm
@@ -7,10 +7,12 @@
 #include "base/logging.h"
 #import "base/test/ios/wait_util.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/form_data_importer.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/ios/browser/autofill_driver_ios.h"
 #import "components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h"
 #include "components/autofill/ios/browser/ios_test_event_waiter.h"
@@ -82,8 +84,8 @@
 
 namespace autofill {
 
-// Helper class that provides access to private members of AutofillManager and
-// FormDataImporter.
+// Helper class that provides access to private members of AutofillManager,
+// FormDataImporter and CreditCardSaveManager.
 class SaveCardInfobarEGTestHelper {
  public:
   SaveCardInfobarEGTestHelper() {}
@@ -110,6 +112,21 @@
         ->GetPaymentsClient();
   }
 
+  static void ClearCreditCardSaveStrikes() {
+    credit_card_save_manager()
+        ->GetCreditCardSaveStrikeDatabase()
+        ->ClearAllStrikes();
+  }
+
+  static void SetMaxStrikesOnFormFillCard() {
+    // The strike key is made of CreditCardSaveStrikeDatabase's project prefix
+    // and the last 4 digits of the card used in fillAndSubmitForm(), which can
+    // be found in credit_card_upload_form_address_and_cc.html.
+    credit_card_save_manager()
+        ->GetCreditCardSaveStrikeDatabase()
+        ->strike_database_->SetStrikeData("CreditCardSave__5454", 3);
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SaveCardInfobarEGTestHelper);
 };
@@ -166,6 +183,9 @@
     personal_data_manager_->RemoveByGUID(profile->guid());
   }
 
+  // Clear CreditCardSave StrikeDatabase.
+  autofill::SaveCardInfobarEGTestHelper::ClearCreditCardSaveStrikes();
+
   [super tearDown];
 }
 
@@ -260,10 +280,15 @@
 
 #pragma mark - Tests
 
+// Upon completion, each test should have the SaveInfobar removed if the
+// |AutofillSaveCreditCardUsesStrikeSystemV2| flag is enabled. This is because
+// the tearDown() function, which is triggered after each test, removes
+// SaveInfoBar and InfobarEvent::STRIKE_CHANGE_COMPLETE will be expected.
+
 // Ensures that submitting the form should query Google Payments; and the
 // fallback local save infobar becomes visible if the request unexpectedly fails
 // but the form data is complete.
-- (void)testOfferLocalSave_FullData_RequestFails {
+- (void)offerLocalSave_FullData_RequestFails {
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kCreditCardUploadForm)];
 
@@ -286,10 +311,29 @@
              @"Save card infobar failed to show.");
 }
 
+- (void)testOfferLocalSave_FullData_RequestFails_StikeDatabaseDisabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerLocalSave_FullData_RequestFails];
+  chrome_test_util::RemoveAllInfoBars();
+}
+
+- (void)testOfferLocalSave_FullData_RequestFails_StikeDatabaseEnabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerLocalSave_FullData_RequestFails];
+  [self resetEventWaiterForEvents:{InfobarEvent::STRIKE_CHANGE_COMPLETE}
+                          timeout:kWaitForDownloadTimeout];
+  chrome_test_util::RemoveAllInfoBars();
+  [self waitForEvents];
+}
+
 // Ensures that submitting the form should query Google Payments; and the
 // fallback local save infobar becomes visible if the request is declined but
 // the form data is complete.
-- (void)testOfferLocalSave_FullData_PaymentsDeclines {
+- (void)offerLocalSave_FullData_PaymentsDeclines {
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kCreditCardUploadForm)];
 
@@ -311,6 +355,25 @@
              @"Save card infobar failed to show.");
 }
 
+- (void)testOfferLocalSave_FullData_PaymentsDeclines_StikeDatabaseDisabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerLocalSave_FullData_PaymentsDeclines];
+  chrome_test_util::RemoveAllInfoBars();
+}
+
+- (void)testOfferLocalSave_FullData_PaymentsDeclines_StikeDatabaseEnabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerLocalSave_FullData_PaymentsDeclines];
+  [self resetEventWaiterForEvents:{InfobarEvent::STRIKE_CHANGE_COMPLETE}
+                          timeout:kWaitForDownloadTimeout];
+  chrome_test_util::RemoveAllInfoBars();
+  [self waitForEvents];
+}
+
 // Ensures that submitting the form, even with only card number and expiration
 // date, should query Google Payments; but the fallback local save infobar
 // should not appear if the request is declined and the form data is incomplete.
@@ -337,7 +400,7 @@
 
 // Ensures that submitting the form should query Google Payments; and the
 // upstreaming infobar should appear if the request is accepted.
-- (void)testOfferUpstream_FullData_PaymentsAccepts {
+- (void)offerUpstream_FullData_PaymentsAccepts {
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kCreditCardUploadForm)];
 
@@ -358,10 +421,29 @@
              @"Save card infobar failed to show.");
 }
 
+- (void)testOfferUpstream_FullData_PaymentsAccepts_StikeDatabaseDisabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerUpstream_FullData_PaymentsAccepts];
+  chrome_test_util::RemoveAllInfoBars();
+}
+
+- (void)testOfferUpstream_FullData_PaymentsAccepts_StikeDatabaseEnabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerUpstream_FullData_PaymentsAccepts];
+  [self resetEventWaiterForEvents:{InfobarEvent::STRIKE_CHANGE_COMPLETE}
+                          timeout:kWaitForDownloadTimeout];
+  chrome_test_util::RemoveAllInfoBars();
+  [self waitForEvents];
+}
+
 // Ensures that submitting the form, even with only card number and expiration
 // date, should query Google Payments and the upstreaming infobar should appear
 // if the request is accepted.
-- (void)testOfferUpstream_PartialData_PaymentsAccepts {
+- (void)offerUpstream_PartialData_PaymentsAccepts {
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kCreditCardUploadForm)];
 
@@ -373,7 +455,7 @@
             {InfobarEvent::REQUESTED_UPLOAD_SAVE,
              InfobarEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE}
                           timeout:kWaitForDownloadTimeout];
-  [self fillAndSubmitFormWithCardDetailsOnly];
+  [self fillAndSubmitForm];
   [self waitForEvents];
 
   // Wait until the save card infobar becomes visible.
@@ -382,9 +464,28 @@
              @"Save card infobar failed to show.");
 }
 
+- (void)testOfferUpstream_PartialData_PaymentsAccepts_StikeDatabaseDisabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerUpstream_PartialData_PaymentsAccepts];
+  chrome_test_util::RemoveAllInfoBars();
+}
+
+- (void)testOfferUpstream_PartialData_PaymentsAccepts_StikeDatabaseEnabled {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self offerUpstream_PartialData_PaymentsAccepts];
+  [self resetEventWaiterForEvents:{InfobarEvent::STRIKE_CHANGE_COMPLETE}
+                          timeout:kWaitForDownloadTimeout];
+  chrome_test_util::RemoveAllInfoBars();
+  [self waitForEvents];
+}
+
 // Ensures that the infobar goes away and UMA metrics are correctly logged if
 // the user declines upload.
-- (void)testUMA_Upstream_UserDeclines {
+- (void)UMA_Upstream_UserDeclines {
   // TODO(crbug.com/925670): re-enable when fixed.
   EARL_GREY_TEST_DISABLED(@"Failing regularly on the bots.");
 
@@ -409,9 +510,20 @@
                        kSaveCardInfobarViewUploadAccessibilityID],
              @"Save card infobar failed to show.");
 
-  // Tap the X button.
-  [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
-      performAction:grey_tap()];
+  if (base::FeatureList::IsEnabled(
+          autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2)) {
+    [self resetEventWaiterForEvents:{InfobarEvent::STRIKE_CHANGE_COMPLETE}
+                            timeout:kWaitForDownloadTimeout];
+    // Tap the X button.
+    [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
+        performAction:grey_tap()];
+    [self waitForEvents];
+
+  } else {
+    // Tap the X button.
+    [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
+        performAction:grey_tap()];
+  }
 
   // Wait until the save card infobar disappears.
   GREYAssert([self waitForUIElementToDisappearOrTimeout:
@@ -425,6 +537,26 @@
   histogram_tester.ExpectTotalCount("Autofill.UploadAcceptedCardOrigin", 0);
 }
 
+- (void)testUMA_Upstream_UserDeclines_StikeDatabaseDisabled {
+  // TODO(crbug.com/925670): re-enable when fixed.
+  EARL_GREY_TEST_DISABLED(@"Failing regularly on the bots.");
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self UMA_Upstream_UserDeclines];
+}
+
+- (void)testUMA_Upstream_UserDeclines_StikeDatabaseEnabled {
+  // TODO(crbug.com/925670): re-enable when fixed.
+  EARL_GREY_TEST_DISABLED(@"Failing regularly on the bots.");
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self UMA_Upstream_UserDeclines];
+}
+
 // Ensures that the infobar goes away, an UploadCardRequest RPC is sent to
 // Google Payments, and UMA metrics are correctly logged if the user accepts
 // upload.
@@ -487,10 +619,7 @@
 
 // Ensures that the infobar goes away and no credit card is saved to Chrome if
 // the user declines local save.
-- (void)testUserData_LocalSave_UserDeclines {
-  // TODO(crbug.com/925670): re-enable when fixed.
-  EARL_GREY_TEST_DISABLED(@"Failing regularly on the bots.");
-
+- (void)userData_LocalSave_UserDeclines {
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kCreditCardUploadForm)];
 
@@ -511,9 +640,20 @@
                        kSaveCardInfobarViewLocalAccessibilityID],
              @"Save card infobar failed to show.");
 
-  // Tap the X button.
-  [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
-      performAction:grey_tap()];
+  if (base::FeatureList::IsEnabled(
+          autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2)) {
+    [self resetEventWaiterForEvents:{InfobarEvent::STRIKE_CHANGE_COMPLETE}
+                            timeout:kWaitForDownloadTimeout];
+    // Tap the X button.
+    [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
+        performAction:grey_tap()];
+    [self waitForEvents];
+
+  } else {
+    // Tap the X button.
+    [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
+        performAction:grey_tap()];
+  }
 
   // Wait until the save card infobar disappears.
   GREYAssert([self waitForUIElementToDisappearOrTimeout:
@@ -525,6 +665,26 @@
                   @"No credit card should have been saved.");
 }
 
+- (void)testUserData_LocalSave_UserDeclines_StikeDatabaseDisabled {
+  // TODO(crbug.com/925670): re-enable when fixed.
+  EARL_GREY_TEST_DISABLED(@"Failing regularly on the bots.");
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self userData_LocalSave_UserDeclines];
+}
+
+- (void)testUserData_LocalSave_UserDeclines_StikeDatabaseEnabled {
+  // TODO(crbug.com/925670): re-enable when fixed.
+  EARL_GREY_TEST_DISABLED(@"Failing regularly on the bots.");
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      autofill::features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+  [self userData_LocalSave_UserDeclines];
+}
+
 // Ensures that the infobar goes away and the credit card is saved to Chrome if
 // the user accepts local save.
 - (void)testUserData_LocalSave_UserAccepts {
@@ -566,4 +726,31 @@
                   @"Credit card should have been saved.");
 }
 
+// Ensures that submitting the form should query Google Payments; but the
+// fallback local save infobar should not appear if the maximum StrikeDatabase
+// strike limit is reached.
+// TODO(crbug.com/925670): remove SetMaxStrikesOnFormFillCard() and incur
+// the maximum number of strikes by showing and declining save infobar instead.
+- (void)testNotOfferLocalSave_MaxStrikesReached {
+  [ChromeEarlGrey
+      loadURL:web::test::HttpServer::MakeUrl(kCreditCardUploadForm)];
+
+  // Set up the Google Payments server response.
+  test_url_loader_factory_.AddResponse(kURLGetUploadDetailsRequest,
+                                       kResponseGetUploadDetailsFailure);
+
+  autofill::SaveCardInfobarEGTestHelper::SetMaxStrikesOnFormFillCard();
+  [self resetEventWaiterForEvents:
+            {InfobarEvent::REQUESTED_UPLOAD_SAVE,
+             InfobarEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE}
+                          timeout:kWaitForDownloadTimeout];
+  [self fillAndSubmitForm];
+  [self waitForEvents];
+
+  // Make sure the save card infobar does not become visible.
+  GREYAssertFalse([self waitForUIElementToAppearOrTimeout:
+                            kSaveCardInfobarViewLocalAccessibilityID],
+                  @"Save card infobar should not show.");
+}
+
 @end
diff --git a/ios/chrome/test/testing_application_context.h b/ios/chrome/test/testing_application_context.h
index 48f003fa..2b9e143 100644
--- a/ios/chrome/test/testing_application_context.h
+++ b/ios/chrome/test/testing_application_context.h
@@ -15,7 +15,6 @@
 namespace network {
 class TestNetworkConnectionTracker;
 class TestURLLoaderFactory;
-class WeakWrapperSharedURLLoaderFactory;
 }  // namespace network
 
 class TestingApplicationContext : public ApplicationContext {
@@ -73,9 +72,6 @@
   std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory_;
   std::unique_ptr<network::TestNetworkConnectionTracker>
       test_network_connection_tracker_;
-  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
-      system_shared_url_loader_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(TestingApplicationContext);
 };
 
diff --git a/ios/chrome/test/testing_application_context.mm b/ios/chrome/test/testing_application_context.mm
index 056b2df..e54e9cec 100644
--- a/ios/chrome/test/testing_application_context.mm
+++ b/ios/chrome/test/testing_application_context.mm
@@ -11,7 +11,6 @@
 #include "components/network_time/network_time_tracker.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "net/url_request/url_request_context_getter.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_url_loader_factory.h"
@@ -28,16 +27,12 @@
       test_url_loader_factory_(
           std::make_unique<network::TestURLLoaderFactory>()),
       test_network_connection_tracker_(
-          network::TestNetworkConnectionTracker::CreateInstance()),
-      system_shared_url_loader_factory_(
-          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-              test_url_loader_factory_.get())) {
+          network::TestNetworkConnectionTracker::CreateInstance()) {
   DCHECK(!GetApplicationContext());
   SetApplicationContext(this);
 }
 
 TestingApplicationContext::~TestingApplicationContext() {
-  system_shared_url_loader_factory_->Detach();
   DCHECK_EQ(this, GetApplicationContext());
   DCHECK(!local_state_);
   SetApplicationContext(nullptr);
@@ -101,7 +96,7 @@
 scoped_refptr<network::SharedURLLoaderFactory>
 TestingApplicationContext::GetSharedURLLoaderFactory() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return system_shared_url_loader_factory_;
+  return test_url_loader_factory_->GetSafeWeakWrapper();
 }
 
 network::mojom::NetworkContext*
diff --git a/ios/features.gni b/ios/features.gni
index 050b0f81..0c8e398e 100644
--- a/ios/features.gni
+++ b/ios/features.gni
@@ -7,4 +7,8 @@
   # components/cronet/tools/cr_cronet.py as cronet requires specific
   # gn args to build correctly).
   is_cronet_build = false
+
+  # Controls whether universal links are blocked from opening native apps
+  # when the user is browsing in off the record mode.
+  block_universal_links_in_off_the_record_mode = true
 }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 4f4bf51..cbe3ee8 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -490,6 +490,7 @@
     "//ios/web/web_state:wk_web_view_security_util",
     "//ios/web/web_state/js",
     "//ios/web/web_state/js:script_util",
+    "//ios/web/web_state/ui:block_universal_links_buildflags",
     "//ios/web/web_state/ui:crw_context_menu_controller",
     "//ios/web/web_state/ui:crw_wk_script_message_router",
     "//ios/web/web_state/ui:favicon_util",
@@ -513,6 +514,7 @@
     "web_state/ui/html_element_fetch_request_unittest.mm",
     "web_state/ui/web_view_js_utils_unittest.mm",
     "web_state/ui/wk_back_forward_list_item_holder_unittest.mm",
+    "web_state/ui/wk_navigation_action_policy_util_unittest.mm",
     "web_state/ui/wk_navigation_action_util_unittest.mm",
     "web_state/ui/wk_web_view_configuration_provider_unittest.mm",
   ]
diff --git a/ios/web/features.mm b/ios/web/features.mm
index 6f55e193..f1210031 100644
--- a/ios/web/features.mm
+++ b/ios/web/features.mm
@@ -30,5 +30,8 @@
 
 const base::Feature kHistoryClobberWorkaround{
     "WKWebViewHistoryClobberWorkaround", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kBlockUniversalLinksInOffTheRecordMode{
+    "BlockUniversalLinksInOffTheRecord", base::FEATURE_DISABLED_BY_DEFAULT};
 }  // namespace features
 }  // namespace web
diff --git a/ios/web/public/features.h b/ios/web/public/features.h
index f66145a..1a5ab17 100644
--- a/ios/web/public/features.h
+++ b/ios/web/public/features.h
@@ -36,6 +36,10 @@
 // (crbug.com/887497).
 extern const base::Feature kHistoryClobberWorkaround;
 
+// Used to prevent native apps from being opened when a universal link is tapped
+// and the user is browsing in off the record mode.
+extern const base::Feature kBlockUniversalLinksInOffTheRecordMode;
+
 }  // namespace features
 }  // namespace web
 
diff --git a/ios/web/web_state/ui/BUILD.gn b/ios/web/web_state/ui/BUILD.gn
index 30341c0..d573a00 100644
--- a/ios/web/web_state/ui/BUILD.gn
+++ b/ios/web/web_state/ui/BUILD.gn
@@ -2,10 +2,18 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
 import("//ios/build/config.gni")
+import("//ios/features.gni")
+
+buildflag_header("block_universal_links_buildflags") {
+  header = "block_universal_links_buildflags.h"
+  flags = [ "BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE=$block_universal_links_in_off_the_record_mode" ]
+}
 
 source_set("ui") {
   deps = [
+    ":block_universal_links_buildflags",
     ":crw_context_menu_controller",
     ":crw_web_view_navigation_proxy",
     ":crw_wk_script_message_router",
@@ -57,6 +65,8 @@
     "web_kit_constants.h",
     "wk_back_forward_list_item_holder.h",
     "wk_back_forward_list_item_holder.mm",
+    "wk_navigation_action_policy_util.h",
+    "wk_navigation_action_policy_util.mm",
     "wk_navigation_action_util.h",
     "wk_navigation_action_util.mm",
   ]
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 9cbaa97..7d0d593 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -102,6 +102,7 @@
 #import "ios/web/web_state/ui/favicon_util.h"
 #include "ios/web/web_state/ui/web_kit_constants.h"
 #import "ios/web/web_state/ui/wk_back_forward_list_item_holder.h"
+#import "ios/web/web_state/ui/wk_navigation_action_policy_util.h"
 #import "ios/web/web_state/ui/wk_navigation_action_util.h"
 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 #import "ios/web/web_state/web_frame_impl.h"
@@ -4701,8 +4702,9 @@
         }));
   }
 
-  decisionHandler(allowLoad ? WKNavigationActionPolicyAllow
-                            : WKNavigationActionPolicyCancel);
+  WKNavigationActionPolicy allowPolicy = web::GetAllowNavigationActionPolicy(
+      self.webState->GetBrowserState()->IsOffTheRecord());
+  decisionHandler(allowLoad ? allowPolicy : WKNavigationActionPolicyCancel);
 }
 
 - (void)webView:(WKWebView*)webView
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 068c83b4..3c0adc5 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -26,6 +26,7 @@
 #include "ios/web/public/features.h"
 #include "ios/web/public/referrer.h"
 #include "ios/web/public/test/fakes/fake_download_controller_delegate.h"
+#include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/test/fakes/test_native_content.h"
 #import "ios/web/public/test/fakes/test_native_content_provider.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
@@ -45,8 +46,10 @@
 #include "ios/web/test/test_url_constants.h"
 #import "ios/web/test/web_test_with_web_controller.h"
 #import "ios/web/test/wk_web_view_crash_utils.h"
+#include "ios/web/web_state/ui/block_universal_links_buildflags.h"
 #import "ios/web/web_state/ui/crw_web_controller_container_view.h"
 #import "ios/web/web_state/ui/web_view_js_utils.h"
+#import "ios/web/web_state/ui/wk_navigation_action_policy_util.h"
 #import "ios/web/web_state/web_state_impl.h"
 #import "ios/web/web_state/wk_web_view_security_util.h"
 #import "net/base/mac/url_conversions.h"
@@ -782,6 +785,11 @@
     });
     return policy_match;
   }
+
+  // Return an owned BrowserState in order to set off the record state.
+  BrowserState* GetBrowserState() override { return &browser_state_; }
+
+  TestBrowserState browser_state_;
 };
 
 // Tests that App specific URLs in iframes are allowed if the main frame is App
@@ -798,6 +806,44 @@
       app_url_request, WKNavigationActionPolicyAllow));
 }
 
+// Tests that URL is allowed in OffTheRecord mode when the
+// |kBlockUniversalLinksInOffTheRecordMode| feature is disabled.
+TEST_P(CRWWebControllerPolicyDeciderTest, AllowOffTheRecordNavigation) {
+  browser_state_.SetOffTheRecord(true);
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      web::features::kBlockUniversalLinksInOffTheRecordMode);
+
+  NSURL* url = [NSURL URLWithString:@(kTestURLString)];
+  NSMutableURLRequest* url_request = [NSMutableURLRequest requestWithURL:url];
+  url_request.mainDocumentURL = url;
+  EXPECT_TRUE(VerifyDecidePolicyForNavigationAction(
+      url_request, WKNavigationActionPolicyAllow));
+}
+
+// Tests that URL is allowed in OffTheRecord mode and that universal links are
+// blocked when the |kBlockUniversalLinksInOffTheRecordMode| feature is enabled
+// and the BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE buildflag is set.
+TEST_P(CRWWebControllerPolicyDeciderTest,
+       AllowOffTheRecordNavigationBlockUniversalLinks) {
+  browser_state_.SetOffTheRecord(true);
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      web::features::kBlockUniversalLinksInOffTheRecordMode);
+
+  NSURL* url = [NSURL URLWithString:@(kTestURLString)];
+  NSMutableURLRequest* url_request = [NSMutableURLRequest requestWithURL:url];
+  url_request.mainDocumentURL = url;
+
+  WKNavigationActionPolicy expected_policy = WKNavigationActionPolicyAllow;
+#if BUILDFLAG(BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE)
+  expected_policy = kNavigationActionPolicyAllowAndBlockUniversalLinks;
+#endif  // BUILDFLAG(BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE)
+
+  EXPECT_TRUE(
+      VerifyDecidePolicyForNavigationAction(url_request, expected_policy));
+}
+
 // Tests that App specific URLs in iframes are not allowed if the main frame is
 // not App specific URL.
 TEST_P(CRWWebControllerPolicyDeciderTest,
diff --git a/ios/web/web_state/ui/wk_navigation_action_policy_util.h b/ios/web/web_state/ui/wk_navigation_action_policy_util.h
new file mode 100644
index 0000000..db2510a4
--- /dev/null
+++ b/ios/web/web_state/ui/wk_navigation_action_policy_util.h
@@ -0,0 +1,23 @@
+// 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 IOS_WEB_WEB_STATE_UI_WK_NAVIGATION_ACTION_POLICY_UTIL_H_
+#define IOS_WEB_WEB_STATE_UI_WK_NAVIGATION_ACTION_POLICY_UTIL_H_
+
+#import <WebKit/WebKit.h>
+
+namespace web {
+
+// Navigation action policy which allows the load but prevents opening universal
+// links in native applications.
+extern const WKNavigationActionPolicy
+    kNavigationActionPolicyAllowAndBlockUniversalLinks;
+
+// Returns the WKNavigationActionPolicy for allowing navigations given the
+// |off_the_record| state for the associated BrowserState.
+WKNavigationActionPolicy GetAllowNavigationActionPolicy(bool off_the_record);
+
+}  // namespace web
+
+#endif  // IOS_WEB_WEB_STATE_UI_WK_NAVIGATION_ACTION_POLICY_UTIL_H_
diff --git a/ios/web/web_state/ui/wk_navigation_action_policy_util.mm b/ios/web/web_state/ui/wk_navigation_action_policy_util.mm
new file mode 100644
index 0000000..4ec2d5bf
--- /dev/null
+++ b/ios/web/web_state/ui/wk_navigation_action_policy_util.mm
@@ -0,0 +1,38 @@
+// 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.
+
+#import "ios/web/web_state/ui/wk_navigation_action_policy_util.h"
+
+#include "base/feature_list.h"
+#include "ios/web/public/features.h"
+#include "ios/web/web_state/ui/block_universal_links_buildflags.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+const WKNavigationActionPolicy
+    kNavigationActionPolicyAllowAndBlockUniversalLinks =
+        static_cast<WKNavigationActionPolicy>(WKNavigationActionPolicyAllow +
+                                              2);
+
+WKNavigationActionPolicy GetAllowNavigationActionPolicy(bool off_the_record) {
+  // When both the |block_universal_links_in_off_the_record| gn arg and the
+  // |web::features::kBlockUniversalLinksInOffTheRecordMode| feature flag are
+  // enabled, the returned value will block opening native applications if
+  // |off_the_record| is true to prevent sharing off the record state.
+#if BUILDFLAG(BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE)
+  bool block_universal_links_enabled = base::FeatureList::IsEnabled(
+      web::features::kBlockUniversalLinksInOffTheRecordMode);
+  if (off_the_record && block_universal_links_enabled) {
+    return kNavigationActionPolicyAllowAndBlockUniversalLinks;
+  }
+#endif  // BUILDFLAG(BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE)
+
+  return WKNavigationActionPolicyAllow;
+}
+
+}  // namespace web
diff --git a/ios/web/web_state/ui/wk_navigation_action_policy_util_unittest.mm b/ios/web/web_state/ui/wk_navigation_action_policy_util_unittest.mm
new file mode 100644
index 0000000..f59c749
--- /dev/null
+++ b/ios/web/web_state/ui/wk_navigation_action_policy_util_unittest.mm
@@ -0,0 +1,56 @@
+// 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.
+
+#import "ios/web/web_state/ui/wk_navigation_action_policy_util.h"
+
+#import <WebKit/WebKit.h>
+
+#include "base/test/scoped_feature_list.h"
+#include "ios/web/public/features.h"
+#include "ios/web/web_state/ui/block_universal_links_buildflags.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+using WKNavigationActionPolicyUtilTest = PlatformTest;
+
+// Tests GetAllowNavigationActionPolicy for normal browsing mode.
+TEST_F(WKNavigationActionPolicyUtilTest, AllowNavigationActionPolicy) {
+  WKNavigationActionPolicy policy = GetAllowNavigationActionPolicy(false);
+  EXPECT_EQ(WKNavigationActionPolicyAllow, policy);
+}
+
+// Tests GetAllowNavigationActionPolicy for off the record browsing mode with
+// the |kBlockUniversalLinksInOffTheRecordMode| feature disabled.
+TEST_F(WKNavigationActionPolicyUtilTest,
+       AllowNavigationActionPolicyForOffTheRecord) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      web::features::kBlockUniversalLinksInOffTheRecordMode);
+
+  WKNavigationActionPolicy policy = GetAllowNavigationActionPolicy(true);
+  EXPECT_EQ(WKNavigationActionPolicyAllow, policy);
+}
+
+// Tests GetAllowNavigationActionPolicy for off the record browsing mode with
+// the |kBlockUniversalLinksInOffTheRecordMode| feature enabled.
+TEST_F(WKNavigationActionPolicyUtilTest, BlockUniversalLinksForOffTheRecord) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      web::features::kBlockUniversalLinksInOffTheRecordMode);
+
+  WKNavigationActionPolicy expected_policy = WKNavigationActionPolicyAllow;
+#if BUILDFLAG(BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE)
+  expected_policy = kNavigationActionPolicyAllowAndBlockUniversalLinks;
+#endif  // BUILDFLAG(BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE)
+
+  EXPECT_EQ(expected_policy, GetAllowNavigationActionPolicy(true));
+}
+
+}  // namespace web
diff --git a/jingle/glue/utils.cc b/jingle/glue/utils.cc
index 66fc3b9..57c1410 100644
--- a/jingle/glue/utils.cc
+++ b/jingle/glue/utils.cc
@@ -77,8 +77,8 @@
 
 bool DeserializeP2PCandidate(const std::string& candidate_str,
                              cricket::Candidate* candidate) {
-  std::unique_ptr<base::Value> value(
-      base::JSONReader::Read(candidate_str, base::JSON_ALLOW_TRAILING_COMMAS));
+  std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(
+      candidate_str, base::JSON_ALLOW_TRAILING_COMMAS));
   if (!value.get() || !value->is_dict()) {
     return false;
   }
diff --git a/media/blink/DEPS b/media/blink/DEPS
index d7d401da..39cc187 100644
--- a/media/blink/DEPS
+++ b/media/blink/DEPS
@@ -15,7 +15,6 @@
   "+services/network/public/cpp",
   "+services/network/public/mojom",
   "+services/service_manager/public/cpp",
-  "+third_party/blink/public/common",
   "+third_party/blink/public/mojom",
   "+third_party/blink/public/platform",
   "+third_party/blink/public/web",
diff --git a/media/blink/webmediaplayer_delegate.h b/media/blink/webmediaplayer_delegate.h
index c3f9c0d7..882a185 100644
--- a/media/blink/webmediaplayer_delegate.h
+++ b/media/blink/webmediaplayer_delegate.h
@@ -72,12 +72,6 @@
     // Called when Picture-in-Picture mode is terminated from the
     // Picture-in-Picture window.
     virtual void OnPictureInPictureModeEnded() = 0;
-
-    // Called when a custom control is clicked on the Picture-in-Picture window.
-    // |control_id| is the identifier for its custom control. This is defined by
-    // the site that calls the web API.
-    virtual void OnPictureInPictureControlClicked(
-        const std::string& control_id) = 0;
   };
 
   // Returns true if the host frame is hidden or closed.
@@ -114,12 +108,6 @@
   // Notify that the muted status of the media player has changed.
   virtual void DidPlayerMutedStatusChange(int delegate_id, bool muted) = 0;
 
-  // Notify that custom controls have been sent to be assigned to the
-  // Picture-in-Picture window.
-  virtual void DidSetPictureInPictureCustomControls(
-      int delegate_id,
-      const std::vector<blink::PictureInPictureControlInfo>&) = 0;
-
   // Notify that playback is stopped. This will drop wake locks and remove any
   // external controls.
   //
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index d05c969..c9637b6 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -57,7 +57,6 @@
 #include "media/filters/memory_data_source.h"
 #include "media/media_buildflags.h"
 #include "net/base/data_url.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/public/platform/web_encrypted_media_types.h"
 #include "third_party/blink/public/platform/web_localized_string.h"
 #include "third_party/blink/public/platform/web_media_player_client.h"
@@ -910,11 +909,6 @@
   DCHECK(bridge_->GetSurfaceId().is_valid());
 }
 
-void WebMediaPlayerImpl::SetPictureInPictureCustomControls(
-    const std::vector<blink::PictureInPictureControlInfo>& controls) {
-  delegate_->DidSetPictureInPictureCustomControls(delegate_id_, controls);
-}
-
 void WebMediaPlayerImpl::SetSinkId(
     const blink::WebString& sink_id,
     std::unique_ptr<blink::WebSetSinkIdCallbacks> web_callback) {
@@ -2301,14 +2295,6 @@
   client_->PictureInPictureStopped();
 }
 
-void WebMediaPlayerImpl::OnPictureInPictureControlClicked(
-    const std::string& control_id) {
-  if (client_ && IsInPictureInPicture()) {
-    client_->PictureInPictureControlClicked(
-        blink::WebString::FromUTF8(control_id));
-  }
-}
-
 void WebMediaPlayerImpl::SendBytesReceivedUpdate() {
   media_metrics_provider_->AddBytesReceived(bytes_received_since_last_update_);
   bytes_received_since_last_update_ = 0;
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 06ede31..93216c48 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -121,8 +121,6 @@
   void SetRate(double rate) override;
   void SetVolume(double volume) override;
   void OnRequestPictureInPicture() override;
-  void SetPictureInPictureCustomControls(
-      const std::vector<blink::PictureInPictureControlInfo>&) override;
   void SetSinkId(
       const blink::WebString& sink_id,
       std::unique_ptr<blink::WebSetSinkIdCallbacks> web_callback) override;
@@ -229,7 +227,6 @@
   void OnVolumeMultiplierUpdate(double multiplier) override;
   void OnBecamePersistentVideo(bool value) override;
   void OnPictureInPictureModeEnded() override;
-  void OnPictureInPictureControlClicked(const std::string& control_id) override;
 
   // Callback for when bytes are received by |chunk_demuxer_| or the UrlData
   // being loaded.
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index e46686b..d8b3e39 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -46,7 +46,6 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
 #include "third_party/blink/public/platform/web_media_player.h"
@@ -143,7 +142,6 @@
   MOCK_METHOD1(MediaRemotingStarted, void(const blink::WebString&));
   MOCK_METHOD1(MediaRemotingStopped, void(blink::WebLocalizedString::Name));
   MOCK_METHOD0(PictureInPictureStopped, void());
-  MOCK_METHOD1(PictureInPictureControlClicked, void(const blink::WebString&));
   MOCK_METHOD0(OnPictureInPictureStateChange, void());
   MOCK_CONST_METHOD0(CouldPlayIfEnoughData, bool());
   MOCK_METHOD0(RequestPlay, void());
@@ -209,10 +207,6 @@
     DCHECK_EQ(player_id_, delegate_id);
   }
 
-  MOCK_METHOD2(DidSetPictureInPictureCustomControls,
-               void(int,
-                    const std::vector<blink::PictureInPictureControlInfo>&));
-
   void ClearStaleFlag(int player_id) override {
     DCHECK_EQ(player_id_, player_id);
     is_stale_ = false;
diff --git a/media/cast/receiver/video_decoder.cc b/media/cast/receiver/video_decoder.cc
index 74d8d80..7278f89d 100644
--- a/media/cast/receiver/video_decoder.cc
+++ b/media/cast/receiver/video_decoder.cc
@@ -199,7 +199,7 @@
     // Make sure this is a JSON string.
     if (!len || data[0] != '{')
       return NULL;
-    std::unique_ptr<base::Value> values(base::JSONReader::Read(
+    std::unique_ptr<base::Value> values(base::JSONReader::ReadDeprecated(
         base::StringPiece(reinterpret_cast<char*>(data), len)));
     if (!values)
       return NULL;
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 9c918a92..0664e40 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -59,7 +59,8 @@
 }
 MATCHER(IsJSONDictionary, "") {
   std::string result(arg.begin(), arg.end());
-  std::unique_ptr<base::Value> root(base::JSONReader().ReadToValue(result));
+  std::unique_ptr<base::Value> root(
+      base::JSONReader().ReadToValueDeprecated(result));
   return (root.get() && root->type() == base::Value::Type::DICTIONARY);
 }
 MATCHER(IsNullTime, "") {
diff --git a/media/cdm/json_web_key.cc b/media/cdm/json_web_key.cc
index aec3796e..3b3ba1c 100644
--- a/media/cdm/json_web_key.cc
+++ b/media/cdm/json_web_key.cc
@@ -172,7 +172,8 @@
     return false;
   }
 
-  std::unique_ptr<base::Value> root(base::JSONReader().ReadToValue(jwk_set));
+  std::unique_ptr<base::Value> root(
+      base::JSONReader().ReadToValueDeprecated(jwk_set));
   if (!root.get() || root->type() != base::Value::Type::DICTIONARY) {
     DVLOG(1) << "Not valid JSON: " << jwk_set << ", root: " << root.get();
     return false;
@@ -241,7 +242,8 @@
     return false;
   }
 
-  std::unique_ptr<base::Value> root(base::JSONReader().ReadToValue(input));
+  std::unique_ptr<base::Value> root(
+      base::JSONReader().ReadToValueDeprecated(input));
   if (!root.get() || root->type() != base::Value::Type::DICTIONARY) {
     error_message->assign("Not valid JSON: ");
     error_message->append(ShortenTo64Characters(input));
@@ -375,7 +377,7 @@
   }
 
   std::unique_ptr<base::Value> root(
-      base::JSONReader().ReadToValue(license_as_str));
+      base::JSONReader().ReadToValueDeprecated(license_as_str));
   if (!root.get() || root->type() != base::Value::Type::DICTIONARY) {
     DVLOG(1) << "Not valid JSON: " << license_as_str;
     return false;
diff --git a/media/gpu/image_processor.cc b/media/gpu/image_processor.cc
index 9cf0ab5..85418c5 100644
--- a/media/gpu/image_processor.cc
+++ b/media/gpu/image_processor.cc
@@ -33,7 +33,7 @@
 bool ImageProcessor::Process(scoped_refptr<VideoFrame> frame,
                              int output_buffer_index,
                              std::vector<base::ScopedFD> output_dmabuf_fds,
-                             FrameReadyCB cb) {
+                             LegacyFrameReadyCB cb) {
   return ProcessInternal(std::move(frame), output_buffer_index,
                          std::move(output_dmabuf_fds),
                          BindToCurrentLoop(std::move(cb)));
diff --git a/media/gpu/image_processor.h b/media/gpu/image_processor.h
index ebff253..4727bb94 100644
--- a/media/gpu/image_processor.h
+++ b/media/gpu/image_processor.h
@@ -64,6 +64,14 @@
   // Process() is responsible for making sure this invariant is
   // respected by using media::BindToCurrentLoop().
   using FrameReadyCB = base::OnceCallback<void(scoped_refptr<VideoFrame>)>;
+  // Callback to be used to return a processed image to the client.
+  // Used when calling the "legacy" Process() method with buffers that are
+  // managed by the IP. The first argument is the index of the returned buffer.
+  // FrameReadyCB is guaranteed to be executed on the "client thread".
+  // Process() is responsible for making sure this invariant is
+  // respected by using media::BindToCurrentLoop().
+  using LegacyFrameReadyCB =
+      base::OnceCallback<void(size_t, scoped_refptr<VideoFrame>)>;
 
   // Callback to be used to notify client when ImageProcess encounters error.
   // It should be assigned in subclass' factory method. ErrorCB is guaranteed to
@@ -114,7 +122,7 @@
   bool Process(scoped_refptr<VideoFrame> frame,
                int output_buffer_index,
                std::vector<base::ScopedFD> output_dmabuf_fds,
-               FrameReadyCB cb);
+               LegacyFrameReadyCB cb);
 #endif
 
   // Called by client to process |input_frame| and store in |output_frame|. This
@@ -159,7 +167,7 @@
   virtual bool ProcessInternal(scoped_refptr<VideoFrame> frame,
                                int output_buffer_index,
                                std::vector<base::ScopedFD> output_dmabuf_fds,
-                               FrameReadyCB cb) = 0;
+                               LegacyFrameReadyCB cb) = 0;
 #endif
   virtual bool ProcessInternal(scoped_refptr<VideoFrame> input_frame,
                                scoped_refptr<VideoFrame> output_frame,
diff --git a/media/gpu/libyuv_image_processor.cc b/media/gpu/libyuv_image_processor.cc
index 9654749..6d663ff0 100644
--- a/media/gpu/libyuv_image_processor.cc
+++ b/media/gpu/libyuv_image_processor.cc
@@ -104,7 +104,7 @@
     scoped_refptr<VideoFrame> frame,
     int output_buffer_index,
     std::vector<base::ScopedFD> output_dmabuf_fds,
-    FrameReadyCB cb) {
+    LegacyFrameReadyCB cb) {
   DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
   NOTIMPLEMENTED();
   return false;
diff --git a/media/gpu/libyuv_image_processor.h b/media/gpu/libyuv_image_processor.h
index 386463d..1780fc62 100644
--- a/media/gpu/libyuv_image_processor.h
+++ b/media/gpu/libyuv_image_processor.h
@@ -61,7 +61,7 @@
   bool ProcessInternal(scoped_refptr<VideoFrame> frame,
                        int output_buffer_index,
                        std::vector<base::ScopedFD> output_dmabuf_fds,
-                       FrameReadyCB cb) override;
+                       LegacyFrameReadyCB cb) override;
 #endif
   bool ProcessInternal(scoped_refptr<VideoFrame> input_frame,
                        scoped_refptr<VideoFrame> output_frame,
diff --git a/media/gpu/test/image.cc b/media/gpu/test/image.cc
index 41f60429..6585c9b5 100644
--- a/media/gpu/test/image.cc
+++ b/media/gpu/test/image.cc
@@ -103,7 +103,8 @@
   }
 
   base::JSONReader reader;
-  std::unique_ptr<base::Value> metadata(reader.ReadToValue(json_data));
+  std::unique_ptr<base::Value> metadata(
+      reader.ReadToValueDeprecated(json_data));
   if (!metadata) {
     VLOGF(1) << "Failed to parse image metadata: " << json_path << ": "
              << reader.GetErrorMessage();
diff --git a/media/gpu/test/video_player/video.cc b/media/gpu/test/video_player/video.cc
index 47a8e3f..ca90ead 100644
--- a/media/gpu/test/video_player/video.cc
+++ b/media/gpu/test/video_player/video.cc
@@ -124,7 +124,8 @@
   }
 
   base::JSONReader reader;
-  std::unique_ptr<base::Value> metadata(reader.ReadToValue(json_data));
+  std::unique_ptr<base::Value> metadata(
+      reader.ReadToValueDeprecated(json_data));
   if (!metadata) {
     VLOGF(1) << "Failed to parse video metadata: " << json_path << ": "
              << reader.GetErrorMessage();
diff --git a/media/gpu/v4l2/v4l2_image_processor.cc b/media/gpu/v4l2/v4l2_image_processor.cc
index 099746f..7242552d 100644
--- a/media/gpu/v4l2/v4l2_image_processor.cc
+++ b/media/gpu/v4l2/v4l2_image_processor.cc
@@ -376,13 +376,13 @@
     scoped_refptr<VideoFrame> frame,
     int output_buffer_index,
     std::vector<base::ScopedFD> output_dmabuf_fds,
-    FrameReadyCB cb) {
+    LegacyFrameReadyCB cb) {
   DVLOGF(4) << "ts=" << frame->timestamp().InMilliseconds();
 
   auto job_record = std::make_unique<JobRecord>();
   job_record->input_frame = frame;
   job_record->output_buffer_index = output_buffer_index;
-  job_record->ready_cb = std::move(cb);
+  job_record->legacy_ready_cb = std::move(cb);
 
   switch (output_memory_type_) {
     case V4L2_MEMORY_MMAP:
@@ -600,7 +600,9 @@
   VLOGF(2);
   DCHECK_CALLED_ON_VALID_THREAD(device_thread_checker_);
 
-  input_queue_->DeallocateBuffers();
+  // We may be destroyed before we allocate any buffer.
+  if (input_queue_)
+    input_queue_->DeallocateBuffers();
 }
 
 void V4L2ImageProcessor::DestroyOutputBuffers() {
@@ -609,7 +611,9 @@
 
   output_buffer_map_.clear();
 
-  output_queue_->DeallocateBuffers();
+  // We may be destroyed before we allocate any buffer.
+  if (output_queue_)
+    output_queue_->DeallocateBuffers();
 }
 
 void V4L2ImageProcessor::DevicePollTask(bool poll_device) {
@@ -632,6 +636,7 @@
 void V4L2ImageProcessor::ServiceDeviceTask() {
   DVLOGF(4);
   DCHECK_CALLED_ON_VALID_THREAD(device_thread_checker_);
+  DCHECK(input_queue_);
   // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
   // so either:
   // * device_poll_thread_ is running normally
@@ -667,6 +672,7 @@
 void V4L2ImageProcessor::EnqueueInput(const JobRecord* job_record) {
   DVLOGF(4);
   DCHECK_CALLED_ON_VALID_THREAD(device_thread_checker_);
+  DCHECK(input_queue_);
 
   const size_t old_inputs_queued = input_queue_->QueuedBuffersCount();
   if (!EnqueueInputRecord(job_record))
@@ -688,6 +694,7 @@
 void V4L2ImageProcessor::EnqueueOutput(const JobRecord* job_record) {
   DVLOGF(4);
   DCHECK_CALLED_ON_VALID_THREAD(device_thread_checker_);
+  DCHECK(output_queue_);
 
   const int old_outputs_queued = output_buffer_queued_count_;
   if (!EnqueueOutputRecord(job_record))
@@ -709,6 +716,8 @@
 void V4L2ImageProcessor::Dequeue() {
   DVLOGF(4);
   DCHECK_CALLED_ON_VALID_THREAD(device_thread_checker_);
+  DCHECK(input_queue_);
+  DCHECK(output_queue_);
   DCHECK(input_queue_->IsStreaming());
 
   // Dequeue completed input (VIDEO_OUTPUT) buffers,
@@ -793,12 +802,18 @@
 
     DVLOGF(4) << "Processing finished, returning frame, index=" << dqbuf.index;
 
-    std::move(job_record->ready_cb).Run(std::move(output_frame));
+    if (!job_record->legacy_ready_cb.is_null()) {
+      std::move(job_record->legacy_ready_cb)
+          .Run(dqbuf.index, std::move(output_frame));
+    } else {
+      std::move(job_record->ready_cb).Run(std::move(output_frame));
+    }
   }
 }
 
 bool V4L2ImageProcessor::EnqueueInputRecord(const JobRecord* job_record) {
   DVLOGF(4);
+  DCHECK(input_queue_);
   DCHECK_GT(input_queue_->FreeBuffersCount(), 0u);
 
   // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
@@ -920,10 +935,10 @@
     return;
   }
 
-  if (!input_queue_->Streamoff())
+  if (input_queue_ && !input_queue_->Streamoff())
     return;
 
-  if (!output_queue_->Streamoff())
+  if (output_queue_ && !output_queue_->Streamoff())
     return;
 
   // Reset all our accounting info.
diff --git a/media/gpu/v4l2/v4l2_image_processor.h b/media/gpu/v4l2/v4l2_image_processor.h
index 953f3f46..bc46c1c 100644
--- a/media/gpu/v4l2/v4l2_image_processor.h
+++ b/media/gpu/v4l2/v4l2_image_processor.h
@@ -100,6 +100,7 @@
     int output_buffer_index;
     std::vector<base::ScopedFD> output_dmabuf_fds;
     FrameReadyCB ready_cb;
+    LegacyFrameReadyCB legacy_ready_cb;
   };
 
   V4L2ImageProcessor(scoped_refptr<V4L2Device> device,
@@ -132,7 +133,7 @@
   bool ProcessInternal(scoped_refptr<VideoFrame> frame,
                        int output_buffer_index,
                        std::vector<base::ScopedFD> output_dmabuf_fds,
-                       FrameReadyCB cb) override;
+                       LegacyFrameReadyCB cb) override;
   bool ProcessInternal(scoped_refptr<VideoFrame> input_frame,
                        scoped_refptr<VideoFrame> output_frame,
                        FrameReadyCB cb) override;
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 48d8fca..a868c5c 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -548,47 +548,39 @@
     const gfx::GpuMemoryBufferHandle& gpu_memory_buffer_handle) {
   DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id;
   DCHECK(child_task_runner_->BelongsToCurrentThread());
-
-  std::vector<base::ScopedFD> dmabuf_fds;
-  int32_t stride = 0;
-#if defined(USE_OZONE)
-  DCHECK_EQ(gpu_memory_buffer_handle.native_pixmap_handle.fds.size(),
-            gpu_memory_buffer_handle.native_pixmap_handle.planes.size());
-
-  // If the driver does not accept as many fds as we received from the client,
-  // we have to check if the additional fds are actually duplicated fds pointing
-  // to previous planes; if so, we can close the duplicates and keep only the
-  // original fd(s).
-  // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
-  // Otherwise, if offset == 0, return error as it may be pointing to a new
-  // plane.
-  for (auto& fd : gpu_memory_buffer_handle.native_pixmap_handle.fds) {
-    dmabuf_fds.emplace_back(fd.fd);
-  }
-  for (size_t i = dmabuf_fds.size() - 1; i >= egl_image_planes_count_; i--) {
-    if (gpu_memory_buffer_handle.native_pixmap_handle.planes[i].offset == 0) {
-      VLOGF(1) << "The dmabuf fd points to a new buffer, ";
-      NOTIFY_ERROR(INVALID_ARGUMENT);
-      return;
-    }
-    // Drop safely, because this fd is duplicate dmabuf fd pointing to previous
-    // buffer and the appropriate address can be accessed by associated offset.
-    dmabuf_fds.pop_back();
-  }
-
-  stride = gpu_memory_buffer_handle.native_pixmap_handle.planes[0].stride;
-  for (const auto& plane :
-       gpu_memory_buffer_handle.native_pixmap_handle.planes) {
-    DVLOGF(3) << ": offset=" << plane.offset << ", stride=" << plane.stride;
-  }
-#endif
-
   if (output_mode_ != Config::OutputMode::IMPORT) {
     VLOGF(1) << "Cannot import in non-import mode";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
 
+  std::vector<base::ScopedFD> dmabuf_fds;
+  std::vector<gfx::NativePixmapPlane> planes;
+#if defined(USE_OZONE)
+  DCHECK_EQ(gpu_memory_buffer_handle.native_pixmap_handle.fds.size(),
+            gpu_memory_buffer_handle.native_pixmap_handle.planes.size());
+
+  for (auto& fd : gpu_memory_buffer_handle.native_pixmap_handle.fds) {
+    dmabuf_fds.emplace_back(fd.fd);
+  }
+
+  planes = gpu_memory_buffer_handle.native_pixmap_handle.planes;
+#endif
+
+  decoder_thread_.task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &V4L2VideoDecodeAccelerator::ImportBufferForPictureForImportTask,
+          base::Unretained(this), picture_buffer_id, pixel_format,
+          std::move(dmabuf_fds), std::move(planes)));
+}
+
+void V4L2VideoDecodeAccelerator::ImportBufferForPictureForImportTask(
+    int32_t picture_buffer_id,
+    VideoPixelFormat pixel_format,
+    std::vector<base::ScopedFD> dmabuf_fds,
+    std::vector<gfx::NativePixmapPlane> planes) {
+  DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
   // |output_format_fourcc_| is the output format of the decoder. It is not
   // the final output format from the image processor (if exists).
   // Use |egl_image_format_fourcc_|, it will be the final output format.
@@ -599,11 +591,30 @@
     return;
   }
 
-  decoder_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&V4L2VideoDecodeAccelerator::ImportBufferForPictureTask,
-                     base::Unretained(this), picture_buffer_id,
-                     std::move(dmabuf_fds), stride));
+  // If the driver does not accept as many fds as we received from the client,
+  // we have to check if the additional fds are actually duplicated fds pointing
+  // to previous planes; if so, we can close the duplicates and keep only the
+  // original fd(s).
+  // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
+  // Otherwise, if offset == 0, return error as it may be pointing to a new
+  // plane.
+  for (size_t i = dmabuf_fds.size() - 1; i >= egl_image_planes_count_; i--) {
+    if (planes[i].offset == 0) {
+      VLOGF(1) << "The dmabuf fd points to a new buffer, ";
+      NOTIFY_ERROR(INVALID_ARGUMENT);
+      return;
+    }
+    // Drop safely, because this fd is duplicate dmabuf fd pointing to previous
+    // buffer and the appropriate address can be accessed by associated offset.
+    dmabuf_fds.pop_back();
+  }
+
+  for (const auto& plane : planes) {
+    DVLOGF(3) << ": offset=" << plane.offset << ", stride=" << plane.stride;
+  }
+
+  ImportBufferForPictureTask(picture_buffer_id, std::move(dmabuf_fds),
+                             planes[0].stride);
 }
 
 void V4L2VideoDecodeAccelerator::ImportBufferForPictureTask(
@@ -2492,8 +2503,7 @@
   image_processor_->Process(
       input_frame, buf->BufferId(), std::move(output_fds),
       base::BindOnce(&V4L2VideoDecodeAccelerator::FrameProcessed,
-                     base::Unretained(this), bitstream_buffer_id,
-                     buf->BufferId()));
+                     base::Unretained(this), bitstream_buffer_id));
   return true;
 }
 
@@ -2677,7 +2687,7 @@
 
 void V4L2VideoDecodeAccelerator::FrameProcessed(
     int32_t bitstream_buffer_id,
-    int ip_buffer_index,
+    size_t ip_buffer_index,
     scoped_refptr<VideoFrame> frame) {
   DVLOGF(4) << "ip_buffer_index=" << ip_buffer_index
             << ", bitstream_buffer_id=" << bitstream_buffer_id;
@@ -2703,8 +2713,8 @@
               << bitstream_buffer_id;
     return;
   }
-  DCHECK_GE(ip_buffer_index, 0);
-  DCHECK_LT(ip_buffer_index, static_cast<int>(output_buffer_map_.size()));
+  DCHECK_GE(ip_buffer_index, 0u);
+  DCHECK_LT(ip_buffer_index, output_buffer_map_.size());
 
   // This is the output record for the buffer received from the IP, which index
   // may differ from the buffer used by the VDA.
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.h b/media/gpu/v4l2/v4l2_video_decode_accelerator.h
index 6a22d9c..81b4ca9 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.h
@@ -243,6 +243,14 @@
                                   std::vector<base::ScopedFD> dmabuf_fds,
                                   int32_t stride);
 
+  // Check |planes| and |dmabuf_fds| are valid in import mode, besides
+  // ImportBufferForPicture.
+  void ImportBufferForPictureForImportTask(
+      int32_t picture_buffer_id,
+      VideoPixelFormat pixel_format,
+      std::vector<base::ScopedFD> dmabuf_fds,
+      std::vector<gfx::NativePixmapPlane> planes);
+
   // Create an EGLImage for the buffer associated with V4L2 |buffer_index| and
   // for |picture_buffer_id|, backed by dmabuf file descriptors in
   // |passed_dmabuf_fds|, taking ownership of them.
@@ -419,7 +427,7 @@
   // |bitstream_buffer_id| and stored in |output_buffer_index| buffer of
   // image processor.
   void FrameProcessed(int32_t bitstream_buffer_id,
-                      int output_buffer_index,
+                      size_t output_buffer_index,
                       scoped_refptr<VideoFrame> frame);
 
   // Image processor notifies an error.
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 934d36fd..0b660c3d 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -400,8 +400,8 @@
         if (!image_processor_->Process(
                 frame, output_buffer_index, std::vector<base::ScopedFD>(),
                 base::BindOnce(&V4L2VideoEncodeAccelerator::FrameProcessed,
-                               weak_this_, force_keyframe, frame->timestamp(),
-                               output_buffer_index))) {
+                               weak_this_, force_keyframe,
+                               frame->timestamp()))) {
           NOTIFY_ERROR(kPlatformFailureError);
         }
       }
@@ -529,12 +529,12 @@
 void V4L2VideoEncodeAccelerator::FrameProcessed(
     bool force_keyframe,
     base::TimeDelta timestamp,
-    int output_buffer_index,
+    size_t output_buffer_index,
     scoped_refptr<VideoFrame> frame) {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DVLOGF(4) << "force_keyframe=" << force_keyframe
             << ", output_buffer_index=" << output_buffer_index;
-  DCHECK_GE(output_buffer_index, 0);
+  DCHECK_GE(output_buffer_index, 0u);
   DCHECK(encoder_thread_.IsRunning());
   DCHECK(!weak_this_.WasInvalidated());
 
@@ -548,7 +548,7 @@
 }
 
 void V4L2VideoEncodeAccelerator::ReuseImageProcessorOutputBuffer(
-    int output_buffer_index) {
+    size_t output_buffer_index) {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DVLOGF(4) << "output_buffer_index=" << output_buffer_index;
   free_image_processor_output_buffer_indices_.push_back(output_buffer_index);
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.h b/media/gpu/v4l2/v4l2_video_encode_accelerator.h
index 7e2d30c..aff19bb 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.h
@@ -117,7 +117,7 @@
   // encode.
   void FrameProcessed(bool force_keyframe,
                       base::TimeDelta timestamp,
-                      int output_buffer_index,
+                      size_t output_buffer_index,
                       scoped_refptr<VideoFrame> frame);
 
   // Error callback for handling image processor errors.
@@ -218,7 +218,7 @@
   bool AllocateImageProcessorOutputBuffers();
 
   // Recycle output buffer of image processor with |output_buffer_index|.
-  void ReuseImageProcessorOutputBuffer(int output_buffer_index);
+  void ReuseImageProcessorOutputBuffer(size_t output_buffer_index);
 
   // Copy encoded stream data from an output V4L2 buffer at |bitstream_data|
   // of size |bitstream_size| into a BitstreamBuffer referenced by |buffer_ref|,
diff --git a/media/learning/common/value.h b/media/learning/common/value.h
index 62f4953..ef37eeb 100644
--- a/media/learning/common/value.h
+++ b/media/learning/common/value.h
@@ -27,7 +27,7 @@
  public:
   Value();
   template <typename T>
-  explicit Value(T x) : value_(x) {
+  explicit Value(const T& x) : value_(x) {
     // We want to rule out mostly pointers, since they wouldn't make much sense.
     // Note that the implicit cast would likely fail anyway.
     static_assert(std::is_arithmetic<T>::value || std::is_enum<T>::value,
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
index 2739747..1935034 100644
--- a/mojo/public/cpp/bindings/README.md
+++ b/mojo/public/cpp/bindings/README.md
@@ -1371,10 +1371,10 @@
 
 In order to define the mapping for `gfx::Rect`, we want the following
 `StructTraits` specialization, which we'll define in
-`//ui/gfx/geometry/mojo/geometry_struct_traits.h`:
+`//ui/gfx/geometry/mojo/geometry_mojom_traits.h`:
 
 ``` cpp
-#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "mojo/public/cpp/bindings/mojom_traits.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/mojo/geometry.mojom.h"
 
@@ -1394,10 +1394,10 @@
 }  // namespace mojo
 ```
 
-And in `//ui/gfx/geometry/mojo/geometry_struct_traits.cc`:
+And in `//ui/gfx/geometry/mojo/geometry_mojom_traits.cc`:
 
 ``` cpp
-#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/geometry/mojo/geometry_mojom_traits.h"
 
 namespace mojo {
 
@@ -1465,10 +1465,10 @@
 mojom = "//ui/gfx/geometry/mojo/geometry.mojom"
 os_whitelist = [ "android" ]
 public_headers = [ "//ui/gfx/geometry/rect.h" ]
-traits_headers = [ "//ui/gfx/geometry/mojo/geometry_struct_traits.h" ]
+traits_headers = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.h" ]
 sources = [
-  "//ui/gfx/geometry/mojo/geometry_struct_traits.cc",
-  "//ui/gfx/geometry/mojo/geometry_struct_traits.h",
+  "//ui/gfx/geometry/mojo/geometry_mojom_traits.cc",
+  "//ui/gfx/geometry/mojo/geometry_mojom_traits.h",
 ]
 public_deps = [ "//ui/gfx/geometry" ]
 type_mappings = [
@@ -1489,9 +1489,9 @@
   here.
 * `traits_headers`: Headers which contain the relevant `StructTraits`
   specialization(s) for any type mappings described by this file.
-* `sources`: Any implementation sources and headers needed for the
-  `StructTraits` definition. These sources are compiled directly into the
-  generated C++ bindings target for a `mojom` file applying this typemap.
+* `sources`: Any implementation sources needed for the `StructTraits`
+  definition. These sources are compiled directly into the generated C++
+  bindings target for a `mojom` file applying this typemap.
 * `public_deps`: Target dependencies exposed by the `public_headers` and
   `traits_headers`.
 * `deps`: Target dependencies exposed by `sources` but not already covered by
diff --git a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
index ce7ee62a..948d77a6 100644
--- a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
+++ b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
@@ -48,6 +48,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
@@ -226,7 +227,7 @@
 
         // Send the intent to the receiver.
         BroadcastReceiver receiver = receivers.get(0);
-        receiver.onReceive(ShadowApplication.getInstance().getApplicationContext(), intent);
+        receiver.onReceive(RuntimeEnvironment.application.getApplicationContext(), intent);
 
         // Verify that the auth token is properly requested from the account manager.
         verify(sMockAccountManager)
diff --git a/net/cert/cert_verify_proc_blacklist.inc b/net/cert/cert_verify_proc_blacklist.inc
index 249b61db..4014d81 100644
--- a/net/cert/cert_verify_proc_blacklist.inc
+++ b/net/cert/cert_verify_proc_blacklist.inc
@@ -7,6 +7,14 @@
 // rationale is documented in net/data/ssl/blacklist/README.md
 static constexpr uint8_t
     kBlacklistedSPKIs[][crypto::kSHA256Length] = {
+        // 2740d956b1127b791aa1b3cc644a4dbedba76186a23638b95102351a834ea861.pem
+        {0x04, 0xdd, 0xe9, 0xaa, 0x9a, 0x79, 0xf6, 0x14, 0x98, 0x68, 0x23,
+         0x25, 0xfa, 0x08, 0x70, 0x27, 0x67, 0x07, 0xfb, 0x9c, 0xa9, 0x53,
+         0x84, 0x12, 0x0b, 0x46, 0x89, 0x32, 0x68, 0x49, 0x4f, 0xc9},
+        // 91e5cc32910686c5cac25c18cc805696c7b33868c280caf0c72844a2a8eb91e2.pem
+        {0x0c, 0x43, 0xea, 0x8b, 0xcd, 0xe9, 0xfc, 0x3b, 0xca, 0x16, 0x56,
+         0x64, 0xac, 0x82, 0x15, 0x56, 0x7e, 0x34, 0x89, 0xd5, 0x39, 0x3a,
+         0x0c, 0x81, 0xe1, 0xa7, 0x91, 0x41, 0x99, 0x2e, 0x19, 0x53},
         // ead610e6e90b439f2ecb51628b0932620f6ef340bd843fca38d3181b8f4ba197.pem
         {0x12, 0x13, 0x23, 0x60, 0xa3, 0x3b, 0xfd, 0xc6, 0xc3, 0xbf, 0x7b,
          0x7f, 0xab, 0x26, 0xa1, 0x68, 0x48, 0x74, 0xe7, 0x2c, 0x12, 0x63,
@@ -31,18 +39,38 @@
         {0x1f, 0x42, 0x24, 0xce, 0xc8, 0x4f, 0xc9, 0x9c, 0xed, 0x88, 0x1f,
          0xf6, 0xfc, 0xfd, 0x3e, 0x21, 0xf8, 0xc5, 0x19, 0xc5, 0x47, 0xaa,
          0x6a, 0x5d, 0xd3, 0xde, 0x24, 0x73, 0x02, 0xce, 0x50, 0xd1},
+        // e54e9fc27e7350ff63a77764a40267b7e95ae5df3ed7df5336e8f8541356c845.pem
+        {0x25, 0xda, 0x1a, 0xd5, 0x8b, 0xbf, 0xcf, 0xb2, 0x27, 0xd8, 0x72,
+         0x3b, 0x18, 0x57, 0xd4, 0xc1, 0x8e, 0x7b, 0xaa, 0x74, 0x17, 0xb4,
+         0xf9, 0xef, 0xf9, 0x36, 0x6b, 0x5e, 0x86, 0x9f, 0x8b, 0x39},
         // 159ca03a88897c8f13817a212629df84ce824709492b8c9adb8e5437d2fc72be.pem
         {0x2c, 0x99, 0x8e, 0x76, 0x11, 0x60, 0xc3, 0xb0, 0x6d, 0x82, 0xfa,
          0xa9, 0xfd, 0xc7, 0x54, 0x5d, 0x9b, 0xda, 0x9e, 0xb6, 0x03, 0x10,
          0xf9, 0x92, 0xaa, 0x51, 0x0a, 0x62, 0x80, 0xb7, 0x42, 0x45},
+        // d0d672c2547d574ae055d9e78a993ddbcc74044c4253fbfaca573a67d368e1db.pem
+        {0x30, 0xef, 0xe4, 0x13, 0x82, 0x47, 0x6c, 0x33, 0x80, 0xf0, 0x2f,
+         0x7e, 0x23, 0xe6, 0x6b, 0xa2, 0xf8, 0x67, 0xb0, 0x59, 0xee, 0x1e,
+         0xa6, 0x87, 0x96, 0xb4, 0x41, 0xb8, 0x5b, 0x5d, 0x12, 0x56},
         // 32ecc96f912f96d889e73088cd031c7ded2c651c805016157a23b6f32f798a3b.key
         {0x32, 0xec, 0xc9, 0x6f, 0x91, 0x2f, 0x96, 0xd8, 0x89, 0xe7, 0x30,
          0x88, 0xcd, 0x03, 0x1c, 0x7d, 0xed, 0x2c, 0x65, 0x1c, 0x80, 0x50,
          0x16, 0x15, 0x7a, 0x23, 0xb6, 0xf3, 0x2f, 0x79, 0x8a, 0x3b},
+        // 4aefc3d39ef59e4d4b0304b20f53a8af2efb69edece66def74494abfc10a2d66.pem
+        {0x36, 0xea, 0x96, 0x12, 0x8c, 0x89, 0x83, 0x9f, 0xb6, 0x21, 0xf8,
+         0xad, 0x0e, 0x1e, 0xe0, 0xb9, 0xc2, 0x20, 0x6f, 0x62, 0xab, 0x7b,
+         0x4d, 0xa2, 0xc6, 0x76, 0x58, 0x93, 0xc9, 0xb7, 0xce, 0xd2},
         // d487a56f83b07482e85e963394c1ecc2c9e51d0903ee946b02c301581ed99e16.pem
         {0x38, 0x1a, 0x3f, 0xc7, 0xa8, 0xb0, 0x82, 0xfa, 0x28, 0x61, 0x3a,
          0x4d, 0x07, 0xf2, 0xc7, 0x55, 0x3f, 0x4e, 0x19, 0x18, 0xee, 0x07,
          0xca, 0xa9, 0xe8, 0xb7, 0xce, 0xde, 0x5a, 0x9c, 0xa0, 0x6a},
+        // 0ef7c54a3af101a2cfedb0c9f36fe8214d51a504fdc2ad1e243019cefd7d03c2.pem
+        {0x38, 0x3e, 0x0e, 0x13, 0x7c, 0x37, 0xbf, 0xb9, 0xdb, 0x29, 0xf9,
+         0xa8, 0xe4, 0x5e, 0x9f, 0xf8, 0xdd, 0x4c, 0x30, 0xe4, 0x40, 0xfe,
+         0xc2, 0xac, 0xd3, 0xdb, 0xa7, 0xb6, 0xc7, 0x20, 0xb9, 0x93},
+        // cb954e9d80a3e520ac71f1a84511657f2f309d172d0bb55e0ec2c236e74ff4b4.pem
+        {0x39, 0x4c, 0xff, 0x58, 0x9e, 0x68, 0x93, 0x12, 0xcf, 0xc0, 0x71,
+         0xee, 0x0b, 0xc1, 0x9f, 0xe4, 0xc6, 0x06, 0x21, 0x6c, 0xe5, 0x43,
+         0x42, 0x9d, 0xe6, 0xdb, 0x62, 0xe4, 0x2d, 0xbb, 0x3b, 0xc1},
         // 42187727be39faf667aeb92bf0cc4e268f6e2ead2cefbec575bdc90430024f69.pem
         {0x3e, 0xdb, 0xd9, 0xac, 0xe6, 0x39, 0xba, 0x1a, 0x2d, 0x4a, 0xd0,
          0x47, 0x18, 0x71, 0x1f, 0xda, 0x23, 0xe8, 0x59, 0xb2, 0xfb, 0xf5,
@@ -59,6 +87,10 @@
         {0x4b, 0xb8, 0xf3, 0x5b, 0xa1, 0xe1, 0x26, 0xf8, 0xdd, 0xe1, 0xb0,
          0xc4, 0x20, 0x62, 0x5e, 0xd8, 0x6d, 0xce, 0x61, 0xa7, 0xbd, 0xda,
          0xdb, 0xde, 0xa9, 0xab, 0xa5, 0x78, 0xff, 0x13, 0x14, 0x5e},
+        // fa5a828c9a7e732692682e60b14c634309cbb2bb79eb12aef44318d853ee97e3.pem
+        {0x4c, 0xdb, 0x06, 0x0f, 0x3c, 0xfe, 0x4c, 0x3d, 0x3f, 0x5e, 0x31,
+         0xc3, 0x00, 0xfd, 0x68, 0xa9, 0x1e, 0x0d, 0x1e, 0x5f, 0x46, 0xb6,
+         0x4e, 0x48, 0x95, 0xf2, 0x0e, 0x1b, 0x5c, 0xf8, 0x26, 0x9f},
         // 7abd72a323c9d179c722564f4e27a51dd4afd24006b38a40ce918b94960bcf18.pem
         {0x57, 0x80, 0x94, 0x46, 0xea, 0xf1, 0x14, 0x84, 0x38, 0x54, 0xfe,
          0x63, 0x6e, 0xd9, 0xbc, 0xb5, 0x52, 0xe3, 0xc6, 0x16, 0x66, 0x3b,
@@ -89,6 +121,10 @@
         {0x7a, 0xed, 0xdd, 0xf3, 0x6b, 0x18, 0xf8, 0xac, 0xb7, 0x37, 0x9f,
          0xe1, 0xce, 0x18, 0x32, 0x12, 0xb2, 0x35, 0x0d, 0x07, 0x88, 0xab,
          0xe0, 0xe8, 0x24, 0x57, 0xbe, 0x9b, 0xad, 0xad, 0x6d, 0x54},
+        // c43807a64c51a3fbde5421011698013d8b46f4e315c46186dc23aea2670cd34f.pem
+        {0x7c, 0xd2, 0x95, 0xb7, 0x55, 0x44, 0x80, 0x8a, 0xbd, 0x94, 0x09,
+         0x46, 0x6f, 0x08, 0x37, 0xc5, 0xaa, 0xdc, 0x02, 0xe3, 0x3b, 0x61,
+         0x50, 0xc6, 0x64, 0x4d, 0xe0, 0xa0, 0x96, 0x59, 0xf2, 0x3c},
         // f3bae5e9c0adbfbfb6dbf7e04e74be6ead3ca98a5604ffe591cea86c241848ec.pem
         {0x7d, 0x5e, 0x3f, 0x50, 0x50, 0x81, 0x97, 0xb9, 0xa4, 0x78, 0xb1,
          0x13, 0x40, 0xb7, 0xdc, 0xe2, 0x0a, 0x3c, 0x4d, 0xe4, 0x9c, 0x48,
@@ -97,10 +133,26 @@
         {0x7e, 0x70, 0x58, 0xea, 0x35, 0xad, 0x43, 0x59, 0x65, 0x41, 0x59,
          0x97, 0x3f, 0x56, 0x01, 0x87, 0xf1, 0x6d, 0x19, 0xc5, 0x14, 0xb9,
          0x39, 0xc5, 0x05, 0x56, 0x72, 0xd1, 0xd2, 0xa5, 0x18, 0xac},
+        // 5e8e77aafdda2ba5ce442f27d8246650bbd6508befbeda35966a4dc7e6174edc.pem
+        {0x87, 0xbf, 0xd8, 0xaf, 0xa3, 0xaf, 0x5b, 0x42, 0x9d, 0x09, 0xa9,
+         0xaa, 0x54, 0xee, 0x61, 0x36, 0x4f, 0x5a, 0xe1, 0x11, 0x31, 0xe4,
+         0x38, 0xfc, 0x41, 0x09, 0x53, 0x43, 0xcd, 0x16, 0xb1, 0x35},
+        // ddd8ab9178c99cbd9685ea4ae66dc28bfdc9a5a8a166f7f69ad0b5042ad6eb28.pem
+        {0x8f, 0x59, 0x1f, 0x7a, 0xa4, 0xdc, 0x3e, 0xfe, 0x94, 0x90, 0xc3,
+         0x8a, 0x46, 0x92, 0xc9, 0x01, 0x1e, 0xd1, 0x28, 0xf1, 0xde, 0x59,
+         0x55, 0x69, 0x40, 0x6d, 0x77, 0xb6, 0xfa, 0x1f, 0x6b, 0x4c},
         // 450f1b421bb05c8609854884559c323319619e8b06b001ea2dcbb74a23aa3be2.pem
         {0x93, 0xca, 0x2d, 0x43, 0x6c, 0xae, 0x7f, 0x68, 0xd2, 0xb4, 0x25,
          0x6c, 0xa1, 0x75, 0xc9, 0x85, 0xce, 0x39, 0x92, 0x6d, 0xc9, 0xf7,
          0xee, 0xae, 0xec, 0xf2, 0xf8, 0x97, 0x0f, 0xb9, 0x78, 0x02},
+        // e757fd60d8dd4c26f77aca6a87f63ea4d38d0b736c7f79b56cad932d4c400fb5.pem
+        {0x96, 0x2e, 0x4b, 0x54, 0xbb, 0x98, 0xa7, 0xee, 0x5d, 0x5f, 0xeb,
+         0x96, 0x33, 0xf9, 0x91, 0xd3, 0xc3, 0x30, 0x0e, 0x95, 0x14, 0xda,
+         0xde, 0x7b, 0x0d, 0x4f, 0x82, 0x8c, 0x79, 0x4f, 0x8e, 0x87},
+        // 3d3d823fad13dfeef32da580166d4a4992bed5a22d695d12c8b08cc3463c67a2.pem
+        {0x96, 0x8d, 0xba, 0x69, 0xfb, 0xff, 0x15, 0xbf, 0x37, 0x62, 0x08,
+         0x94, 0x31, 0xad, 0xe5, 0xa7, 0xea, 0xd4, 0xb7, 0xea, 0xf1, 0xbe,
+         0x70, 0x02, 0x68, 0x10, 0xbc, 0x57, 0xd1, 0xc6, 0x4f, 0x6e},
         // 1f17f2cbb109f01c885c94d9e74a48625ae9659665d6d7e7bc5a10332976370f.pem
         {0x99, 0xba, 0x47, 0x84, 0xf9, 0xb0, 0x85, 0x12, 0x90, 0x2e, 0xb0,
          0xc3, 0xc8, 0x6d, 0xf0, 0xec, 0x04, 0x9e, 0xac, 0x9b, 0x65, 0xf7,
@@ -109,6 +161,14 @@
         {0x9b, 0x8a, 0x93, 0xde, 0xcc, 0xcf, 0xba, 0xfc, 0xf4, 0xd0, 0x4d,
          0x34, 0x42, 0x12, 0x8f, 0xb3, 0x52, 0x18, 0xcf, 0xe4, 0x37, 0xa3,
          0xd8, 0xd0, 0x32, 0x8c, 0x99, 0xf8, 0x90, 0x89, 0xe4, 0x50},
+        // 2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem
+        {0x9c, 0x35, 0x74, 0x7c, 0x3a, 0x53, 0x5c, 0xf2, 0x13, 0xb1, 0x47,
+         0x4e, 0xdb, 0x39, 0x77, 0xf1, 0x38, 0x24, 0x0d, 0x6d, 0xc1, 0xce,
+         0xcd, 0xee, 0x74, 0x11, 0xa8, 0xf1, 0x25, 0x53, 0xb1, 0x3e},
+        // 8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem
+        {0x9c, 0x59, 0xa3, 0xcc, 0xae, 0xa4, 0x69, 0x98, 0x42, 0xb0, 0x68,
+         0xcf, 0xc5, 0x2c, 0xf9, 0x45, 0xdb, 0x51, 0x98, 0x69, 0x57, 0xc8,
+         0x32, 0xcd, 0xb1, 0x8c, 0xa7, 0x38, 0x49, 0xfb, 0xb9, 0xee},
         // 7d8ce822222b90c0b14342c7a8145d1f24351f4d1a1fe0edfd312ee73fb00149.pem
         {0x9d, 0x98, 0xa1, 0xfb, 0x60, 0x53, 0x8c, 0x4c, 0xc4, 0x85, 0x7f,
          0xf1, 0xa8, 0xc8, 0x03, 0x4f, 0xaf, 0x6f, 0xc5, 0x92, 0x09, 0x3f,
@@ -117,12 +177,24 @@
         {0x9d, 0xd5, 0x5f, 0xc5, 0x73, 0xf5, 0x46, 0xcb, 0x6a, 0x38, 0x31,
          0xd1, 0x11, 0x2d, 0x87, 0x10, 0xa6, 0xf4, 0xf8, 0x2d, 0xc8, 0x7f,
          0x5f, 0xae, 0x9d, 0x3a, 0x1a, 0x02, 0x8d, 0xd3, 0x6e, 0x4b},
+        // 487afc8d0d411b2a05561a2a6f35918f4040e5570c4c73ee323cc50583bcfbb7.pem
+        {0xa0, 0xcf, 0x53, 0xf4, 0x22, 0x65, 0x1e, 0x39, 0x31, 0x7a, 0xe3,
+         0x1a, 0xf6, 0x45, 0x77, 0xbe, 0x45, 0x0f, 0xa3, 0x76, 0xe2, 0x89,
+         0xed, 0x83, 0x42, 0xb7, 0xfc, 0x13, 0x3c, 0x69, 0x74, 0x19},
         // 0d136e439f0ab6e97f3a02a540da9f0641aa554e1d66ea51ae2920d51b2f7217.pem
         // 4fee0163686ecbd65db968e7494f55d84b25486d438e9de558d629d28cd4d176.pem
         // 8a1bd21661c60015065212cc98b1abb50dfd14c872a208e66bae890f25c448af.pem
         {0xa9, 0x03, 0xaf, 0x8c, 0x07, 0xbb, 0x91, 0xb0, 0xd9, 0xe3, 0xf3,
          0xa3, 0x0c, 0x6d, 0x53, 0x33, 0x9f, 0xc5, 0xbd, 0x47, 0xe5, 0xd6,
          0xbd, 0xb4, 0x76, 0x59, 0x88, 0x60, 0xc0, 0x68, 0xa0, 0x24},
+        // a2e3bdaacaaf2d2e8204b3bc7eddc805d54d3ab8bdfe7bf102c035f67d8f898a.pem
+        {0xa9, 0xb5, 0x5a, 0x9b, 0x55, 0x31, 0xbb, 0xf7, 0xc7, 0x1a, 0x1e,
+         0x49, 0x20, 0xef, 0xe7, 0x96, 0xc2, 0xb6, 0x79, 0x68, 0xf5, 0x5a,
+         0x6c, 0xe5, 0xcb, 0x62, 0x17, 0x2e, 0xd9, 0x94, 0x5b, 0xca},
+        // 5472692abe5d02cd22eae3e0a0077f17802721d6576cde1cba2263ee803410c5.pem
+        {0xaf, 0x59, 0x15, 0x18, 0xe2, 0xe6, 0xc6, 0x0e, 0xbb, 0xfc, 0x09,
+         0x07, 0xaf, 0xaa, 0x49, 0xbc, 0x40, 0x51, 0xd4, 0x5e, 0x7f, 0x21,
+         0x4a, 0xbf, 0xee, 0x75, 0x12, 0xee, 0x00, 0xf6, 0x61, 0xed},
         // b8c1b957c077ea76e00b0f45bff5ae3acb696f221d2e062164fe37125e5a8d25.pem
         {0xb3, 0x18, 0x2e, 0x28, 0x9a, 0xe3, 0x4d, 0xdf, 0x2b, 0xe6, 0x43,
          0xab, 0x79, 0xc2, 0x44, 0x30, 0x16, 0x05, 0xfa, 0x0f, 0x1e, 0xaa,
@@ -144,10 +216,18 @@
         {0xc6, 0x01, 0x23, 0x4e, 0x2b, 0x93, 0x25, 0xdc, 0x92, 0xe3, 0xea,
          0xba, 0xc1, 0x96, 0x00, 0xb0, 0xb4, 0x99, 0x47, 0xd4, 0xd0, 0x4d,
          0x8c, 0x99, 0xd3, 0x21, 0x27, 0x49, 0x3e, 0xa0, 0x28, 0xf8},
+        // 53d48e7b8869a3314f213fd2e0178219ca09022dbe50053bf6f76fccd61e8112.pem
+        {0xc8, 0xfd, 0xdc, 0x75, 0xcb, 0x1b, 0xdb, 0xb5, 0x8c, 0x07, 0xb4,
+         0xea, 0x84, 0x72, 0x87, 0xf6, 0x26, 0x65, 0x9d, 0xd6, 0x6b, 0xc1,
+         0x0a, 0x26, 0xad, 0xd9, 0xb5, 0x75, 0xb3, 0xa0, 0xa3, 0x8d},
         // ec30c9c3065a06bb07dc5b1c6b497f370c1ca65c0f30c08e042ba6bcecc78f2c.pem
         {0xcd, 0xee, 0x9f, 0x33, 0x05, 0x57, 0x2a, 0x67, 0x7e, 0x1a, 0x6c,
          0x82, 0xdc, 0x1e, 0x02, 0xa3, 0x5b, 0x11, 0xca, 0xe6, 0xa6, 0x84,
          0x33, 0x8c, 0x9f, 0x37, 0xfe, 0x1a, 0xc8, 0xda, 0xec, 0x23},
+        // c71f33c36d8efeefbed9d44e85e21cfe96b36fb0e132c52dca2415868492bf8a.pem
+        {0xd3, 0x1e, 0xc3, 0x92, 0x85, 0xb7, 0xa5, 0x31, 0x9d, 0x01, 0x57,
+         0xdb, 0x42, 0x0e, 0xd8, 0x7c, 0x74, 0x3e, 0x33, 0x3b, 0xbc, 0x77,
+         0xf8, 0x77, 0x1f, 0x70, 0x46, 0x4f, 0x43, 0x6a, 0x60, 0x49},
         // 9ed8f9b0e8e42a1656b8e1dd18f42ba42dc06fe52686173ba2fc70e756f207dc.pem
         // a686fee577c88ab664d0787ecdfff035f4806f3de418dc9e4d516324fff02083.pem
         // fdedb5bdfcb67411513a61aee5cb5b5d7c52af06028efc996cc1b05b1d6cea2b.pem
@@ -162,6 +242,10 @@
         {0xdb, 0x15, 0xc0, 0x06, 0x2b, 0x52, 0x0f, 0x31, 0x8a, 0x19, 0xda,
          0xcf, 0xec, 0xd6, 0x4f, 0x9e, 0x7a, 0x3f, 0xbe, 0x60, 0x9f, 0xd5,
          0x86, 0x79, 0x6f, 0x20, 0xae, 0x02, 0x8e, 0x8e, 0x30, 0x58},
+        // 2a4397aafa6227fa11f9f9d76ecbb022b0a4494852c2b93fb2085c8afb19b62a.pem
+        {0xdb, 0x1d, 0x13, 0xec, 0x42, 0xa2, 0xcb, 0xa3, 0x67, 0x3b, 0xa6,
+         0x7a, 0xf2, 0xde, 0xf8, 0x12, 0xe9, 0xc3, 0x55, 0x66, 0x61, 0x75,
+         0x76, 0xd9, 0x5b, 0x4d, 0x6f, 0xac, 0xe3, 0xef, 0x0a, 0xe8},
         // 3946901f46b0071e90d78279e82fababca177231a704be72c5b0e8918566ea66.pem
         {0xdd, 0x3e, 0xeb, 0x77, 0x9b, 0xee, 0x07, 0xf9, 0xef, 0xda, 0xc3,
          0x82, 0x40, 0x8b, 0x28, 0xd1, 0x42, 0xfa, 0x84, 0x2c, 0x78, 0xe8,
@@ -183,6 +267,10 @@
         {0xe7, 0xb9, 0x32, 0xae, 0x7e, 0x9b, 0xdc, 0x70, 0x1d, 0x77, 0x1d,
          0x6f, 0x39, 0xe8, 0xa6, 0x53, 0x44, 0x9e, 0xea, 0x43, 0xbd, 0xb4,
          0x7b, 0xd9, 0x10, 0x22, 0x95, 0x0d, 0x91, 0x79, 0xd8, 0x7e},
+        // 5ccaf9f8f2bb3a0d215922eca383354b6ee3c62407ed32e30f6fb2618edeea10.pem
+        {0xe8, 0x49, 0xc7, 0x17, 0x6c, 0x93, 0xdf, 0x65, 0xf6, 0x4b, 0x61,
+         0x69, 0x82, 0x36, 0x6e, 0x56, 0x63, 0x11, 0x78, 0x12, 0xb6, 0xfa,
+         0x2b, 0xc0, 0xc8, 0xfa, 0x8a, 0xea, 0xee, 0x41, 0x81, 0xcc},
         // ea08c8d45d52ca593de524f0513ca6418da9859f7b08ef13ff9dd7bf612d6a37.key
         {0xea, 0x08, 0xc8, 0xd4, 0x5d, 0x52, 0xca, 0x59, 0x3d, 0xe5, 0x24,
          0xf0, 0x51, 0x3c, 0xa6, 0x41, 0x8d, 0xa9, 0x85, 0x9f, 0x7b, 0x08,
@@ -203,6 +291,10 @@
         {0xf3, 0x0e, 0x8f, 0x61, 0x01, 0x1d, 0x65, 0x87, 0x3c, 0xcb, 0x81,
          0xb4, 0x0f, 0xa6, 0x21, 0x97, 0x49, 0xb9, 0x94, 0xf0, 0x1f, 0xa2,
          0x4d, 0x02, 0x01, 0xd5, 0x21, 0xc2, 0x43, 0x56, 0x03, 0xca},
+        // 0d90cd8e35209b4cefebdd62b644bed8eb55c74dddff26e75caf8ae70491f0bd.pem
+        {0xf5, 0x29, 0x3d, 0x47, 0xed, 0x38, 0xd4, 0xc3, 0x1b, 0x2d, 0x42,
+         0xde, 0xe3, 0xb5, 0xb3, 0xac, 0xe9, 0x7c, 0xa2, 0x6c, 0xa2, 0xac,
+         0x03, 0x65, 0xe3, 0x62, 0x2e, 0xe8, 0x02, 0x13, 0x1f, 0xbb},
         // 67ed4b703d15dc555f8c444b3a05a32579cb7599bd19c9babe10c584ea327ae0.pem
         {0xfa, 0x00, 0xbe, 0xc7, 0x3d, 0xd9, 0x97, 0x95, 0xdf, 0x11, 0x62,
          0xc7, 0x89, 0x98, 0x70, 0x04, 0xc2, 0x6c, 0xbf, 0x90, 0xaf, 0x4d,
diff --git a/net/cert/crl_set.cc b/net/cert/crl_set.cc
index 785f6ab1..93d3a16 100644
--- a/net/cert/crl_set.cc
+++ b/net/cert/crl_set.cc
@@ -54,8 +54,8 @@
   const base::StringPiece header_bytes(data->data(), header_len);
   data->remove_prefix(header_len);
 
-  std::unique_ptr<base::Value> header =
-      base::JSONReader::Read(header_bytes, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> header = base::JSONReader::ReadDeprecated(
+      header_bytes, base::JSON_ALLOW_TRAILING_COMMAS);
   if (header.get() == nullptr)
     return nullptr;
 
diff --git a/net/cert/ct_log_response_parser_unittest.cc b/net/cert/ct_log_response_parser_unittest.cc
index 11006ec5..4861cdd 100644
--- a/net/cert/ct_log_response_parser_unittest.cc
+++ b/net/cert/ct_log_response_parser_unittest.cc
@@ -23,7 +23,7 @@
 namespace {
 std::unique_ptr<base::Value> ParseJson(const std::string& json) {
   base::JSONReader json_reader;
-  return json_reader.Read(json);
+  return json_reader.ReadDeprecated(json);
 }
 }
 
diff --git a/net/data/ssl/blacklist/0d90cd8e35209b4cefebdd62b644bed8eb55c74dddff26e75caf8ae70491f0bd.pem b/net/data/ssl/blacklist/0d90cd8e35209b4cefebdd62b644bed8eb55c74dddff26e75caf8ae70491f0bd.pem
new file mode 100644
index 0000000..8fd95519
--- /dev/null
+++ b/net/data/ssl/blacklist/0d90cd8e35209b4cefebdd62b644bed8eb55c74dddff26e75caf8ae70491f0bd.pem
@@ -0,0 +1,109 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            0a:b4:c7:3c:41:3a:01:94:9f:23:78:f2:b2:29:f6:6c
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = "thawte, Inc.", CN = thawte EV SSL CA - G3
+        Validity
+            Not Before: Sep 14 00:00:00 2015 GMT
+            Not After : Sep 15 23:59:59 2015 GMT
+        Subject: jurisdictionC = US, jurisdictionST = Delaware, O = Symantec Corp, businessCategory = Private Organization, serialNumber = 2158113, C = US, ST = California, L = Mountain view, CN = www.google.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:8e:d9:6a:64:8f:6b:e8:d8:71:bf:fd:da:e3:58:
+                    62:35:8c:e0:31:0c:b8:65:27:48:7f:a3:f6:54:04:
+                    3f:4d:23:5c:dc:46:18:eb:5c:1a:f8:e7:99:9e:f9:
+                    20:e4:5f:61:bb:bb:35:28:5b:eb:f9:57:a7:1c:56:
+                    48:fe:74:b3:27:fe:5a:dd:79:36:cb:dc:fa:a0:8b:
+                    14:52:8d:e0:3a:7a:24:77:8e:4c:f8:dd:e9:34:35:
+                    f8:8b:b0:30:3c:f1:dc:78:6e:e7:39:e2:4a:4d:6e:
+                    49:5e:32:a7:25:14:c6:5a:85:f8:28:a8:1f:f5:00:
+                    bb:ac:c9:31:d0:fa:cc:70:80:9d:95:86:df:84:0e:
+                    11:16:36:1d:b4:47:d6:aa:9a:a3:49:cf:af:f5:80:
+                    b6:48:6e:8f:c1:df:a5:aa:38:0a:1f:ed:97:77:7f:
+                    c1:46:f8:3c:a4:67:71:2d:ba:3d:45:fa:64:67:fa:
+                    5e:fd:33:0e:5a:0c:b5:13:bd:fa:66:c9:ab:aa:2d:
+                    29:5a:5b:c1:d4:eb:b6:db:88:f6:fc:dd:89:5f:22:
+                    30:40:65:18:72:59:69:ec:a2:89:35:58:0b:40:ad:
+                    bd:d7:44:ea:8a:91:cc:a0:8a:e9:7f:14:09:1c:41:
+                    2d:b5:2b:f6:2e:c9:28:f6:8b:d4:69:31:0b:b2:4c:
+                    e1:bf
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                DNS:www.google.com, DNS:google.com
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://ti.symcb.com/ti.crl
+
+            X509v3 Certificate Policies: 
+                Policy: 2.16.840.1.113733.1.7.48.1
+                  CPS: https://www.thawte.com/cps
+                  User Notice:
+                    Explicit Text: https://www.thawte.com/repository
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Authority Key Identifier: 
+                keyid:F0:70:51:DA:D3:2A:91:4F:52:77:D7:86:77:74:0F:CE:71:1A:6C:22
+
+            Authority Information Access: 
+                OCSP - URI:http://ti.symcd.com
+                CA Issuers - URI:http://ti.symcb.com/ti.crt
+
+            CT Precertificate Poison: critical
+                NULL
+    Signature Algorithm: sha256WithRSAEncryption
+         8b:08:d4:31:46:6a:cc:14:77:a2:f1:57:3d:de:18:75:ec:dd:
+         8a:99:f3:fe:e0:da:95:01:f3:94:0f:65:57:73:0a:bf:4e:63:
+         3e:41:c2:2b:b9:89:7a:c1:b4:d6:05:77:85:52:db:fa:46:a2:
+         1d:d0:29:01:23:18:d4:c4:a8:98:cf:85:04:e5:31:be:ca:91:
+         67:24:55:63:77:31:52:4a:09:92:12:72:b2:32:55:ee:c1:57:
+         e1:c0:7d:bd:78:7c:7d:db:10:11:f6:56:3c:fd:5f:94:9b:df:
+         fe:ce:54:5c:b3:7b:65:ae:6e:c2:bb:ea:c5:2a:6e:a4:5f:cc:
+         69:f4:65:d5:b4:e5:4d:e2:a0:b0:25:e3:90:2b:51:21:89:8c:
+         a7:87:17:2e:07:d0:bb:5c:cd:88:d1:2b:34:3a:6c:25:2e:a0:
+         4c:b9:ae:1e:61:8d:f2:11:c4:25:59:38:11:9e:58:db:0c:5b:
+         d1:7c:47:f7:c3:39:fb:a2:24:52:f4:90:8b:24:bb:94:2e:44:
+         57:cd:55:58:4d:cf:45:c5:9a:b2:58:8a:63:36:57:c1:3c:e4:
+         08:ec:c9:61:c2:77:3f:d3:14:e5:f9:cc:00:1a:41:64:bb:cc:
+         c5:49:a6:cc:bc:27:07:1d:e4:81:c9:79:40:07:55:c0:4e:6f:
+         c0:1f:59:a4
+-----BEGIN CERTIFICATE-----
+MIIFMzCCBBugAwIBAgIQCrTHPEE6AZSfI3jysin2bDANBgkqhkiG9w0BAQsFADBE
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMR4wHAYDVQQDExV0
+aGF3dGUgRVYgU1NMIENBIC0gRzMwHhcNMTUwOTE0MDAwMDAwWhcNMTUwOTE1MjM1
+OTU5WjCBzDETMBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysGAQQBgjc8AgECDAhE
+ZWxhd2FyZTEWMBQGA1UECgwNU3ltYW50ZWMgQ29ycDEdMBsGA1UEDxMUUHJpdmF0
+ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzIxNTgxMTMxCzAJBgNVBAYTAlVTMRMw
+EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiB2aWV3MRcwFQYD
+VQQDDA53d3cuZ29vZ2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAI7ZamSPa+jYcb/92uNYYjWM4DEMuGUnSH+j9lQEP00jXNxGGOtcGvjnmZ75
+IORfYbu7NShb6/lXpxxWSP50syf+Wt15Nsvc+qCLFFKN4Dp6JHeOTPjd6TQ1+Iuw
+MDzx3Hhu5zniSk1uSV4ypyUUxlqF+CioH/UAu6zJMdD6zHCAnZWG34QOERY2HbRH
+1qqao0nPr/WAtkhuj8Hfpao4Ch/tl3d/wUb4PKRncS26PUX6ZGf6Xv0zDloMtRO9
++mbJq6otKVpbwdTrttuI9vzdiV8iMEBlGHJZaeyiiTVYC0CtvddE6oqRzKCK6X8U
+CRxBLbUr9i7JKPaL1GkxC7JM4b8CAwEAAaOCAZYwggGSMCUGA1UdEQQeMByCDnd3
+dy5nb29nbGUuY29tggpnb29nbGUuY29tMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQD
+AgWgMCsGA1UdHwQkMCIwIKAeoByGGmh0dHA6Ly90aS5zeW1jYi5jb20vdGkuY3Js
+MHMGA1UdIARsMGowaAYLYIZIAYb4RQEHMAEwWTAmBggrBgEFBQcCARYaaHR0cHM6
+Ly93d3cudGhhd3RlLmNvbS9jcHMwLwYIKwYBBQUHAgIwIwwhaHR0cHM6Ly93d3cu
+dGhhd3RlLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
+BQcDAjAfBgNVHSMEGDAWgBTwcFHa0yqRT1J314Z3dA/OcRpsIjBXBggrBgEFBQcB
+AQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly90aS5zeW1jZC5jb20wJgYIKwYBBQUH
+MAKGGmh0dHA6Ly90aS5zeW1jYi5jb20vdGkuY3J0MBMGCisGAQQB1nkCBAMBAf8E
+AgUAMA0GCSqGSIb3DQEBCwUAA4IBAQCLCNQxRmrMFHei8Vc93hh17N2KmfP+4NqV
+AfOUD2VXcwq/TmM+QcIruYl6wbTWBXeFUtv6RqId0CkBIxjUxKiYz4UE5TG+ypFn
+JFVjdzFSSgmSEnKyMlXuwVfhwH29eHx92xAR9lY8/V+Um9/+zlRcs3tlrm7Cu+rF
+Km6kX8xp9GXVtOVN4qCwJeOQK1EhiYynhxcuB9C7XM2I0Ss0OmwlLqBMua4eYY3y
+EcQlWTgRnljbDFvRfEf3wzn7oiRS9JCLJLuULkRXzVVYTc9FxZqyWIpjNlfBPOQI
+7Mlhwnc/0xTl+cwAGkFku8zFSabMvCcHHeSByXlAB1XATm/AH1mk
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/0ef7c54a3af101a2cfedb0c9f36fe8214d51a504fdc2ad1e243019cefd7d03c2.pem b/net/data/ssl/blacklist/0ef7c54a3af101a2cfedb0c9f36fe8214d51a504fdc2ad1e243019cefd7d03c2.pem
new file mode 100644
index 0000000..7396450
--- /dev/null
+++ b/net/data/ssl/blacklist/0ef7c54a3af101a2cfedb0c9f36fe8214d51a504fdc2ad1e243019cefd7d03c2.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:28:cd:43:87:67:18:3d:c5:0f:a5:8b:e6:06:2b:62:bb:bb
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 12:36:35 2017 GMT
+            Not After : Jan 30 12:36:35 2018 GMT
+        Subject: CN = youtube.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c7:ed:b4:18:06:59:3d:1b:ff:e0:76:20:ea:49:
+                    21:68:5a:cc:ea:90:83:be:33:cb:d3:c8:c7:91:0b:
+                    91:b8:57:48:e8:f4:b2:4f:95:a1:5e:9d:fe:b1:74:
+                    28:45:5f:cf:8d:29:b9:87:df:53:a3:35:a2:57:4b:
+                    8b:fa:22:11:be:8d:06:27:66:1c:ff:63:80:80:62:
+                    c8:62:cc:f4:34:14:64:b9:5d:aa:57:44:68:98:48:
+                    48:5a:88:bd:16:9f:ba:05:16:13:75:31:68:6a:00:
+                    bf:c4:f6:df:fc:49:2a:47:03:4e:20:ed:e3:59:8e:
+                    61:d3:f3:3f:a0:85:98:4a:5b:b3:75:7d:d8:cf:32:
+                    e7:2c:4e:af:81:3e:6b:10:aa:b5:ac:ae:52:d5:92:
+                    57:be:f6:d9:35:69:44:7b:d6:01:60:33:a7:93:92:
+                    9b:75:22:36:0e:5c:22:bf:01:8c:d6:a6:11:15:38:
+                    b9:42:52:e9:d5:25:5a:d0:65:e8:88:f0:59:f4:0e:
+                    22:54:65:c6:36:7a:0e:09:1b:ee:ac:a9:c1:e1:51:
+                    ed:e1:f0:20:f3:a9:6a:04:4c:26:1d:b8:16:a2:61:
+                    7e:13:5e:bc:a1:12:6d:a4:0d:ca:18:0d:50:62:e4:
+                    ef:1e:8e:d5:1a:b4:1e:76:7e:79:2b:66:aa:4b:86:
+                    29:31
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                1B:BC:2B:E0:3D:5B:74:8A:E0:52:12:A5:A7:11:1C:86:02:B7:A6:F9
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:cpanel.youtube.tg, DNS:mail.youtube.tg, DNS:webdisk.youtube.tg, DNS:webmail.youtube.tg, DNS:www.youtube.tg, DNS:youtube.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         7c:86:f3:c4:57:78:b5:54:6a:5c:88:00:e1:b6:c1:33:34:33:
+         34:56:9b:d1:86:88:34:c3:09:eb:37:a4:08:bb:4b:ad:4c:4f:
+         f1:44:84:eb:cd:64:77:71:4b:1f:81:b4:1b:6b:7e:08:bb:ee:
+         74:ad:17:b5:11:a2:ba:20:b5:8a:ce:76:9e:76:12:0e:af:5a:
+         d8:f8:d7:08:2d:ae:9a:53:6b:f3:2e:44:6e:0b:a9:c9:2a:e1:
+         30:28:7f:bd:3c:de:cd:47:8b:98:22:d3:5c:32:ab:f1:fd:66:
+         9b:0f:e6:3e:97:90:35:c4:40:13:73:98:ad:ee:20:a7:2e:84:
+         0a:92:d5:2b:70:f0:3a:a5:47:ac:d3:48:85:8e:50:d4:22:71:
+         1e:08:13:89:dc:05:6a:d7:e9:a7:3d:f8:50:dd:09:ea:80:f8:
+         ac:2e:f7:e0:f0:ef:a9:2f:ee:31:dc:f9:4b:67:ff:16:49:91:
+         f7:71:cc:3b:3a:b6:55:54:0b:1e:fc:4d:38:ad:19:c9:73:e5:
+         45:0a:1f:16:b9:fb:7d:3a:6d:95:c5:75:3b:8f:63:46:37:1f:
+         8e:31:97:41:d6:bc:3c:89:06:d6:d2:c2:5f:8d:3b:bc:8a:72:
+         6c:8d:1f:22:ae:ad:5e:c8:e9:2f:f8:09:4a:d8:ff:a9:14:41:
+         30:ab:08:41
+-----BEGIN CERTIFICATE-----
+MIIFUzCCBDugAwIBAgISAyjNQ4dnGD3FD6WL5gYrYru7MA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMjM2MzVaFw0x
+ODAxMzAxMjM2MzVaMBUxEzARBgNVBAMTCnlvdXR1YmUudGcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDH7bQYBlk9G//gdiDqSSFoWszqkIO+M8vTyMeR
+C5G4V0jo9LJPlaFenf6xdChFX8+NKbmH31OjNaJXS4v6IhG+jQYnZhz/Y4CAYshi
+zPQ0FGS5XapXRGiYSEhaiL0Wn7oFFhN1MWhqAL/E9t/8SSpHA04g7eNZjmHT8z+g
+hZhKW7N1fdjPMucsTq+BPmsQqrWsrlLVkle+9tk1aUR71gFgM6eTkpt1IjYOXCK/
+AYzWphEVOLlCUunVJVrQZeiI8Fn0DiJUZcY2eg4JG+6sqcHhUe3h8CDzqWoETCYd
+uBaiYX4TXryhEm2kDcoYDVBi5O8ejtUatB52fnkrZqpLhikxAgMBAAGjggJmMIIC
+YjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
+MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBu8K+A9W3SK4FISpacRHIYCt6b5MB8G
+A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAu
+BggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAv
+BggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
+cQYDVR0RBGowaIIRY3BhbmVsLnlvdXR1YmUudGeCD21haWwueW91dHViZS50Z4IS
+d2ViZGlzay55b3V0dWJlLnRnghJ3ZWJtYWlsLnlvdXR1YmUudGeCDnd3dy55b3V0
+dWJlLnRnggp5b3V0dWJlLnRnMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsr
+BgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlw
+dC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25s
+eSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4g
+YWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQg
+aHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEL
+BQADggEBAHyG88RXeLVUalyIAOG2wTM0MzRWm9GGiDTDCes3pAi7S61MT/FEhOvN
+ZHdxSx+BtBtrfgi77nStF7URorogtYrOdp52Eg6vWtj41wgtrppTa/MuRG4Lqckq
+4TAof7083s1Hi5gi01wyq/H9ZpsP5j6XkDXEQBNzmK3uIKcuhAqS1Stw8DqlR6zT
+SIWOUNQicR4IE4ncBWrX6ac9+FDdCeqA+Kwu9+Dw76kv7jHc+Utn/xZJkfdxzDs6
+tlVUCx78TTitGclz5UUKHxa5+306bZXFdTuPY0Y3H44xl0HWvDyJBtbSwl+NO7yK
+cmyNHyKurV7I6S/4CUrY/6kUQTCrCEE=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/2740d956b1127b791aa1b3cc644a4dbedba76186a23638b95102351a834ea861.pem b/net/data/ssl/blacklist/2740d956b1127b791aa1b3cc644a4dbedba76186a23638b95102351a834ea861.pem
new file mode 100644
index 0000000..4e86de36
--- /dev/null
+++ b/net/data/ssl/blacklist/2740d956b1127b791aa1b3cc644a4dbedba76186a23638b95102351a834ea861.pem
@@ -0,0 +1,102 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1228079246 (0x4933008e)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = CN, O = CNNIC, CN = CNNIC ROOT
+        Validity
+            Not Before: Mar 19 06:20:09 2015 GMT
+            Not After : Apr  3 06:20:09 2015 GMT
+        Subject: C = EG, O = MCSHOLDING, CN = MCSHOLDING TEST
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:a5:f9:75:0c:06:ae:ee:0c:11:cd:96:33:4d:6b:
+                    ce:c0:4a:0c:3d:5d:eb:d2:4b:09:7f:e7:47:2c:ac:
+                    71:00:f9:08:af:34:f1:a3:6a:c7:fc:e6:ab:ce:d0:
+                    be:ca:cd:2a:98:98:b9:d0:8e:33:49:07:61:20:d1:
+                    5a:34:ce:83:14:06:79:8e:1a:bf:db:e4:a0:38:3a:
+                    ee:94:b9:a3:a0:58:3a:89:14:ac:60:3e:03:d4:c7:
+                    cd:3b:1c:b0:9a:88:1a:49:10:a9:b0:b2:fd:e5:e8:
+                    e1:04:e2:ea:82:6d:fe:0c:51:45:91:ad:75:22:ae:
+                    ff:4f:90:0b:c0:53:65:77:3e:1e:c2:56:b5:36:c6:
+                    d6:85:cc:0e:83:1a:33:1f:76:99:5b:2b:97:2b:8b:
+                    d7:d1:14:15:4c:9d:59:d7:80:2f:a4:a2:85:d5:88:
+                    36:02:60:55:ca:58:df:93:fc:4a:62:07:96:d3:c4:
+                    fa:bf:8d:01:27:97:2f:a6:5c:74:f1:3a:42:6e:5d:
+                    79:14:30:31:1a:3c:d9:b2:57:4d:e0:b8:3f:0f:69:
+                    31:a2:9d:65:99:d9:d6:31:87:b5:98:26:df:f0:cb:
+                    bb:15:c0:24:13:62:52:1a:6b:cb:45:07:97:e3:c4:
+                    94:5e:c9:0d:47:2c:e9:cf:e9:f4:8f:fe:35:e1:32:
+                    e7:31
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            Authority Information Access: 
+                OCSP - URI:http://ocspcnnicroot.cnnic.cn
+                CA Issuers - URI:http://www.cnnic.cn/download/cert/CNNICROOT.cer
+
+            X509v3 Authority Key Identifier: 
+                keyid:65:F2:31:AD:2A:F7:F7:DD:52:96:0A:C7:02:C1:0E:EF:A6:D5:3B:11
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Certificate Policies: 
+                Policy: 1.3.6.1.4.1.29836.1.6
+                  CPS: http://www.cnnic.cn/cps/
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  DirName:C = CN, O = CNNIC, OU = crl, CN = crl1
+
+                Full Name:
+                  URI:http://crl.cnnic.cn/download/rootsha2crl/CRL1.crl
+
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                44:A4:89:AB:14:5F:3D:6F:20:3C:AA:7C:FA:19:AE:F4:48:60:05:B5
+    Signature Algorithm: sha256WithRSAEncryption
+         5c:b4:f5:53:9b:4f:b9:e0:84:89:31:be:9e:2e:ea:9e:21:4b:
+         a5:8f:6d:a1:a6:f3:2f:48:eb:e9:db:ad:1e:31:80:d0:79:3b:
+         10:ef:9a:24:f7:93:1b:35:f3:1a:c2:c7:c2:2c:0a:7f:6f:5b:
+         f1:5f:73:91:04:fb:0d:79:0d:e9:1a:06:d6:83:fd:4e:60:9d:
+         6c:92:43:4c:ea:64:98:44:ab:d7:fb:47:d0:af:1f:64:4c:e2:
+         dd:77:68:16:c2:2c:a1:a0:81:97:00:42:1f:7e:20:78:e8:c6:
+         50:1d:0b:7f:15:93:59:58:40:14:84:f0:a7:90:6b:36:05:67:
+         ea:7f:22:6d:bb:d1:a5:26:4d:b3:30:a4:58:d4:5b:b5:1a:8c:
+         50:8c:b8:0d:e1:a0:07:b3:0f:58:ce:d7:05:b5:7d:35:79:6f:
+         a2:db:0c:00:2a:68:24:8c:7e:9c:c1:76:49:ba:7c:66:11:de:
+         f2:47:ce:fe:d0:ce:55:be:08:da:f2:79:26:2a:15:39:ce:6b:
+         18:a6:df:d8:87:28:99:94:0e:2d:68:a1:9a:ce:52:36:9c:2b:
+         ec:b4:68:b3:6c:15:ac:cb:70:42:f2:c4:41:a5:c8:fc:21:78:
+         53:77:32:20:a9:21:4c:72:e2:d3:b2:c9:76:1b:18:58:42:0b:
+         42:92:b3:e4
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgIESTMAjjANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJD
+TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMTUwMzE5
+MDYyMDA5WhcNMTUwNDAzMDYyMDA5WjA8MQswCQYDVQQGEwJFRzETMBEGA1UECgwK
+TUNTSE9MRElORzEYMBYGA1UEAwwPTUNTSE9MRElORyBURVNUMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfl1DAau7gwRzZYzTWvOwEoMPV3r0ksJf+dH
+LKxxAPkIrzTxo2rH/OarztC+ys0qmJi50I4zSQdhINFaNM6DFAZ5jhq/2+SgODru
+lLmjoFg6iRSsYD4D1MfNOxywmogaSRCpsLL95ejhBOLqgm3+DFFFka11Iq7/T5AL
+wFNldz4ewla1NsbWhcwOgxozH3aZWyuXK4vX0RQVTJ1Z14AvpKKF1Yg2AmBVyljf
+k/xKYgeW08T6v40BJ5cvplx08TpCbl15FDAxGjzZsldN4Lg/D2kxop1lmdnWMYe1
+mCbf8Mu7FcAkE2JSGmvLRQeX48SUXskNRyzpz+n0j/414TLnMQIDAQABo4IBpDCC
+AaAwdgYIKwYBBQUHAQEEajBoMCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcGNubmlj
+cm9vdC5jbm5pYy5jbjA7BggrBgEFBQcwAoYvaHR0cDovL3d3dy5jbm5pYy5jbi9k
+b3dubG9hZC9jZXJ0L0NOTklDUk9PVC5jZXIwHwYDVR0jBBgwFoAUZfIxrSr3991S
+lgrHAsEO76bVOxEwDwYDVR0TAQH/BAUwAwEB/zA/BgNVHSAEODA2MDQGCisGAQQB
+gekMAQYwJjAkBggrBgEFBQcCARYYaHR0cDovL3d3dy5jbm5pYy5jbi9jcHMvMIGG
+BgNVHR8EfzB9MEKgQKA+pDwwOjELMAkGA1UEBhMCQ04xDjAMBgNVBAoMBUNOTklD
+MQwwCgYDVQQLDANjcmwxDTALBgNVBAMMBGNybDEwN6A1oDOGMWh0dHA6Ly9jcmwu
+Y25uaWMuY24vZG93bmxvYWQvcm9vdHNoYTJjcmwvQ1JMMS5jcmwwCwYDVR0PBAQD
+AgEGMB0GA1UdDgQWBBREpImrFF89byA8qnz6Ga70SGAFtTANBgkqhkiG9w0BAQsF
+AAOCAQEAXLT1U5tPueCEiTG+ni7qniFLpY9toabzL0jr6dutHjGA0Hk7EO+aJPeT
+GzXzGsLHwiwKf29b8V9zkQT7DXkN6RoG1oP9TmCdbJJDTOpkmESr1/tH0K8fZEzi
+3XdoFsIsoaCBlwBCH34geOjGUB0LfxWTWVhAFITwp5BrNgVn6n8ibbvRpSZNszCk
+WNRbtRqMUIy4DeGgB7MPWM7XBbV9NXlvotsMACpoJIx+nMF2Sbp8ZhHe8kfO/tDO
+Vb4I2vJ5JioVOc5rGKbf2IcomZQOLWihms5SNpwr7LRos2wVrMtwQvLEQaXI/CF4
+U3cyIKkhTHLi07LJdhsYWEILQpKz5A==
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/2a4397aafa6227fa11f9f9d76ecbb022b0a4494852c2b93fb2085c8afb19b62a.pem b/net/data/ssl/blacklist/2a4397aafa6227fa11f9f9d76ecbb022b0a4494852c2b93fb2085c8afb19b62a.pem
new file mode 100644
index 0000000..fcf4cc1
--- /dev/null
+++ b/net/data/ssl/blacklist/2a4397aafa6227fa11f9f9d76ecbb022b0a4494852c2b93fb2085c8afb19b62a.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:74:d6:03:90:32:97:1c:34:c7:c6:d5:be:b9:94:48:d2:5d
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 12:27:08 2017 GMT
+            Not After : Jan 30 12:27:08 2018 GMT
+        Subject: CN = youtube.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:bf:26:b2:11:c8:9e:97:23:2e:a3:08:02:87:ea:
+                    7b:97:66:f2:9e:72:8f:a3:12:19:14:1c:20:51:5b:
+                    7b:a3:34:1f:af:22:f6:33:b8:83:ba:98:4a:d9:01:
+                    a7:a5:2e:d2:cf:eb:da:8a:46:cf:da:3f:a6:19:65:
+                    2c:fe:6c:6c:e0:0d:66:01:8f:3d:de:11:3f:d5:7e:
+                    c8:ce:a6:f8:4d:6e:3e:9a:88:b3:ed:3d:e9:1e:13:
+                    9e:39:e5:6c:64:10:eb:83:01:33:d5:4f:20:48:65:
+                    0d:a5:ba:dc:f4:48:8a:66:e7:97:f7:9d:2d:be:15:
+                    79:58:08:b6:de:3e:a8:86:8e:0c:81:9d:4b:09:04:
+                    81:ec:bf:34:dc:48:a1:a4:3f:94:18:b2:7e:91:5e:
+                    55:30:81:9a:24:1f:98:fd:e3:15:d3:e8:4a:31:8c:
+                    0d:52:85:95:3e:0e:89:51:82:d9:23:5a:75:07:39:
+                    ce:22:1a:88:c6:1c:ef:05:b0:c6:23:5e:de:b6:c7:
+                    86:03:8e:b1:34:24:8f:79:dd:a3:0d:9b:51:36:7b:
+                    7a:3c:93:43:4d:16:c5:dd:79:51:8e:be:f7:64:e9:
+                    d6:fe:5c:b2:83:58:9f:a6:a7:a6:73:5b:5d:16:47:
+                    e4:e4:fa:48:03:4c:3a:ef:cc:1e:18:aa:34:25:30:
+                    1a:9f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                E8:85:84:9C:8D:5B:AE:2A:5F:FA:42:AA:8D:A7:FB:F6:13:7C:84:C7
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:cpanel.youtube.tg, DNS:mail.youtube.tg, DNS:webmail.youtube.tg, DNS:www.youtube.tg, DNS:youtube.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         14:fd:1f:03:07:4e:a8:33:4d:e2:bf:36:43:3a:20:f5:22:54:
+         ff:3a:2b:17:70:9b:d2:b3:ea:0e:6f:c1:e8:93:a5:0d:4e:5d:
+         ae:6a:08:3b:cd:70:b4:9b:ab:b4:fd:c8:eb:38:58:52:da:d8:
+         52:5a:ad:f5:49:af:8f:8b:ac:ff:c3:c6:e1:29:f9:f3:fd:6e:
+         71:40:28:bd:cf:94:9e:d8:c2:6c:67:2f:7e:d6:54:22:5b:62:
+         07:7a:21:bc:06:ac:93:82:2a:1c:d5:92:25:b9:86:75:6d:4f:
+         8b:fc:e1:fa:e4:84:fa:6a:5e:22:eb:7e:91:88:74:0e:47:7d:
+         ee:c0:05:b4:39:65:2a:03:4c:66:1a:5e:ef:9a:88:cd:72:69:
+         71:87:b7:57:f3:05:af:90:87:60:89:1e:30:a2:9b:04:47:a6:
+         bf:a7:f5:d0:bf:21:7c:74:fd:50:0d:2d:7c:e0:2d:04:1d:20:
+         f6:7f:96:79:7e:02:e5:5f:28:29:2d:a0:15:eb:50:4b:5e:56:
+         0f:34:f9:3d:9e:00:5c:59:49:62:7d:ba:ed:b3:84:0c:8d:99:
+         62:08:fe:5a:42:b1:21:c8:e1:8f:98:5b:2f:6e:da:ff:c4:f6:
+         a6:e8:7c:67:9c:e9:0f:7f:46:e5:3a:4e:57:9e:c5:2d:a0:96:
+         25:98:82:00
+-----BEGIN CERTIFICATE-----
+MIIFPzCCBCegAwIBAgISA3TWA5Aylxw0x8bVvrmUSNJdMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMjI3MDhaFw0x
+ODAxMzAxMjI3MDhaMBUxEzARBgNVBAMTCnlvdXR1YmUudGcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC/JrIRyJ6XIy6jCAKH6nuXZvKeco+jEhkUHCBR
+W3ujNB+vIvYzuIO6mErZAaelLtLP69qKRs/aP6YZZSz+bGzgDWYBjz3eET/VfsjO
+pvhNbj6aiLPtPekeE5455WxkEOuDATPVTyBIZQ2lutz0SIpm55f3nS2+FXlYCLbe
+PqiGjgyBnUsJBIHsvzTcSKGkP5QYsn6RXlUwgZokH5j94xXT6EoxjA1ShZU+DolR
+gtkjWnUHOc4iGojGHO8FsMYjXt62x4YDjrE0JI953aMNm1E2e3o8k0NNFsXdeVGO
+vvdk6db+XLKDWJ+mp6ZzW10WR+Tk+kgDTDrvzB4YqjQlMBqfAgMBAAGjggJSMIIC
+TjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
+MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOiFhJyNW64qX/pCqo2n+/YTfITHMB8G
+A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAu
+BggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAv
+BggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
+XQYDVR0RBFYwVIIRY3BhbmVsLnlvdXR1YmUudGeCD21haWwueW91dHViZS50Z4IS
+d2VibWFpbC55b3V0dWJlLnRngg53d3cueW91dHViZS50Z4IKeW91dHViZS50ZzCB
+/gYDVR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYB
+BQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCB
+ngyBm1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkg
+UmVseWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUg
+Q2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQu
+b3JnL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAU/R8DB06oM03ivzZD
+OiD1IlT/OisXcJvSs+oOb8Hok6UNTl2uagg7zXC0m6u0/cjrOFhS2thSWq31Sa+P
+i6z/w8bhKfnz/W5xQCi9z5Se2MJsZy9+1lQiW2IHeiG8BqyTgioc1ZIluYZ1bU+L
+/OH65IT6al4i636RiHQOR33uwAW0OWUqA0xmGl7vmojNcmlxh7dX8wWvkIdgiR4w
+opsER6a/p/XQvyF8dP1QDS184C0EHSD2f5Z5fgLlXygpLaAV61BLXlYPNPk9ngBc
+WUlifbrts4QMjZliCP5aQrEhyOGPmFsvbtr/xPam6HxnnOkPf0blOk5XnsUtoJYl
+mIIA
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem b/net/data/ssl/blacklist/2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem
new file mode 100644
index 0000000..03544516
--- /dev/null
+++ b/net/data/ssl/blacklist/2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem
@@ -0,0 +1,156 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            01:af:1e:fb:dd:5e:ae:09:52:32:0b:24:fe:6b:55:68
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
+        Validity
+            Not Before: Sep  2 00:00:00 2016 GMT
+            Not After : Sep 11 12:00:00 2019 GMT
+        Subject: C = US, ST = California, L = Walnut Creek, O = Lucas Garron, CN = revoked.badssl.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c7:31:65:e4:55:cf:69:90:9f:6e:1f:d8:6a:13:
+                    7e:74:bf:13:3a:54:64:0f:74:24:3d:dc:60:b8:a7:
+                    45:01:b7:c8:6a:03:ac:64:4a:65:f0:7c:81:81:83:
+                    0a:d9:dd:31:20:82:48:a6:33:63:ee:2b:74:ea:b4:
+                    e6:c7:1c:b2:5e:e4:28:3a:7a:3d:20:19:03:b7:15:
+                    3f:4f:c9:26:ec:b7:cb:bf:48:6e:5f:34:70:56:c4:
+                    86:c7:e3:52:9a:21:33:2f:10:13:f3:25:0c:1e:94:
+                    35:2e:e8:d0:d1:b5:a0:77:40:91:2e:e9:ba:f8:ff:
+                    4e:f5:fb:f2:7a:04:a7:e6:c6:ce:3f:0f:10:18:32:
+                    c8:06:bc:15:b3:be:69:ac:75:7d:42:a0:8c:2e:c3:
+                    ac:e1:20:4f:1e:36:9c:9a:2e:a2:fd:79:80:b6:62:
+                    f8:c0:b2:03:a9:29:50:cc:d5:25:8a:33:5e:e0:78:
+                    13:18:c0:80:17:09:95:bd:a2:fe:92:15:07:20:7a:
+                    81:ce:db:0e:81:29:89:d4:c8:ec:b3:b3:79:0e:f2:
+                    ce:25:e7:ee:be:21:7d:af:0c:13:94:29:de:35:9a:
+                    1e:d8:84:18:5a:5c:1a:94:82:ce:9a:61:d6:9d:ec:
+                    f8:ee:ad:3f:09:5b:73:ec:a2:9b:fa:dc:62:f1:58:
+                    1f:7d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Authority Key Identifier: 
+                keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
+
+            X509v3 Subject Key Identifier: 
+                F4:48:7D:07:45:1A:32:07:90:91:AC:05:B8:9F:A9:11:F0:7E:11:36
+            X509v3 Subject Alternative Name: 
+                DNS:revoked.badssl.com
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crl3.digicert.com/ssca-sha2-g5.crl
+
+                Full Name:
+                  URI:http://crl4.digicert.com/ssca-sha2-g5.crl
+
+            X509v3 Certificate Policies: 
+                Policy: 2.16.840.1.114412.1.1
+                  CPS: https://www.digicert.com/CPS
+                Policy: 2.23.140.1.2.3
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.digicert.com
+                CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            CT Precertificate SCTs: 
+                Signed Certificate Timestamp:
+                    Version   : v1 (0x0)
+                    Log ID    : A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:
+                                3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10
+                    Timestamp : Sep  2 20:40:03.802 2016 GMT
+                    Extensions: none
+                    Signature : ecdsa-with-SHA256
+                                30:44:02:20:3F:6C:A8:F5:C4:7C:01:4C:C3:5A:28:27:
+                                50:47:63:D9:AC:E1:BE:2D:BF:87:78:CB:3A:80:97:24:
+                                74:CD:16:F7:02:20:71:FF:93:A2:B5:54:7E:7F:53:45:
+                                7F:59:5A:60:18:21:5C:AB:7D:1F:08:B2:54:A0:B3:C4:
+                                88:A5:83:D2:63:55
+                Signed Certificate Timestamp:
+                    Version   : v1 (0x0)
+                    Log ID    : 68:F6:98:F8:1F:64:82:BE:3A:8C:EE:B9:28:1D:4C:FC:
+                                71:51:5D:67:93:D4:44:D1:0A:67:AC:BB:4F:4F:FB:C4
+                    Timestamp : Sep  2 20:40:03.745 2016 GMT
+                    Extensions: none
+                    Signature : ecdsa-with-SHA256
+                                30:46:02:21:00:FE:59:97:22:4C:6C:0F:39:05:D9:E4:
+                                CA:7E:3B:D3:B3:47:1B:61:72:B6:3A:4F:D6:F2:A3:57:
+                                49:48:4F:6A:6D:02:21:00:8F:14:1B:3C:1B:89:A3:1D:
+                                70:EC:D4:D7:11:BC:F9:0B:3C:60:AC:8C:84:73:24:6B:
+                                0E:37:6E:53:7F:9D:7F:34
+                Signed Certificate Timestamp:
+                    Version   : v1 (0x0)
+                    Log ID    : 56:14:06:9A:2F:D7:C2:EC:D3:F5:E1:BD:44:B2:3E:C7:
+                                46:76:B9:BC:99:11:5C:C0:EF:94:98:55:D6:89:D0:DD
+                    Timestamp : Sep  2 20:40:03.967 2016 GMT
+                    Extensions: none
+                    Signature : ecdsa-with-SHA256
+                                30:45:02:20:0E:BF:53:59:17:0C:EC:66:0C:5E:87:BB:
+                                8F:5F:B6:76:86:F2:5C:FC:BC:A8:B9:C0:DF:BC:1A:3B:
+                                EE:11:F2:D0:02:21:00:87:25:39:E4:32:99:48:CA:20:
+                                1B:13:96:1D:C3:2C:98:6B:1B:C0:CC:E5:67:22:BD:92:
+                                14:E9:68:CD:95:82:32
+    Signature Algorithm: sha256WithRSAEncryption
+         5a:a0:49:88:ad:60:1f:08:53:4c:d9:b8:dc:f5:40:41:ad:ef:
+         c8:7b:01:3b:13:70:44:99:f6:5c:23:46:f7:3a:c8:7d:c9:21:
+         ad:3a:49:45:82:1e:5d:3b:1e:9b:6a:0a:3e:61:2d:f6:b1:99:
+         74:2f:91:f9:d5:f1:9f:ae:74:26:8b:3c:a7:8c:be:28:fe:ac:
+         3b:70:ae:08:56:71:ac:55:7c:40:89:02:2d:61:2a:fd:54:72:
+         bf:1a:5c:70:19:90:15:a4:76:a0:7f:56:1c:c1:f0:8d:5e:99:
+         3d:83:41:54:68:e5:62:c1:5a:a2:64:8c:01:64:7a:23:b9:3f:
+         bf:22:cf:1f:c0:47:80:1f:94:d5:f2:30:84:fb:07:02:fa:5b:
+         a0:ba:09:04:98:4e:f3:25:56:4c:c4:7e:e0:27:d8:e8:32:8f:
+         b3:3c:5a:92:4b:c0:77:2d:b0:e5:ae:1f:af:1d:7f:21:9c:65:
+         26:be:0c:ba:e8:0d:c1:d2:67:b4:b9:33:d1:4a:ee:fc:b8:af:
+         03:5b:c8:3e:bc:fa:09:9d:04:ce:3e:a6:b5:c4:74:3b:31:7a:
+         f3:2c:42:b3:c7:73:db:aa:75:2e:8d:8a:9e:79:33:be:d7:b6:
+         14:9b:26:ab:7b:9e:14:b3:55:e6:4b:bb:86:94:11:74:02:35:
+         b4:52:70:9b
+-----BEGIN CERTIFICATE-----
+MIIGoTCCBYmgAwIBAgIQAa8e+91erglSMgsk/mtVaDANBgkqhkiG9w0BAQsFADBN
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
+aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTYwOTAyMDAwMDAwWhcN
+MTkwOTExMTIwMDAwWjBtMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p
+YTEVMBMGA1UEBxMMV2FsbnV0IENyZWVrMRUwEwYDVQQKEwxMdWNhcyBHYXJyb24x
+GzAZBgNVBAMTEnJldm9rZWQuYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMcxZeRVz2mQn24f2GoTfnS/EzpUZA90JD3cYLinRQG3yGoD
+rGRKZfB8gYGDCtndMSCCSKYzY+4rdOq05sccsl7kKDp6PSAZA7cVP0/JJuy3y79I
+bl80cFbEhsfjUpohMy8QE/MlDB6UNS7o0NG1oHdAkS7puvj/TvX78noEp+bGzj8P
+EBgyyAa8FbO+aax1fUKgjC7DrOEgTx42nJouov15gLZi+MCyA6kpUMzVJYozXuB4
+ExjAgBcJlb2i/pIVByB6gc7bDoEpidTI7LOzeQ7yziXn7r4hfa8ME5Qp3jWaHtiE
+GFpcGpSCzpph1p3s+O6tPwlbc+yim/rcYvFYH30CAwEAAaOCA1swggNXMB8GA1Ud
+IwQYMBaAFA+AYRyCMWHVLyjnjUY4tCzhxtniMB0GA1UdDgQWBBT0SH0HRRoyB5CR
+rAW4n6kR8H4RNjAdBgNVHREEFjAUghJyZXZva2VkLmJhZHNzbC5jb20wDgYDVR0P
+AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8E
+ZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc1
+LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1n
+NS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0
+cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgMwfAYIKwYBBQUHAQEE
+cDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYB
+BQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJT
+ZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAX4GCisGAQQB1nkCBAIE
+ggFuBIIBagFoAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFW
+7KE32gAABAMARjBEAiA/bKj1xHwBTMNaKCdQR2PZrOG+Lb+HeMs6gJckdM0W9wIg
+cf+TorVUfn9TRX9ZWmAYIVyrfR8IslSgs8SIpYPSY1UAdwBo9pj4H2SCvjqM7rko
+HUz8cVFdZ5PURNEKZ6y7T0/7xAAAAVbsoTehAAAEAwBIMEYCIQD+WZciTGwPOQXZ
+5Mp+O9OzRxthcrY6T9byo1dJSE9qbQIhAI8UGzwbiaMdcOzU1xG8+Qs8YKyMhHMk
+aw43blN/nX80AHYAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFW
+7KE4fwAABAMARzBFAiAOv1NZFwzsZgxeh7uPX7Z2hvJc/LyoucDfvBo77hHy0AIh
+AIclOeQymUjKIBsTlh3DLJhrG8DM5WcivZIU6WjNlYIyMA0GCSqGSIb3DQEBCwUA
+A4IBAQBaoEmIrWAfCFNM2bjc9UBBre/IewE7E3BEmfZcI0b3Osh9ySGtOklFgh5d
+Ox6bago+YS32sZl0L5H51fGfrnQmizynjL4o/qw7cK4IVnGsVXxAiQItYSr9VHK/
+GlxwGZAVpHagf1YcwfCNXpk9g0FUaOViwVqiZIwBZHojuT+/Is8fwEeAH5TV8jCE
++wcC+lugugkEmE7zJVZMxH7gJ9joMo+zPFqSS8B3LbDlrh+vHX8hnGUmvgy66A3B
+0me0uTPRSu78uK8DW8g+vPoJnQTOPqa1xHQ7MXrzLEKzx3PbqnUujYqeeTO+17YU
+myare54Us1XmS7uGlBF0AjW0UnCb
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/3d3d823fad13dfeef32da580166d4a4992bed5a22d695d12c8b08cc3463c67a2.pem b/net/data/ssl/blacklist/3d3d823fad13dfeef32da580166d4a4992bed5a22d695d12c8b08cc3463c67a2.pem
new file mode 100644
index 0000000..dbb2158
--- /dev/null
+++ b/net/data/ssl/blacklist/3d3d823fad13dfeef32da580166d4a4992bed5a22d695d12c8b08cc3463c67a2.pem
Binary files differ
diff --git a/net/data/ssl/blacklist/487afc8d0d411b2a05561a2a6f35918f4040e5570c4c73ee323cc50583bcfbb7.pem b/net/data/ssl/blacklist/487afc8d0d411b2a05561a2a6f35918f4040e5570c4c73ee323cc50583bcfbb7.pem
new file mode 100644
index 0000000..0ea35243
--- /dev/null
+++ b/net/data/ssl/blacklist/487afc8d0d411b2a05561a2a6f35918f4040e5570c4c73ee323cc50583bcfbb7.pem
@@ -0,0 +1,108 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            36:52:d1:64:91:4b:72:8f:c0:9f:77:0b:00:68:c6:81
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, ST = TX, L = Houston, O = "cPanel, Inc.", CN = "cPanel, Inc. Certification Authority"
+        Validity
+            Not Before: Jan 14 00:00:00 2018 GMT
+            Not After : Apr 14 23:59:59 2018 GMT
+        Subject: CN = google.com.bd
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c5:c8:af:b7:38:55:ef:c6:c6:31:40:da:2f:90:
+                    b7:57:b4:cf:a3:4b:32:8a:1b:c2:2d:4b:bf:a1:92:
+                    78:8e:f5:b1:eb:4f:fc:d8:86:6e:37:71:4a:b9:f2:
+                    8d:ae:1f:8b:f5:fa:ed:1c:a0:36:78:e6:97:2f:6c:
+                    5c:a7:93:cb:4d:a7:e4:93:c7:a5:91:f4:6f:ba:2a:
+                    97:42:63:1b:b0:c7:ae:a0:41:05:f4:bf:5e:a9:5e:
+                    54:a9:e3:d9:5b:4a:e3:74:01:9a:1d:8f:5e:88:2f:
+                    83:3a:df:e1:b8:fd:cf:df:a3:e5:b5:69:05:12:41:
+                    4c:d9:50:39:36:3c:8e:5b:68:47:65:a3:c5:a7:fb:
+                    6f:bd:20:ee:7d:94:72:9c:3a:a8:ce:a7:40:00:ec:
+                    8a:62:9c:98:d5:c1:6c:f6:9e:fc:26:6c:50:99:36:
+                    3d:ad:20:b3:c6:85:8e:f2:9e:f0:fc:c5:54:ab:05:
+                    3d:ad:a7:06:5e:17:bf:27:bc:3c:9d:06:81:f3:0b:
+                    10:fd:2e:39:f6:bb:a6:ed:94:cc:b8:67:ee:87:5d:
+                    b1:6d:79:ff:c5:a3:1b:19:29:5b:33:c9:60:bb:31:
+                    4b:75:8a:b3:88:19:2d:60:f9:f9:0b:95:48:41:fd:
+                    d9:85:dd:5e:1a:e1:8c:bd:b6:bd:d7:9f:7a:18:c0:
+                    69:05
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Authority Key Identifier: 
+                keyid:7E:03:5A:65:41:6B:A7:7E:0A:E1:B8:9D:08:EA:1D:8E:1D:6A:C7:65
+
+            X509v3 Subject Key Identifier: 
+                4C:62:65:25:4F:EE:DD:23:5E:DB:91:A2:36:EA:87:BA:C4:05:02:38
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Certificate Policies: 
+                Policy: 1.3.6.1.4.1.6449.1.2.2.52
+                  CPS: https://secure.comodo.com/CPS
+                Policy: 2.23.140.1.2.1
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crl.comodoca.com/cPanelIncCertificationAuthority.crl
+
+            Authority Information Access: 
+                CA Issuers - URI:http://crt.comodoca.com/cPanelIncCertificationAuthority.crt
+                OCSP - URI:http://ocsp.comodoca.com
+
+            X509v3 Subject Alternative Name: 
+                DNS:google.com.bd, DNS:cpanel.google.com.bd, DNS:mail.google.com.bd, DNS:webdisk.google.com.bd, DNS:webmail.google.com.bd, DNS:www.google.com.bd
+    Signature Algorithm: sha256WithRSAEncryption
+         0d:46:2d:00:09:c5:59:51:a9:2a:e0:fd:38:5e:5f:b6:6a:92:
+         59:ed:db:f7:47:be:d6:da:1c:a9:e8:f5:ab:eb:d4:43:46:7b:
+         2f:26:a2:c3:36:a8:37:0b:18:7b:f5:ab:84:d4:11:3d:50:98:
+         70:55:ce:93:f9:8e:73:35:31:a0:c7:f0:f1:9e:ac:f4:e3:03:
+         cd:df:49:10:b3:4b:15:2c:8c:de:4e:44:44:94:91:97:61:37:
+         02:b3:49:3b:dd:dc:be:75:b3:c9:f3:2a:d7:bc:a1:ad:dc:4a:
+         dc:08:16:39:44:58:a5:03:01:26:d6:d3:01:e9:6b:3b:33:ea:
+         35:71:88:e0:c3:d0:cb:df:b3:f4:7d:91:f1:75:e0:e4:54:49:
+         e7:4a:c5:af:8f:5e:a3:25:1c:63:29:ef:76:72:b6:7f:c4:5c:
+         d1:ad:c2:8e:89:79:e6:7a:7b:ea:3d:92:4d:dc:18:e4:23:4f:
+         d6:b4:be:4f:2f:71:ed:69:dd:0c:c4:2d:43:f3:be:05:3b:01:
+         ba:a0:c7:0c:3c:84:69:c2:1e:58:47:43:b7:e7:7d:7a:24:a2:
+         51:57:e9:be:11:0b:4f:b7:e6:0a:81:0e:6b:07:be:f0:3d:ac:
+         03:5e:5a:89:49:e7:ea:5e:47:61:c7:05:10:f0:4e:64:f6:99:
+         bd:27:d7:f2
+-----BEGIN CERTIFICATE-----
+MIIFOzCCBCOgAwIBAgIQNlLRZJFLco/An3cLAGjGgTANBgkqhkiG9w0BAQsFADBy
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCVFgxEDAOBgNVBAcTB0hvdXN0b24xFTAT
+BgNVBAoTDGNQYW5lbCwgSW5jLjEtMCsGA1UEAxMkY1BhbmVsLCBJbmMuIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MDExNDAwMDAwMFoXDTE4MDQxNDIzNTk1
+OVowGDEWMBQGA1UEAxMNZ29vZ2xlLmNvbS5iZDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMXIr7c4Ve/GxjFA2i+Qt1e0z6NLMoobwi1Lv6GSeI71setP
+/NiGbjdxSrnyja4fi/X67RygNnjmly9sXKeTy02n5JPHpZH0b7oql0JjG7DHrqBB
+BfS/XqleVKnj2VtK43QBmh2PXogvgzrf4bj9z9+j5bVpBRJBTNlQOTY8jltoR2Wj
+xaf7b70g7n2Ucpw6qM6nQADsimKcmNXBbPae/CZsUJk2Pa0gs8aFjvKe8PzFVKsF
+Pa2nBl4Xvye8PJ0GgfMLEP0uOfa7pu2UzLhn7oddsW15/8WjGxkpWzPJYLsxS3WK
+s4gZLWD5+QuVSEH92YXdXhrhjL22vdefehjAaQUCAwEAAaOCAiUwggIhMB8GA1Ud
+IwQYMBaAFH4DWmVBa6d+CuG4nQjqHY4dasdlMB0GA1UdDgQWBBRMYmUlT+7dI17b
+kaI26oe6xAUCODAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUE
+FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQIC
+NDArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAI
+BgZngQwBAgEwTAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5j
+b20vY1BhbmVsSW5jQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwfQYIKwYBBQUH
+AQEEcTBvMEcGCCsGAQUFBzAChjtodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9jUGFu
+ZWxJbmNDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNydDAkBggrBgEFBQcwAYYYaHR0
+cDovL29jc3AuY29tb2RvY2EuY29tMIGDBgNVHREEfDB6gg1nb29nbGUuY29tLmJk
+ghRjcGFuZWwuZ29vZ2xlLmNvbS5iZIISbWFpbC5nb29nbGUuY29tLmJkghV3ZWJk
+aXNrLmdvb2dsZS5jb20uYmSCFXdlYm1haWwuZ29vZ2xlLmNvbS5iZIIRd3d3Lmdv
+b2dsZS5jb20uYmQwDQYJKoZIhvcNAQELBQADggEBAA1GLQAJxVlRqSrg/TheX7Zq
+klnt2/dHvtbaHKno9avr1ENGey8mosM2qDcLGHv1q4TUET1QmHBVzpP5jnM1MaDH
+8PGerPTjA83fSRCzSxUsjN5ORESUkZdhNwKzSTvd3L51s8nzKte8oa3cStwIFjlE
+WKUDASbW0wHpazsz6jVxiODD0Mvfs/R9kfF14ORUSedKxa+PXqMlHGMp73Zytn/E
+XNGtwo6JeeZ6e+o9kk3cGOQjT9a0vk8vce1p3QzELUPzvgU7Abqgxww8hGnCHlhH
+Q7fnfXokolFX6b4RC0+35gqBDmsHvvA9rANeWolJ5+peR2HHBRDwTmT2mb0n1/I=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/4aefc3d39ef59e4d4b0304b20f53a8af2efb69edece66def74494abfc10a2d66.pem b/net/data/ssl/blacklist/4aefc3d39ef59e4d4b0304b20f53a8af2efb69edece66def74494abfc10a2d66.pem
new file mode 100644
index 0000000..462862728
--- /dev/null
+++ b/net/data/ssl/blacklist/4aefc3d39ef59e4d4b0304b20f53a8af2efb69edece66def74494abfc10a2d66.pem
@@ -0,0 +1,105 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            36:69:5a:c1:30:2e:5c:d2:d0:13:ef:29:a2:68:e6:de
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = CN, O = WoSign CA Limited, CN = WoSign CA Free SSL Certificate G2
+        Validity
+            Not Before: Jun  9 23:38:37 2015 GMT
+            Not After : Jun 10 00:03:27 2018 GMT
+        Subject: CN = med.ucf.edu
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:a2:42:a9:12:83:85:b1:38:00:c1:67:6e:94:e7:
+                    f2:d8:bd:29:89:17:b4:c9:3b:c0:17:1f:c8:d1:bd:
+                    32:9c:b2:ff:54:1d:f8:cb:cb:06:78:52:75:f7:c4:
+                    17:03:79:32:ab:16:69:7b:30:f8:95:aa:22:5b:21:
+                    5a:95:de:03:b6:ac:29:4f:51:63:39:93:4e:01:a0:
+                    14:a8:8e:3b:0f:93:2f:a7:63:7b:89:25:26:ab:06:
+                    b0:f4:93:ed:7c:8d:19:6d:df:96:79:0e:b7:c9:d0:
+                    aa:c5:92:4f:4b:4a:7e:77:c7:f8:f0:e3:cb:ea:47:
+                    a7:00:37:b5:6b:e9:a6:f6:cd:ed:50:68:93:7d:c7:
+                    90:89:98:24:49:ff:a6:03:fa:6c:c9:75:96:ad:e7:
+                    e6:e4:10:d8:ea:38:bb:a8:e0:2c:d3:19:4b:1d:72:
+                    ad:36:f8:47:13:6a:3b:d1:23:b9:0d:ab:4d:14:d0:
+                    26:14:88:b2:95:91:53:68:72:44:b8:c2:93:f1:15:
+                    d4:93:59:c5:09:fc:71:cb:73:f2:0a:04:46:84:db:
+                    7c:20:7d:71:b7:a6:81:73:45:51:59:92:ec:c3:8c:
+                    5c:97:6d:ba:ee:6b:d2:7b:3f:4f:08:82:aa:b5:95:
+                    ab:68:6d:98:b7:f5:28:d9:3f:a5:6d:38:76:27:e6:
+                    9e:4f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication, TLS Web Server Authentication
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                23:E0:10:00:B1:41:D4:33:7B:02:D3:9E:C0:3C:13:9A:C3:59:41:45
+            X509v3 Authority Key Identifier: 
+                keyid:D2:A7:16:20:7C:AF:D9:95:9E:EB:43:0A:19:F2:E0:B9:74:0E:A8:C7
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp6.wosign.com/ca6/server1/free
+                CA Issuers - URI:http://aia6.wosign.com/ca6.server1.free.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crls6.wosign.com/ca6-server1-free.crl
+
+            X509v3 Subject Alternative Name: 
+                DNS:med.ucf.edu, DNS:www.ucf.edu
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.36305.6.1.2.2.1
+                  CPS: http://www.wosign.com/policy/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         24:c9:93:fe:14:af:53:57:49:c2:df:be:1f:9a:89:1e:9c:d5:
+         04:7f:7b:dd:60:47:8f:ae:b4:52:4b:c9:46:32:f0:98:48:02:
+         73:61:23:68:bc:29:c6:f9:af:33:43:f4:3d:93:b4:ce:03:8b:
+         85:60:81:55:aa:7d:c2:75:8b:8e:2a:bc:a3:13:b1:b4:b2:d5:
+         f4:44:23:ae:42:49:85:f1:8f:c8:99:a2:57:c7:ab:60:72:df:
+         22:91:26:95:86:b8:f2:f6:3c:2b:7a:53:8c:8e:9f:f7:45:28:
+         44:61:b4:3e:3e:84:54:d5:9c:63:69:6b:74:f2:24:ba:62:47:
+         f8:cf:57:c8:1f:a4:d0:8e:d4:b4:d1:43:3c:0e:29:91:dc:b1:
+         a2:ec:09:f0:ba:e5:b3:e4:5d:1f:34:00:09:85:01:c7:6b:fc:
+         1d:8b:a9:a1:46:20:aa:b8:18:a7:b8:78:cd:c3:91:87:a4:82:
+         16:2a:96:6f:50:87:00:3c:89:d5:a3:90:af:66:63:aa:2f:c0:
+         95:3f:b3:2e:16:b7:7a:84:68:4a:66:af:28:fa:2a:ec:a4:c2:
+         c3:bc:32:55:ac:7b:a7:21:2d:8b:8b:c0:5e:27:a7:0b:af:94:
+         79:d7:7c:65:33:de:48:76:56:3d:9e:1a:62:f2:ec:d5:ff:a3:
+         a7:65:d1:ff
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIQNmlawTAuXNLQE+8pomjm3jANBgkqhkiG9w0BAQsFADBV
+MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV
+BAMTIVdvU2lnbiBDQSBGcmVlIFNTTCBDZXJ0aWZpY2F0ZSBHMjAeFw0xNTA2MDky
+MzM4MzdaFw0xODA2MTAwMDAzMjdaMBYxFDASBgNVBAMMC21lZC51Y2YuZWR1MIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAokKpEoOFsTgAwWdulOfy2L0p
+iRe0yTvAFx/I0b0ynLL/VB34y8sGeFJ198QXA3kyqxZpezD4laoiWyFald4Dtqwp
+T1FjOZNOAaAUqI47D5Mvp2N7iSUmqwaw9JPtfI0Zbd+WeQ63ydCqxZJPS0p+d8f4
+8OPL6kenADe1a+mm9s3tUGiTfceQiZgkSf+mA/psyXWWrefm5BDY6ji7qOAs0xlL
+HXKtNvhHE2o70SO5DatNFNAmFIiylZFTaHJEuMKT8RXUk1nFCfxxy3PyCgRGhNt8
+IH1xt6aBc0VRWZLsw4xcl2267mvSez9PCIKqtZWraG2Yt/Uo2T+lbTh2J+aeTwID
+AQABo4IBsTCCAa0wCwYDVR0PBAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
+BgEFBQcDATAJBgNVHRMEAjAAMB0GA1UdDgQWBBQj4BAAsUHUM3sC057APBOaw1lB
+RTAfBgNVHSMEGDAWgBTSpxYgfK/ZlZ7rQwoZ8uC5dA6oxzB9BggrBgEFBQcBAQRx
+MG8wNAYIKwYBBQUHMAGGKGh0dHA6Ly9vY3NwNi53b3NpZ24uY29tL2NhNi9zZXJ2
+ZXIxL2ZyZWUwNwYIKwYBBQUHMAKGK2h0dHA6Ly9haWE2Lndvc2lnbi5jb20vY2E2
+LnNlcnZlcjEuZnJlZS5jZXIwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybHM2
+Lndvc2lnbi5jb20vY2E2LXNlcnZlcjEtZnJlZS5jcmwwIwYDVR0RBBwwGoILbWVk
+LnVjZi5lZHWCC3d3dy51Y2YuZWR1MFEGA1UdIARKMEgwCAYGZ4EMAQIBMDwGDSsG
+AQQBgptRBgECAgEwKzApBggrBgEFBQcCARYdaHR0cDovL3d3dy53b3NpZ24uY29t
+L3BvbGljeS8wDQYJKoZIhvcNAQELBQADggEBACTJk/4Ur1NXScLfvh+aiR6c1QR/
+e91gR4+utFJLyUYy8JhIAnNhI2i8Kcb5rzND9D2TtM4Di4VggVWqfcJ1i44qvKMT
+sbSy1fREI65CSYXxj8iZolfHq2By3yKRJpWGuPL2PCt6U4yOn/dFKERhtD4+hFTV
+nGNpa3TyJLpiR/jPV8gfpNCO1LTRQzwOKZHcsaLsCfC65bPkXR80AAmFAcdr/B2L
+qaFGIKq4GKe4eM3DkYekghYqlm9QhwA8idWjkK9mY6ovwJU/sy4Wt3qEaEpmryj6
+KuykwsO8MlWse6chLYuLwF4npwuvlHnXfGUz3kh2Vj2eGmLy7NX/o6dl0f8=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/53d48e7b8869a3314f213fd2e0178219ca09022dbe50053bf6f76fccd61e8112.pem b/net/data/ssl/blacklist/53d48e7b8869a3314f213fd2e0178219ca09022dbe50053bf6f76fccd61e8112.pem
new file mode 100644
index 0000000..527090c
--- /dev/null
+++ b/net/data/ssl/blacklist/53d48e7b8869a3314f213fd2e0178219ca09022dbe50053bf6f76fccd61e8112.pem
@@ -0,0 +1,111 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            05:19:bb:07:ad:6f:78:21:6b:1a:00:1f:a7:22:23:af
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance CA-3
+        Validity
+            Not Before: Apr  9 00:00:00 2014 GMT
+            Not After : Dec 29 12:00:00 2016 GMT
+        Subject: C = US, ST = California, L = Laguna Niguel, O = Gibson Research Corporation, OU = Web Services, CN = revoked.grc.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ba:d7:a0:0c:dd:d9:43:38:ce:1d:63:07:fe:df:
+                    ac:33:95:74:7a:3a:85:b9:05:d2:39:94:8b:05:89:
+                    92:b4:22:9d:29:ce:5d:5d:c6:10:74:1a:59:3d:4e:
+                    2c:76:9f:eb:35:d3:05:a1:12:9f:e2:c7:f6:53:64:
+                    44:09:61:ba:b9:d5:57:e0:99:7a:09:0e:32:f2:ec:
+                    34:64:ba:12:90:e3:9a:97:74:df:dc:61:b2:6f:ee:
+                    f5:50:76:71:6d:b5:c3:bc:a7:ab:f7:f1:8b:da:7d:
+                    33:b2:1f:40:1f:15:16:59:35:a4:9f:13:d6:7d:15:
+                    15:79:21:3b:07:94:3e:f1:1b:59:81:c7:ad:79:ae:
+                    cf:4d:2e:ff:20:c0:c8:40:be:fd:a0:46:05:99:f0:
+                    f8:29:af:12:ec:a3:04:3d:14:4d:bb:04:47:57:4a:
+                    32:bd:b8:c3:96:ef:81:3d:ee:bc:61:5c:e9:46:5b:
+                    c3:70:f0:b1:71:c9:81:5c:da:d6:67:8b:92:02:e1:
+                    e9:71:02:aa:e0:ba:0b:15:cd:a8:8b:47:3b:72:b4:
+                    fa:eb:38:10:09:4d:b0:8b:a3:e2:61:49:59:99:f5:
+                    50:c8:4c:ac:c1:7a:d5:9d:e6:8c:7a:f7:e0:a0:02:
+                    0a:6d:f5:cc:b0:50:27:aa:a7:57:0a:fd:fb:6c:d1:
+                    0e:33
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Authority Key Identifier: 
+                keyid:50:EA:73:89:DB:29:FB:10:8F:9E:E5:01:20:D4:DE:79:99:48:83:F7
+
+            X509v3 Subject Key Identifier: 
+                E2:61:A1:5C:D1:BE:8E:4A:D2:D7:0A:9C:83:DB:99:C8:DB:8D:CC:8A
+            X509v3 Subject Alternative Name: 
+                DNS:revoked.grc.com
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crl3.digicert.com/ca3-g27.crl
+
+                Full Name:
+                  URI:http://crl4.digicert.com/ca3-g27.crl
+
+            X509v3 Certificate Policies: 
+                Policy: 2.16.840.1.114412.1.1
+                  CPS: https://www.digicert.com/CPS
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.digicert.com
+                CA Issuers - URI:http://cacerts.digicert.com/DigiCertHighAssuranceCA-3.crt
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+    Signature Algorithm: sha1WithRSAEncryption
+         bb:dd:a9:e2:60:71:70:79:df:ad:73:7c:66:6f:f3:20:bf:82:
+         96:7e:a5:79:18:55:c9:df:b3:ad:e8:0b:36:3e:17:cf:85:9d:
+         af:30:d3:1e:be:0d:ad:52:c9:68:12:3c:a4:0a:14:e7:57:de:
+         1b:d2:b8:ed:e8:ae:ff:bc:58:bd:31:cf:00:88:5b:0a:16:8e:
+         a9:4d:93:cd:3d:3d:35:60:b6:e3:e9:c7:bd:f8:11:13:b2:1c:
+         5f:37:95:29:d0:70:84:c5:f1:27:95:13:69:91:b6:d8:37:da:
+         3a:8e:4b:80:48:39:87:42:6b:96:c8:45:80:6a:fd:56:88:bb:
+         80:81:e6:05:be:25:78:f9:fa:0f:ae:1a:84:a6:90:e1:5f:56:
+         f1:53:df:78:f5:ba:40:77:db:61:a3:bb:7e:d5:83:46:50:13:
+         8c:07:ad:7e:59:8e:48:c6:dd:5c:6d:8f:91:22:30:7f:13:6a:
+         a6:7b:fd:bf:15:16:1e:9a:2c:f3:48:d4:ad:d2:66:2f:9a:99:
+         68:1d:19:ef:a8:4f:1d:fd:c6:92:4a:20:71:76:f6:fb:89:fe:
+         a9:d5:5f:58:4d:be:a0:e5:cd:82:43:0a:86:9b:c1:37:6c:2a:
+         d5:5d:e7:8e:b6:20:31:80:48:54:74:7c:ad:69:26:50:81:04:
+         38:c2:bd:ac
+-----BEGIN CERTIFICATE-----
+MIIFRTCCBC2gAwIBAgIQBRm7B61veCFrGgAfpyIjrzANBgkqhkiG9w0BAQUFADBm
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBDQS0zMB4XDTE0MDQwOTAwMDAwMFoXDTE2MTIyOTEyMDAwMFowgZExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1MYWd1bmEgTmln
+dWVsMSQwIgYDVQQKExtHaWJzb24gUmVzZWFyY2ggQ29ycG9yYXRpb24xFTATBgNV
+BAsTDFdlYiBTZXJ2aWNlczEYMBYGA1UEAxMPcmV2b2tlZC5ncmMuY29tMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAutegDN3ZQzjOHWMH/t+sM5V0ejqF
+uQXSOZSLBYmStCKdKc5dXcYQdBpZPU4sdp/rNdMFoRKf4sf2U2RECWG6udVX4Jl6
+CQ4y8uw0ZLoSkOOal3Tf3GGyb+71UHZxbbXDvKer9/GL2n0zsh9AHxUWWTWknxPW
+fRUVeSE7B5Q+8RtZgcetea7PTS7/IMDIQL79oEYFmfD4Ka8S7KMEPRRNuwRHV0oy
+vbjDlu+BPe68YVzpRlvDcPCxccmBXNrWZ4uSAuHpcQKq4LoLFc2oi0c7crT66zgQ
+CU2wi6PiYUlZmfVQyEyswXrVneaMevfgoAIKbfXMsFAnqqdXCv37bNEOMwIDAQAB
+o4IBwTCCAb0wHwYDVR0jBBgwFoAUUOpzidsp+xCPnuUBINTeeZlIg/cwHQYDVR0O
+BBYEFOJhoVzRvo5K0tcKnIPbmcjbjcyKMBoGA1UdEQQTMBGCD3Jldm9rZWQuZ3Jj
+LmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
+BwMCMGEGA1UdHwRaMFgwKqAooCaGJGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9j
+YTMtZzI3LmNybDAqoCigJoYkaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL2NhMy1n
+MjcuY3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0
+dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwewYIKwYBBQUHAQEEbzBtMCQGCCsG
+AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRQYIKwYBBQUHMAKGOWh0
+dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VD
+QS0zLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBBQUAA4IBAQC73aniYHFw
+ed+tc3xmb/Mgv4KWfqV5GFXJ37Ot6As2PhfPhZ2vMNMevg2tUsloEjykChTnV94b
+0rjt6K7/vFi9Mc8AiFsKFo6pTZPNPT01YLbj6ce9+BETshxfN5Up0HCExfEnlRNp
+kbbYN9o6jkuASDmHQmuWyEWAav1WiLuAgeYFviV4+foPrhqEppDhX1bxU9949bpA
+d9tho7t+1YNGUBOMB61+WY5Ixt1cbY+RIjB/E2qme/2/FRYemizzSNSt0mYvmplo
+HRnvqE8d/caSSiBxdvb7if6p1V9YTb6g5c2CQwqGm8E3bCrVXeeOtiAxgEhUdHyt
+aSZQgQQ4wr2s
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/5472692abe5d02cd22eae3e0a0077f17802721d6576cde1cba2263ee803410c5.pem b/net/data/ssl/blacklist/5472692abe5d02cd22eae3e0a0077f17802721d6576cde1cba2263ee803410c5.pem
new file mode 100644
index 0000000..7904bb82
--- /dev/null
+++ b/net/data/ssl/blacklist/5472692abe5d02cd22eae3e0a0077f17802721d6576cde1cba2263ee803410c5.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:13:e5:32:ac:64:07:20:a7:dd:73:6e:60:c8:58:34:c7:29
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 12:36:33 2017 GMT
+            Not After : Jan 30 12:36:33 2018 GMT
+        Subject: CN = google.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c5:ca:e1:37:15:af:d8:a4:ff:f4:5b:66:d4:83:
+                    8a:ef:3b:08:5e:38:82:ba:09:d6:65:91:37:e1:d2:
+                    46:d6:eb:3b:92:53:a5:3a:ea:5f:7b:19:30:70:14:
+                    4b:4b:e9:00:c0:7c:b1:b1:41:7b:e5:e0:4f:ce:cc:
+                    10:ff:39:4a:d9:0f:82:f9:79:a6:88:fa:c9:2f:71:
+                    91:bd:96:7b:8b:e3:cf:f6:ce:1c:44:67:17:be:de:
+                    50:01:ec:20:4b:67:23:28:b5:9b:d6:af:71:33:ee:
+                    bb:5b:9a:ff:fc:5b:cf:5b:c7:c3:78:92:62:27:1d:
+                    a2:19:79:38:37:8b:b0:8b:ff:d9:b6:61:06:11:34:
+                    da:bd:5c:1a:38:7d:8e:fc:1c:cb:73:f2:98:b8:64:
+                    3d:d9:c1:9e:28:6b:f7:00:32:58:d0:61:44:26:bd:
+                    d1:02:ff:4b:53:0b:97:d1:91:4c:32:4a:d0:98:0b:
+                    59:d0:5d:7d:22:d3:da:a7:00:5b:32:0e:e2:aa:f5:
+                    87:0b:15:45:90:4e:fd:07:a9:20:b4:83:dc:c7:57:
+                    93:b0:4e:6b:29:e8:f9:ed:1e:f3:ef:61:3d:7e:06:
+                    54:78:74:da:fa:e1:e8:0f:b3:d5:fc:20:e9:8f:be:
+                    fb:c6:74:c3:6e:0b:8f:a4:81:5b:71:86:8d:d3:e5:
+                    83:e7
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                BB:8B:1D:2F:66:CA:57:95:97:17:E3:DD:09:5F:53:E0:4E:EB:49:2D
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:cpanel.google.tg, DNS:google.tg, DNS:mail.google.tg, DNS:webdisk.google.tg, DNS:webmail.google.tg, DNS:www.google.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         1f:10:a1:3a:0a:68:c2:f0:5d:d5:d4:e8:0a:c5:3e:50:c6:56:
+         dd:ce:d5:58:f9:60:16:55:a8:1c:2b:33:f0:22:14:aa:4b:ad:
+         bd:c3:bb:ff:84:c6:2e:b7:19:9e:ea:bc:60:29:f9:8c:87:9d:
+         21:2b:8b:02:1f:78:23:99:f1:b7:ac:97:34:de:04:66:47:30:
+         53:bd:e3:bf:5e:52:1b:a1:be:a9:bb:e7:fb:ca:85:38:9d:bd:
+         db:cd:fc:45:7a:7b:74:87:c6:5c:a4:31:e7:89:2b:c9:fb:bf:
+         1e:bc:e8:7e:5b:df:84:0c:7b:bd:99:22:8d:75:ea:96:6a:42:
+         1c:10:86:d1:27:f9:72:8e:5c:18:a0:0a:18:12:3d:37:a3:d5:
+         06:9b:c0:68:a7:7d:d3:48:0b:f5:4f:fb:74:c4:31:e4:b6:59:
+         ed:ff:5a:fa:2a:30:da:bd:20:78:a2:c6:85:1a:ce:6d:96:02:
+         29:5e:ad:67:c0:7c:52:75:4f:8d:09:8a:dd:a8:55:73:6c:cf:
+         b9:28:a9:f5:f1:86:95:1c:65:a4:60:9d:9f:43:a7:5e:0d:7d:
+         1b:44:6d:ae:0f:35:54:d6:23:5a:5e:6a:ee:4a:cc:6b:5c:ea:
+         cb:f8:36:be:46:89:03:60:48:31:98:13:a6:95:d9:54:3e:6d:
+         82:a0:8c:46
+-----BEGIN CERTIFICATE-----
+MIIFTDCCBDSgAwIBAgISAxPlMqxkByCn3XNuYMhYNMcpMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMjM2MzNaFw0x
+ODAxMzAxMjM2MzNaMBQxEjAQBgNVBAMTCWdvb2dsZS50ZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMXK4TcVr9ik//RbZtSDiu87CF44groJ1mWRN+HS
+RtbrO5JTpTrqX3sZMHAUS0vpAMB8sbFBe+XgT87MEP85StkPgvl5poj6yS9xkb2W
+e4vjz/bOHERnF77eUAHsIEtnIyi1m9avcTPuu1ua//xbz1vHw3iSYicdohl5ODeL
+sIv/2bZhBhE02r1cGjh9jvwcy3PymLhkPdnBnihr9wAyWNBhRCa90QL/S1MLl9GR
+TDJK0JgLWdBdfSLT2qcAWzIO4qr1hwsVRZBO/QepILSD3MdXk7BOayno+e0e8+9h
+PX4GVHh02vrh6A+z1fwg6Y+++8Z0w24Lj6SBW3GGjdPlg+cCAwEAAaOCAmAwggJc
+MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUu4sdL2bKV5WXF+PdCV9T4E7rSS0wHwYD
+VR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7/Oo7KEwbwYIKwYBBQUHAQEEYzBhMC4G
+CCsGAQUFBzABhiJodHRwOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3JnMC8G
+CCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDMubGV0c2VuY3J5cHQub3JnLzBr
+BgNVHREEZDBighBjcGFuZWwuZ29vZ2xlLnRngglnb29nbGUudGeCDm1haWwuZ29v
+Z2xlLnRnghF3ZWJkaXNrLmdvb2dsZS50Z4IRd2VibWFpbC5nb29nbGUudGeCDXd3
+dy5nb29nbGUudGcwgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8T
+AQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCB
+qwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJl
+bGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRh
+bmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczov
+L2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA
+HxChOgpowvBd1dToCsU+UMZW3c7VWPlgFlWoHCsz8CIUqkutvcO7/4TGLrcZnuq8
+YCn5jIedISuLAh94I5nxt6yXNN4EZkcwU73jv15SG6G+qbvn+8qFOJ292838RXp7
+dIfGXKQx54kryfu/HrzoflvfhAx7vZkijXXqlmpCHBCG0Sf5co5cGKAKGBI9N6PV
+BpvAaKd900gL9U/7dMQx5LZZ7f9a+iow2r0geKLGhRrObZYCKV6tZ8B8UnVPjQmK
+3ahVc2zPuSip9fGGlRxlpGCdn0OnXg19G0Rtrg81VNYjWl5q7krMa1zqy/g2vkaJ
+A2BIMZgTppXZVD5tgqCMRg==
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/5ccaf9f8f2bb3a0d215922eca383354b6ee3c62407ed32e30f6fb2618edeea10.pem b/net/data/ssl/blacklist/5ccaf9f8f2bb3a0d215922eca383354b6ee3c62407ed32e30f6fb2618edeea10.pem
new file mode 100644
index 0000000..3de6924
--- /dev/null
+++ b/net/data/ssl/blacklist/5ccaf9f8f2bb3a0d215922eca383354b6ee3c62407ed32e30f6fb2618edeea10.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:fe:c3:1c:27:33:06:73:f9:a9:45:61:d2:31:76:a6:fc:01
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 12:51:13 2017 GMT
+            Not After : Jan 30 12:51:13 2018 GMT
+        Subject: CN = gmail.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c2:3a:0e:66:79:21:60:64:1b:61:e1:80:58:39:
+                    4a:61:f5:c7:60:af:3a:90:0c:cc:7d:d6:02:08:c7:
+                    db:76:d0:10:aa:11:8b:1a:b7:0b:b4:aa:d3:14:5f:
+                    9d:4d:57:12:b9:b5:a8:06:56:83:d4:c9:0b:30:8f:
+                    36:6c:e3:98:6a:1c:94:fe:49:24:5a:6a:08:d2:23:
+                    7f:8b:e2:3a:0a:ba:21:b4:2d:b5:af:be:7a:9a:45:
+                    9f:59:e7:b1:6f:0e:2d:50:ae:aa:2d:3a:7d:75:b5:
+                    da:5d:74:22:74:41:d8:bf:b2:2b:e9:a2:fe:1d:ed:
+                    94:4f:ba:48:2d:c6:29:a8:70:08:ce:4e:fc:bd:1b:
+                    63:bd:cc:26:14:5d:11:c3:1c:ec:af:9b:88:69:ac:
+                    18:6c:a5:04:c3:20:3c:0b:bf:ef:a1:c0:57:e7:59:
+                    3c:87:aa:7c:59:9b:8d:24:a0:2a:9e:86:8a:2f:f4:
+                    5d:7e:16:44:8c:fc:fd:e6:e1:82:67:f8:1a:3f:e1:
+                    e1:3a:9c:b0:92:53:85:9f:83:2e:d1:31:cd:29:12:
+                    d5:c4:aa:17:08:27:92:b7:29:6a:38:1e:37:e0:cd:
+                    f0:1b:46:67:10:f7:69:8f:af:e2:d6:44:b2:0b:13:
+                    4f:5d:a0:22:25:94:50:8f:bb:55:a3:e6:86:fe:32:
+                    9f:b9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                E5:F2:83:ED:40:64:BD:6C:EF:15:DA:87:77:98:49:62:4B:87:D6:F8
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:cpanel.gmail.tg, DNS:gmail.tg, DNS:mail.gmail.tg, DNS:webdisk.gmail.tg, DNS:webmail.gmail.tg, DNS:www.gmail.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         48:69:f2:3c:c9:e1:3f:c7:6d:00:40:0c:54:a1:7a:32:04:57:
+         04:da:fa:9c:3b:b0:1e:9a:d7:63:93:5f:73:a5:d4:fc:4f:29:
+         b3:63:d3:71:d8:1b:ca:47:69:61:84:fe:92:c7:97:a5:8d:f6:
+         b5:5a:4b:2b:cf:2e:f2:3e:44:1f:6e:4a:8a:fa:4b:ff:e4:75:
+         99:96:30:66:cb:98:1a:4b:86:cf:8c:7d:60:b4:00:53:e1:08:
+         9d:c2:7c:9f:3f:ac:3f:bb:1e:9a:26:f7:18:75:07:f0:21:bc:
+         c3:a6:e6:64:5f:e2:6c:e4:b3:ab:1a:04:ba:50:dd:35:41:96:
+         a5:e4:f4:cb:ca:89:84:78:00:ed:9e:57:f3:dd:e4:b9:87:90:
+         c3:51:66:6e:f3:49:e2:23:1b:48:07:15:de:f3:93:4f:d6:7e:
+         a9:1e:4f:00:7e:bf:10:49:4a:d1:00:3b:2a:78:04:5a:58:5c:
+         79:4e:94:b2:d2:16:82:92:46:72:b9:d2:fc:4c:d6:7b:9d:ae:
+         2e:49:f3:0a:34:0c:bd:c7:66:8f:2c:7f:14:13:8d:77:d3:03:
+         7f:8a:a5:4d:28:b9:a5:3c:09:42:f3:fe:a9:f2:86:65:8b:8b:
+         85:54:33:93:e9:28:9f:ec:bd:10:f0:2e:79:5a:4c:0b:75:55:
+         dd:a2:5f:e3
+-----BEGIN CERTIFICATE-----
+MIIFRTCCBC2gAwIBAgISA/7DHCczBnP5qUVh0jF2pvwBMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMjUxMTNaFw0x
+ODAxMzAxMjUxMTNaMBMxETAPBgNVBAMTCGdtYWlsLnRnMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAwjoOZnkhYGQbYeGAWDlKYfXHYK86kAzMfdYCCMfb
+dtAQqhGLGrcLtKrTFF+dTVcSubWoBlaD1MkLMI82bOOYahyU/kkkWmoI0iN/i+I6
+CrohtC21r756mkWfWeexbw4tUK6qLTp9dbXaXXQidEHYv7Ir6aL+He2UT7pILcYp
+qHAIzk78vRtjvcwmFF0Rwxzsr5uIaawYbKUEwyA8C7/vocBX51k8h6p8WZuNJKAq
+noaKL/RdfhZEjPz95uGCZ/gaP+HhOpywklOFn4Mu0THNKRLVxKoXCCeStylqOB43
+4M3wG0ZnEPdpj6/i1kSyCxNPXaAiJZRQj7tVo+aG/jKfuQIDAQABo4ICWjCCAlYw
+DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAM
+BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTl8oPtQGS9bO8V2od3mEliS4fW+DAfBgNV
+HSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEwLgYI
+KwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcwLwYI
+KwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcvMGUG
+A1UdEQReMFyCD2NwYW5lbC5nbWFpbC50Z4IIZ21haWwudGeCDW1haWwuZ21haWwu
+dGeCEHdlYmRpc2suZ21haWwudGeCEHdlYm1haWwuZ21haWwudGeCDHd3dy5nbWFp
+bC50ZzCB/gYDVR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYw
+JgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEF
+BQcCAjCBngyBm1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVw
+b24gYnkgUmVseWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0
+aCB0aGUgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2Vu
+Y3J5cHQub3JnL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQBIafI8yeE/
+x20AQAxUoXoyBFcE2vqcO7Aemtdjk19zpdT8TymzY9Nx2BvKR2lhhP6Sx5eljfa1
+Wksrzy7yPkQfbkqK+kv/5HWZljBmy5gaS4bPjH1gtABT4QidwnyfP6w/ux6aJvcY
+dQfwIbzDpuZkX+Js5LOrGgS6UN01QZal5PTLyomEeADtnlfz3eS5h5DDUWZu80ni
+IxtIBxXe85NP1n6pHk8Afr8QSUrRADsqeARaWFx5TpSy0haCkkZyudL8TNZ7na4u
+SfMKNAy9x2aPLH8UE4130wN/iqVNKLmlPAlC8/6p8oZli4uFVDOT6Sif7L0Q8C55
+WkwLdVXdol/j
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/5e8e77aafdda2ba5ce442f27d8246650bbd6508befbeda35966a4dc7e6174edc.pem b/net/data/ssl/blacklist/5e8e77aafdda2ba5ce442f27d8246650bbd6508befbeda35966a4dc7e6174edc.pem
new file mode 100644
index 0000000..d3338eb
--- /dev/null
+++ b/net/data/ssl/blacklist/5e8e77aafdda2ba5ce442f27d8246650bbd6508befbeda35966a4dc7e6174edc.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:9a:04:4f:a5:81:5b:1e:f6:0a:89:4a:7f:4b:71:a1:6c:91
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 13:19:28 2017 GMT
+            Not After : Jan 30 13:19:28 2018 GMT
+        Subject: CN = blogspot.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b3:af:54:ea:cb:63:5b:29:02:49:f7:e7:74:dd:
+                    8a:45:56:e2:e8:ea:06:2f:e6:55:53:af:cd:c6:6f:
+                    71:37:8e:c0:60:bf:c8:fb:70:cc:a6:9f:66:6c:30:
+                    50:92:0e:ca:29:5b:75:77:79:c3:72:66:0b:c3:39:
+                    36:dc:ad:96:61:fc:17:98:b0:7c:0f:70:72:64:9f:
+                    d7:27:10:40:b1:67:ab:b8:f8:b3:cd:e4:68:33:98:
+                    01:bc:e8:51:38:52:b1:a5:eb:f9:41:1f:2b:4c:36:
+                    2d:8d:fa:e7:5f:27:61:2a:ac:93:8c:95:f2:5f:09:
+                    dd:2d:52:0d:1f:92:fb:01:50:c2:00:4a:d1:3f:e5:
+                    4a:58:ec:ba:a8:a4:b3:5d:5c:ff:b9:7f:52:d4:cd:
+                    fb:79:4f:ff:49:6d:e9:9a:c3:de:f6:ef:50:11:b2:
+                    03:5e:d4:3e:4d:2b:46:88:b1:98:f9:36:b8:c8:b0:
+                    81:02:8f:ff:19:50:b5:34:dd:1e:16:35:a0:3a:35:
+                    c5:d7:08:93:34:aa:46:e7:0e:39:79:d1:eb:01:fb:
+                    6a:8e:c1:73:49:cf:03:b4:ed:cf:c7:75:f5:a6:d0:
+                    1c:ae:cf:9c:60:95:a5:91:35:a7:94:b8:90:93:be:
+                    92:a4:0f:9e:56:d3:32:8c:b9:1e:b9:95:1a:8e:69:
+                    ab:fb
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                9B:80:36:19:83:01:A4:8B:02:05:9C:27:00:D9:0B:66:24:8F:5D:5A
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:blogspot.tg, DNS:cpanel.blogspot.tg, DNS:mail.blogspot.tg, DNS:webdisk.blogspot.tg, DNS:webmail.blogspot.tg, DNS:www.blogspot.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         85:25:f3:9f:7c:a3:84:5c:59:94:d0:d6:0b:21:28:9c:0a:ec:
+         6b:17:0d:b0:3d:8c:46:91:8c:d6:0d:60:74:ec:54:db:4d:27:
+         0d:5b:8e:26:94:ff:0a:0a:59:b0:9e:8e:6b:2f:11:ba:6e:20:
+         00:3d:49:2c:03:2d:c0:5b:d8:18:c4:cc:97:dc:0f:ec:d5:f3:
+         5d:7b:3a:bc:10:86:8a:3c:ed:1d:6e:19:2c:de:4b:0a:5a:83:
+         90:3b:fe:58:90:a4:f3:83:66:b9:71:10:2f:fd:60:87:d4:43:
+         af:5b:4b:87:26:ee:f5:03:72:cc:7e:99:db:c8:d6:02:01:a1:
+         d2:a5:5a:15:eb:1a:9d:e5:5c:73:19:1d:fc:ee:15:59:0f:4a:
+         45:e2:09:12:5f:bc:d6:89:f2:f3:bd:83:01:dc:80:29:3c:b4:
+         7d:bf:a5:c5:19:d5:b0:67:92:cc:88:57:2a:4a:86:94:7a:d1:
+         83:b8:3d:f3:fb:8c:62:86:18:a1:69:f4:ec:42:34:11:e7:0f:
+         1e:02:d5:53:89:56:ba:e3:f6:06:50:45:7f:f6:c5:f1:4c:61:
+         11:c3:07:c1:fa:9d:88:7f:1c:47:c7:79:98:27:05:bf:34:c9:
+         52:ff:72:33:04:1f:52:92:f0:38:a0:97:5b:27:c9:d4:77:b7:
+         1f:5b:19:e0
+-----BEGIN CERTIFICATE-----
+MIIFWjCCBEKgAwIBAgISA5oET6WBWx72ColKf0txoWyRMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMzE5MjhaFw0x
+ODAxMzAxMzE5MjhaMBYxFDASBgNVBAMTC2Jsb2dzcG90LnRnMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs69U6stjWykCSffndN2KRVbi6OoGL+ZVU6/N
+xm9xN47AYL/I+3DMpp9mbDBQkg7KKVt1d3nDcmYLwzk23K2WYfwXmLB8D3ByZJ/X
+JxBAsWeruPizzeRoM5gBvOhROFKxpev5QR8rTDYtjfrnXydhKqyTjJXyXwndLVIN
+H5L7AVDCAErRP+VKWOy6qKSzXVz/uX9S1M37eU//SW3pmsPe9u9QEbIDXtQ+TStG
+iLGY+Ta4yLCBAo//GVC1NN0eFjWgOjXF1wiTNKpG5w45edHrAftqjsFzSc8DtO3P
+x3X1ptAcrs+cYJWlkTWnlLiQk76SpA+eVtMyjLkeuZUajmmr+wIDAQABo4ICbDCC
+AmgwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
+AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSbgDYZgwGkiwIFnCcA2QtmJI9dWjAf
+BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
+LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
+LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
+MHcGA1UdEQRwMG6CC2Jsb2dzcG90LnRnghJjcGFuZWwuYmxvZ3Nwb3QudGeCEG1h
+aWwuYmxvZ3Nwb3QudGeCE3dlYmRpc2suYmxvZ3Nwb3QudGeCE3dlYm1haWwuYmxv
+Z3Nwb3QudGeCD3d3dy5ibG9nc3BvdC50ZzCB/gYDVR0gBIH2MIHzMAgGBmeBDAEC
+ATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0
+c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCBngyBm1RoaXMgQ2VydGlmaWNhdGUg
+bWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkgUmVseWluZyBQYXJ0aWVzIGFuZCBv
+bmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgQ2VydGlmaWNhdGUgUG9saWN5IGZv
+dW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQub3JnL3JlcG9zaXRvcnkvMA0GCSqG
+SIb3DQEBCwUAA4IBAQCFJfOffKOEXFmU0NYLISicCuxrFw2wPYxGkYzWDWB07FTb
+TScNW44mlP8KClmwno5rLxG6biAAPUksAy3AW9gYxMyX3A/s1fNdezq8EIaKPO0d
+bhks3ksKWoOQO/5YkKTzg2a5cRAv/WCH1EOvW0uHJu71A3LMfpnbyNYCAaHSpVoV
+6xqd5VxzGR387hVZD0pF4gkSX7zWifLzvYMB3IApPLR9v6XFGdWwZ5LMiFcqSoaU
+etGDuD3z+4xihhihafTsQjQR5w8eAtVTiVa64/YGUEV/9sXxTGERwwfB+p2IfxxH
+x3mYJwW/NMlS/3IzBB9SkvA4oJdbJ8nUd7cfWxng
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem b/net/data/ssl/blacklist/8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem
new file mode 100644
index 0000000..e16fbcf8
--- /dev/null
+++ b/net/data/ssl/blacklist/8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem
@@ -0,0 +1,72 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number:
+            34:fb:f0:8b:fe:6d:4d:eb:a5:2a:67:9b:30:da:28:68
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = TR, O = Elektronik Bilgi Guvenligi A.S., CN = E-GUVEN Kok Elektronik Sertifika Hizmet Saglayicisi S3
+        Validity
+            Not Before: Apr 14 13:01:28 2016 GMT
+            Not After : Apr 14 13:01:29 2017 GMT
+        Subject: C = TR, ST = Rize, L = Rize, O = ogr.rize.edu.tr, OU = \C3\96\C4\9ERENC\C4\B0 \C4\B0\C5\9ELER\C4\B0 DA\C4\B0RE BA\C5\9EKANLI\C4\9EI, CN = ogr.rize.edu.tr
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c8:0f:73:da:b2:3c:8b:c7:3a:9b:e3:08:83:3f:
+                    dd:66:f4:e8:f7:16:4f:a1:ec:e5:6a:7b:00:e4:20:
+                    6d:ab:da:96:32:b4:32:0e:27:35:de:48:cf:f2:cf:
+                    07:f9:12:4c:a7:ea:58:a2:e8:59:ea:a5:cb:34:64:
+                    f4:b0:79:9e:ad:a0:6a:79:eb:a6:89:7a:d0:b7:d2:
+                    8c:e3:ca:82:f7:0e:c6:43:bc:69:3f:12:f4:1b:55:
+                    66:39:96:6b:1b:93:a2:0f:ff:36:54:a3:60:c9:2b:
+                    76:ba:2c:e8:73:81:dd:17:d2:1c:d6:02:f8:5d:a9:
+                    f5:53:ab:4f:74:38:bb:0e:0e:5f:16:47:79:27:c9:
+                    1f:fd:80:13:59:c5:7e:5a:00:33:83:bc:66:96:e7:
+                    9c:63:ca:b2:ba:5c:b9:75:a2:3a:f2:76:b3:e9:1d:
+                    c5:34:0e:fa:42:c6:33:e6:e2:fb:78:3a:5b:f6:b6:
+                    fc:3c:15:53:18:0a:1b:64:26:0b:7b:66:71:c6:bb:
+                    68:5f:08:8b:ce:63:3f:77:9e:f8:27:b0:58:95:fe:
+                    67:46:06:28:e8:f5:b7:7b:15:5d:0a:1e:aa:73:c1:
+                    f1:c6:f6:4f:c0:ea:9f:2f:5f:10:7a:ac:04:79:6a:
+                    fc:cb:d9:43:1b:73:7c:73:78:d1:6d:91:0a:82:d1:
+                    95:79
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha256WithRSAEncryption
+         78:4b:e6:a4:92:2e:1e:25:83:b7:b0:3d:16:24:66:86:c2:a6:
+         2f:7e:5a:94:ab:d1:68:a8:0e:5a:c9:13:35:e9:c0:36:24:36:
+         50:91:51:b5:9d:9a:96:84:29:1f:72:39:d7:3f:fa:4c:cc:b3:
+         70:00:34:ba:a9:f7:1b:e2:3d:a8:7d:5a:5e:d0:cf:ce:2e:c6:
+         0d:31:9e:7e:0e:45:17:c1:44:e2:eb:7b:4b:86:99:b5:a5:bb:
+         15:ea:8e:ee:58:19:61:ad:fc:5b:77:71:50:f6:a4:0d:47:21:
+         c8:27:78:f4:05:b7:0a:44:70:7d:9f:94:41:c7:80:f1:b9:8f:
+         d1:3f:05:ab:92:db:e0:00:bf:1d:b3:e6:aa:cb:62:8b:65:18:
+         83:66:3a:f1:34:ba:81:0c:f0:a6:c7:60:30:07:5d:37:f5:5f:
+         4a:f1:bf:3d:ed:df:dd:40:32:63:01:1e:96:49:1e:16:83:d1:
+         75:a7:bc:cd:80:aa:d7:47:56:88:4b:5a:bb:53:b7:9b:3b:75:
+         a6:49:9b:b3:c2:5e:66:6b:51:46:d3:22:1a:cb:35:74:36:1d:
+         4b:c3:8f:5e:f6:29:0f:98:cb:a2:ca:2f:ec:56:67:cb:ce:5b:
+         2d:d0:a6:7a:d9:43:a8:ac:cd:ec:ec:94:c9:f6:29:af:f4:20:
+         57:3f:af:c9
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnYCEDT78Iv+bU3rpSpnmzDaKGgwDQYJKoZIhvcNAQELBQAweDELMAkG
+A1UEBhMCVFIxKDAmBgNVBAoMH0VsZWt0cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEu
+Uy4xPzA9BgNVBAMMNkUtR1VWRU4gS29rIEVsZWt0cm9uaWsgU2VydGlmaWthIEhp
+em1ldCBTYWdsYXlpY2lzaSBTMzAeFw0xNjA0MTQxMzAxMjhaFw0xNzA0MTQxMzAx
+MjlaMIGSMQswCQYDVQQGEwJUUjENMAsGA1UECBMEUml6ZTENMAsGA1UEBxMEUml6
+ZTEYMBYGA1UEChMPb2dyLnJpemUuZWR1LnRyMTEwLwYDVQQLDCjDlsSeUkVOQ8Sw
+IMSwxZ5MRVLEsCBEQcSwUkUgQkHFnktBTkxJxJ5JMRgwFgYDVQQDEw9vZ3Iucml6
+ZS5lZHUudHIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDID3PasjyL
+xzqb4wiDP91m9Oj3Fk+h7OVqewDkIG2r2pYytDIOJzXeSM/yzwf5Ekyn6lii6Fnq
+pcs0ZPSweZ6toGp566aJetC30ozjyoL3DsZDvGk/EvQbVWY5lmsbk6IP/zZUo2DJ
+K3a6LOhzgd0X0hzWAvhdqfVTq090OLsODl8WR3knyR/9gBNZxX5aADODvGaW55xj
+yrK6XLl1ojrydrPpHcU0DvpCxjPm4vt4Olv2tvw8FVMYChtkJgt7ZnHGu2hfCIvO
+Yz93nvgnsFiV/mdGBijo9bd7FV0KHqpzwfHG9k/A6p8vXxB6rAR5avzL2UMbc3xz
+eNFtkQqC0ZV5AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHhL5qSSLh4lg7ewPRYk
+ZobCpi9+WpSr0WioDlrJEzXpwDYkNlCRUbWdmpaEKR9yOdc/+kzMs3AANLqp9xvi
+Pah9Wl7Qz84uxg0xnn4ORRfBROLre0uGmbWluxXqju5YGWGt/Ft3cVD2pA1HIcgn
+ePQFtwpEcH2flEHHgPG5j9E/BauS2+AAvx2z5qrLYotlGINmOvE0uoEM8KbHYDAH
+XTf1X0rxvz3t391AMmMBHpZJHhaD0XWnvM2AqtdHVohLWrtTt5s7daZJm7PCXmZr
+UUbTIhrLNXQ2HUvDj172KQ+Yy6LKL+xWZ8vOWy3QpnrZQ6iszezslMn2Ka/0IFc/
+r8k=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/91e5cc32910686c5cac25c18cc805696c7b33868c280caf0c72844a2a8eb91e2.pem b/net/data/ssl/blacklist/91e5cc32910686c5cac25c18cc805696c7b33868c280caf0c72844a2a8eb91e2.pem
new file mode 100644
index 0000000..93751a3d
--- /dev/null
+++ b/net/data/ssl/blacklist/91e5cc32910686c5cac25c18cc805696c7b33868c280caf0c72844a2a8eb91e2.pem
@@ -0,0 +1,125 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            f4:a3:0e:d8:9f:11:07:a1
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = DK, ST = Denmark, L = "industriparken 27, 2750 Ballerup", O = Sennheiser Communications A/S, OU = R&D, CN = SenncomRootCA, emailAddress = support@senncom.com
+        Validity
+            Not Before: Aug  2 05:01:29 2017 GMT
+            Not After : Jul 28 05:01:29 2037 GMT
+        Subject: C = DK, ST = Denmark, L = "industriparken 27, 2750 Ballerup", O = Sennheiser Communications A/S, OU = R&D, CN = SenncomRootCA, emailAddress = support@senncom.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (4096 bit)
+                Modulus:
+                    00:c4:5d:4c:06:51:c1:27:38:af:e5:be:4d:4b:4c:
+                    92:ad:c6:00:92:8e:bb:37:4e:67:60:e6:7b:66:58:
+                    f4:fe:05:ab:77:54:13:8d:ee:98:57:cd:08:c9:50:
+                    a1:d9:17:77:31:c5:75:3d:ad:94:6a:4f:e9:0e:e9:
+                    f5:95:2d:33:e7:62:0f:f8:af:c3:64:b0:4e:de:44:
+                    1b:14:18:60:f5:55:8e:fc:39:3f:73:7d:cf:09:be:
+                    5f:43:71:b3:b1:43:f3:b2:eb:c4:62:8e:7c:77:b4:
+                    a4:52:5f:3d:9c:dc:5b:28:6a:22:d3:52:69:fe:9e:
+                    7e:7d:cc:c4:71:f7:04:8d:a1:02:ef:fc:60:cf:35:
+                    2b:fc:83:d8:32:da:52:95:1b:7a:65:e0:9b:97:5e:
+                    40:86:68:61:ad:30:af:0a:22:a9:64:d1:f0:3d:12:
+                    5f:29:ca:02:95:b5:d0:e5:bc:95:01:d4:78:3d:43:
+                    15:d5:d1:cd:52:ff:e6:24:05:5d:e6:6b:d9:98:2d:
+                    60:72:e5:e8:34:33:48:a0:6e:e4:50:ae:89:58:59:
+                    06:03:e4:1c:7b:36:50:60:81:16:09:91:b0:58:a7:
+                    84:1b:22:0a:d4:cb:0f:13:6b:fc:53:78:76:d4:16:
+                    5b:44:ab:23:64:ea:42:33:87:6c:b6:c3:1b:21:a2:
+                    69:71:4f:f8:bb:77:ec:81:b3:24:20:d4:1f:4b:28:
+                    4e:70:b4:92:b0:ba:94:05:bf:71:d7:d5:c7:23:7e:
+                    75:8f:ab:ee:87:c8:c2:69:bb:16:57:96:ee:5a:d5:
+                    4d:d0:82:4d:b1:14:33:8e:0d:1d:5b:f8:e5:0b:81:
+                    f5:c9:e0:ba:59:08:77:2f:d6:8e:bd:68:5e:b6:7f:
+                    d8:e7:b0:0e:ce:d7:a6:22:5c:5a:36:a1:da:87:70:
+                    a2:67:b3:f4:cc:a8:5e:57:a1:2d:cb:3f:d6:a5:8d:
+                    6c:0e:2b:e8:d8:8a:df:03:3c:10:b9:77:de:bd:19:
+                    b5:f8:94:92:df:d1:e2:b9:f3:7e:00:5c:ca:ce:90:
+                    ab:df:45:bc:bc:4d:f4:47:4d:11:a1:aa:26:32:50:
+                    ac:b0:04:08:c8:50:31:80:81:8f:87:70:c8:40:2e:
+                    a7:55:73:4f:7f:ab:ae:29:7e:fd:a5:06:e5:7c:c6:
+                    e6:65:da:72:6f:02:bd:40:ab:08:b0:34:f3:1d:b1:
+                    e1:f3:11:6b:0a:c1:be:db:ce:eb:23:18:4f:c9:b0:
+                    38:2e:e5:9f:08:15:45:82:ce:f7:26:10:0f:70:2d:
+                    ef:a5:d8:dd:99:19:75:dc:5c:c1:31:2c:76:6c:f2:
+                    bd:ba:48:c0:87:fa:7a:f1:78:5f:2f:96:53:29:56:
+                    44:24:cd
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                FD:1E:B5:6B:5F:09:59:92:9E:81:C6:B0:A6:91:32:4C:00:9F:44:47
+            X509v3 Authority Key Identifier: 
+                keyid:FD:1E:B5:6B:5F:09:59:92:9E:81:C6:B0:A6:91:32:4C:00:9F:44:47
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         13:86:48:92:9c:0c:b6:9d:a4:07:c3:de:fd:47:fe:bf:00:b7:
+         0b:b6:86:cc:79:1e:2e:a6:bd:d0:aa:19:52:ed:1d:b2:0b:e2:
+         d8:3b:64:e3:d1:86:b7:9d:39:d9:9b:df:86:18:f4:5c:65:64:
+         db:37:13:bf:d7:3e:0e:42:d6:79:e3:a9:b5:a2:cc:ed:69:aa:
+         27:0c:04:46:42:95:47:8f:45:9a:6e:4a:5c:54:a9:ef:2f:dc:
+         33:fa:7f:0e:db:49:99:48:1b:f3:17:67:80:66:d3:c9:33:48:
+         17:96:41:ee:e4:56:16:87:ce:2e:6f:78:02:4b:1e:b4:6a:1b:
+         cc:87:89:e3:9f:a7:1d:9c:05:3d:3b:c7:c9:96:34:08:a0:bd:
+         c2:26:cd:f2:aa:85:31:79:dd:5b:4b:63:a9:e0:83:ef:13:33:
+         4a:c5:c0:36:28:37:fc:d4:89:16:cf:d7:1b:07:a8:26:04:fd:
+         17:b8:85:0d:75:61:d6:71:75:6e:6e:f3:3c:34:86:1a:b4:a0:
+         a3:e8:ce:d6:52:4f:11:30:51:fb:7b:bb:e4:44:ad:97:6a:e5:
+         62:c0:3e:88:7e:a2:11:50:ee:2f:59:e5:f1:8f:52:e4:d1:84:
+         ed:58:84:8a:bd:78:92:3d:f4:06:16:9f:37:f5:8b:f2:34:b0:
+         6f:b0:c6:d3:14:e7:a5:30:c7:26:ff:6f:33:92:29:2d:a2:d0:
+         ea:e1:d6:06:7a:c7:40:f3:42:44:ed:1f:8a:ec:7b:74:27:ee:
+         f2:2f:7e:db:cc:01:10:66:a8:92:fe:34:2d:aa:53:40:14:a6:
+         19:43:a2:0d:92:78:7a:1b:38:01:bf:9a:1b:f3:cd:ea:cd:44:
+         fe:9b:b9:b5:53:45:16:8c:05:de:a9:f1:4f:20:14:cf:e0:34:
+         2e:4c:24:89:67:e3:a9:3e:c8:bd:e2:6c:d8:9b:11:ed:37:e8:
+         f6:6f:0e:d6:a3:0b:b7:f9:c2:2c:c8:07:e7:0e:41:43:89:f3:
+         91:b5:b2:98:dd:60:47:f0:4a:de:a9:2f:c0:d2:04:7d:37:0b:
+         70:79:b2:11:7a:1c:58:79:ad:97:91:a0:b7:2d:f3:cc:f8:aa:
+         cc:95:09:b0:b6:39:18:1d:ed:0d:5e:56:e2:49:95:42:65:5a:
+         c7:bf:f4:8f:66:78:18:53:1b:d9:27:84:50:bf:6e:2e:41:64:
+         fa:35:1d:b0:73:2a:bf:6e:71:21:f7:04:9a:2b:55:87:27:da:
+         4e:86:ab:8b:e5:0e:92:30:58:41:4c:da:67:99:c2:ce:03:e5:
+         bb:cf:78:85:b6:5c:72:90:da:4a:26:b4:5b:cd:8c:84:0d:69:
+         30:8f:c9:82:a3:b8:9e:18
+-----BEGIN CERTIFICATE-----
+MIIGTTCCBDWgAwIBAgIJAPSjDtifEQehMA0GCSqGSIb3DQEBCwUAMIG8MQswCQYD
+VQQGEwJESzEQMA4GA1UECAwHRGVubWFyazEpMCcGA1UEBwwgaW5kdXN0cmlwYXJr
+ZW4gMjcsIDI3NTAgQmFsbGVydXAxJjAkBgNVBAoMHVNlbm5oZWlzZXIgQ29tbXVu
+aWNhdGlvbnMgQS9TMQwwCgYDVQQLDANSJkQxFjAUBgNVBAMMDVNlbm5jb21Sb290
+Q0ExIjAgBgkqhkiG9w0BCQEWE3N1cHBvcnRAc2VubmNvbS5jb20wHhcNMTcwODAy
+MDUwMTI5WhcNMzcwNzI4MDUwMTI5WjCBvDELMAkGA1UEBhMCREsxEDAOBgNVBAgM
+B0Rlbm1hcmsxKTAnBgNVBAcMIGluZHVzdHJpcGFya2VuIDI3LCAyNzUwIEJhbGxl
+cnVwMSYwJAYDVQQKDB1TZW5uaGVpc2VyIENvbW11bmljYXRpb25zIEEvUzEMMAoG
+A1UECwwDUiZEMRYwFAYDVQQDDA1TZW5uY29tUm9vdENBMSIwIAYJKoZIhvcNAQkB
+FhNzdXBwb3J0QHNlbm5jb20uY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAxF1MBlHBJziv5b5NS0ySrcYAko67N05nYOZ7Zlj0/gWrd1QTje6YV80I
+yVCh2Rd3McV1Pa2Uak/pDun1lS0z52IP+K/DZLBO3kQbFBhg9VWO/Dk/c33PCb5f
+Q3GzsUPzsuvEYo58d7SkUl89nNxbKGoi01Jp/p5+fczEcfcEjaEC7/xgzzUr/IPY
+MtpSlRt6ZeCbl15AhmhhrTCvCiKpZNHwPRJfKcoClbXQ5byVAdR4PUMV1dHNUv/m
+JAVd5mvZmC1gcuXoNDNIoG7kUK6JWFkGA+QcezZQYIEWCZGwWKeEGyIK1MsPE2v8
+U3h21BZbRKsjZOpCM4dstsMbIaJpcU/4u3fsgbMkINQfSyhOcLSSsLqUBb9x19XH
+I351j6vuh8jCabsWV5buWtVN0IJNsRQzjg0dW/jlC4H1yeC6WQh3L9aOvWhetn/Y
+57AOztemIlxaNqHah3CiZ7P0zKheV6Etyz/WpY1sDivo2IrfAzwQuXfevRm1+JSS
+39HiufN+AFzKzpCr30W8vE30R00RoaomMlCssAQIyFAxgIGPh3DIQC6nVXNPf6uu
+KX79pQblfMbmZdpybwK9QKsIsDTzHbHh8xFrCsG+287rIxhPybA4LuWfCBVFgs73
+JhAPcC3vpdjdmRl13FzBMSx2bPK9ukjAh/p68XhfL5ZTKVZEJM0CAwEAAaNQME4w
+HQYDVR0OBBYEFP0etWtfCVmSnoHGsKaRMkwAn0RHMB8GA1UdIwQYMBaAFP0etWtf
+CVmSnoHGsKaRMkwAn0RHMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
+ABOGSJKcDLadpAfD3v1H/r8Atwu2hsx5Hi6mvdCqGVLtHbIL4tg7ZOPRhredOdmb
+34YY9FxlZNs3E7/XPg5C1nnjqbWizO1pqicMBEZClUePRZpuSlxUqe8v3DP6fw7b
+SZlIG/MXZ4Bm08kzSBeWQe7kVhaHzi5veAJLHrRqG8yHieOfpx2cBT07x8mWNAig
+vcImzfKqhTF53VtLY6ngg+8TM0rFwDYoN/zUiRbP1xsHqCYE/Re4hQ11YdZxdW5u
+8zw0hhq0oKPoztZSTxEwUft7u+RErZdq5WLAPoh+ohFQ7i9Z5fGPUuTRhO1YhIq9
+eJI99AYWnzf1i/I0sG+wxtMU56Uwxyb/bzOSKS2i0Orh1gZ6x0DzQkTtH4rse3Qn
+7vIvftvMARBmqJL+NC2qU0AUphlDog2SeHobOAG/mhvzzerNRP6bubVTRRaMBd6p
+8U8gFM/gNC5MJIln46k+yL3ibNibEe036PZvDtajC7f5wizIB+cOQUOJ85G1spjd
+YEfwSt6pL8DSBH03C3B5shF6HFh5rZeRoLct88z4qsyVCbC2ORgd7Q1eVuJJlUJl
+Wse/9I9meBhTG9knhFC/bi5BZPo1HbBzKr9ucSH3BJorVYcn2k6Gq4vlDpIwWEFM
+2meZws4D5bvPeIW2XHKQ2komtFvNjIQNaTCPyYKjuJ4Y
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/README.md b/net/data/ssl/blacklist/README.md
index c033bf7..758b198c 100644
--- a/net/data/ssl/blacklist/README.md
+++ b/net/data/ssl/blacklist/README.md
@@ -8,6 +8,12 @@
 
 ## Compromises & Misissuances
 
+### .bd
+
+google.com.bd certificates from Comodo.
+
+  * [487afc8d0d411b2a05561a2a6f35918f4040e5570c4c73ee323cc50583bcfbb7.pem](487afc8d0d411b2a05561a2a6f35918f4040e5570c4c73ee323cc50583bcfbb7.pem)
+
 ### China Internet Network Information Center (CNNIC)
 
 For details, see <https://security.googleblog.com/2015/03/maintaining-digital-certificate-security.html>
@@ -18,6 +24,7 @@
 
   * [1c01c6f4dbb2fefc22558b2bca32563f49844acfc32b7be4b0ff599f9e8c7af7.pem](1c01c6f4dbb2fefc22558b2bca32563f49844acfc32b7be4b0ff599f9e8c7af7.pem)
   * [e28393773da845a679f2080cc7fb44a3b7a1c3792cb7eb7729fdcb6a8d99aea7.pem](e28393773da845a679f2080cc7fb44a3b7a1c3792cb7eb7729fdcb6a8d99aea7.pem)
+  * [2740d956b1127b791aa1b3cc644a4dbedba76186a23638b95102351a834ea861.pem](2740d956b1127b791aa1b3cc644a4dbedba76186a23638b95102351a834ea861.pem)
 
 ### Comodo
 
@@ -38,6 +45,13 @@
   * [ead610e6e90b439f2ecb51628b0932620f6ef340bd843fca38d3181b8f4ba197.pem](ead610e6e90b439f2ecb51628b0932620f6ef340bd843fca38d3181b8f4ba197.pem)
   * [f8a5ff189fedbfe34e21103389a68340174439ad12974a4e8d4d784d1f3a0faa.pem](f8a5ff189fedbfe34e21103389a68340174439ad12974a4e8d4d784d1f3a0faa.pem)
 
+### DCSSI
+
+SPKI for an intermediate under the DCSSI root (French government) that was used
+to misissue gstatic.com certificates.
+
+  * [e54e9fc27e7350ff63a77764a40267b7e95ae5df3ed7df5336e8f8541356c845.pem](e54e9fc27e7350ff63a77764a40267b7e95ae5df3ed7df5336e8f8541356c845.pem)
+
 ### DigiNotar
 
 For details, see <https://googleonlinesecurity.blogspot.com/2011/08/update-on-attempted-man-in-middle.html>
@@ -72,6 +86,27 @@
   * [a8e1dfd9cd8e470aa2f443914f931cfd61c323e94d75827affee985241c35ce5.pem](a8e1dfd9cd8e470aa2f443914f931cfd61c323e94d75827affee985241c35ce5.pem)
   * [e4f9a3235df7330255f36412bc849fb630f8519961ec3538301deb896c953da5.pem](e4f9a3235df7330255f36412bc849fb630f8519961ec3538301deb896c953da5.pem)
 
+### Thawte
+
+A precert that appeared in the CT logs for (www.)google.com, issued by
+Thawte. See https://crt.sh/?id=9314698.
+
+  * [0d90cd8e35209b4cefebdd62b644bed8eb55c74dddff26e75caf8ae70491f0bd.pem](0d90cd8e35209b4cefebdd62b644bed8eb55c74dddff26e75caf8ae70491f0bd.pem)
+
+### Togo
+
+google.tg certificates from Let's Encrypt. https://crt.sh/?id=245397170 and
+others.
+
+  * [0ef7c54a3af101a2cfedb0c9f36fe8214d51a504fdc2ad1e243019cefd7d03c2.pem](0ef7c54a3af101a2cfedb0c9f36fe8214d51a504fdc2ad1e243019cefd7d03c2.pem)
+  * [2a4397aafa6227fa11f9f9d76ecbb022b0a4494852c2b93fb2085c8afb19b62a.pem](2a4397aafa6227fa11f9f9d76ecbb022b0a4494852c2b93fb2085c8afb19b62a.pem)
+  * [5472692abe5d02cd22eae3e0a0077f17802721d6576cde1cba2263ee803410c5.pem](5472692abe5d02cd22eae3e0a0077f17802721d6576cde1cba2263ee803410c5.pem)
+  * [5ccaf9f8f2bb3a0d215922eca383354b6ee3c62407ed32e30f6fb2618edeea10.pem](5ccaf9f8f2bb3a0d215922eca383354b6ee3c62407ed32e30f6fb2618edeea10.pem)
+  * [5e8e77aafdda2ba5ce442f27d8246650bbd6508befbeda35966a4dc7e6174edc.pem](5e8e77aafdda2ba5ce442f27d8246650bbd6508befbeda35966a4dc7e6174edc.pem)
+  * [a2e3bdaacaaf2d2e8204b3bc7eddc805d54d3ab8bdfe7bf102c035f67d8f898a.pem](a2e3bdaacaaf2d2e8204b3bc7eddc805d54d3ab8bdfe7bf102c035f67d8f898a.pem)
+  * [c71f33c36d8efeefbed9d44e85e21cfe96b36fb0e132c52dca2415868492bf8a.pem](c71f33c36d8efeefbed9d44e85e21cfe96b36fb0e132c52dca2415868492bf8a.pem)
+  * [fa5a828c9a7e732692682e60b14c634309cbb2bb79eb12aef44318d853ee97e3.pem](fa5a828c9a7e732692682e60b14c634309cbb2bb79eb12aef44318d853ee97e3.pem)
+
 ### Trustwave
 
 For details, see <https://www.trustwave.com/Resources/SpiderLabs-Blog/Clarifying-The-Trustwave-CA-Policy-Update/>
@@ -131,6 +166,13 @@
   * [3ab0fcc7287454c405863e3aa204fea8eb0c50a524d2a7e15524a830cd4ab0fe.pem](3ab0fcc7287454c405863e3aa204fea8eb0c50a524d2a7e15524a830cd4ab0fe.pem)
   * [60911c79835c3739432d08c45df64311e06985c5889dc5420ce3d142c8c7ef58.pem](60911c79835c3739432d08c45df64311e06985c5889dc5420ce3d142c8c7ef58.pem)
 
+### Sennheiser
+
+Certs with disclosed private keys from Sennheiser HeadSetup software.
+
+  * [91e5cc32910686c5cac25c18cc805696c7b33868c280caf0c72844a2a8eb91e2.pem](91e5cc32910686c5cac25c18cc805696c7b33868c280caf0c72844a2a8eb91e2.pem)
+  * [ddd8ab9178c99cbd9685ea4ae66dc28bfdc9a5a8a166f7f69ad0b5042ad6eb28.pem](ddd8ab9178c99cbd9685ea4ae66dc28bfdc9a5a8a166f7f69ad0b5042ad6eb28.pem)
+
 ### sslip.io
 
 For details, see <https://blog.pivotal.io/labs/labs/sslip-io-a-valid-ssl-certificate-for-every-ip-address>
@@ -178,6 +220,12 @@
   * [159ca03a88897c8f13817a212629df84ce824709492b8c9adb8e5437d2fc72be.pem](159ca03a88897c8f13817a212629df84ce824709492b8c9adb8e5437d2fc72be.pem)
   * [b8c1b957c077ea76e00b0f45bff5ae3acb696f221d2e062164fe37125e5a8d25.pem](b8c1b957c077ea76e00b0f45bff5ae3acb696f221d2e062164fe37125e5a8d25.pem)
 
+### E-GUVEN
+
+X.509v1 CA cert issued by E-GUVEN.  Removed from some but not all root stores.
+
+  * [8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem](8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem)
+
 ### Hacking Team
 
 The following keys were reported as used by Hacking Team to compromise users,
@@ -186,6 +234,14 @@
   * [c4387d45364a313fbfe79812b35b815d42852ab03b06f11589638021c8f2cb44.key](c4387d45364a313fbfe79812b35b815d42852ab03b06f11589638021c8f2cb44.key)
   * [ea08c8d45d52ca593de524f0513ca6418da9859f7b08ef13ff9dd7bf612d6a37.key](ea08c8d45d52ca593de524f0513ca6418da9859f7b08ef13ff9dd7bf612d6a37.key)
 
+### JCSI
+
+"Lost" intermediate from Japan Certification Services.  See
+https://bugzilla.mozilla.org/show_bug.cgi?id=1314464, https://crt.sh/?id=6320.
+
+  * [d0d672c2547d574ae055d9e78a993ddbcc74044c4253fbfaca573a67d368e1db.pem](d0d672c2547d574ae055d9e78a993ddbcc74044c4253fbfaca573a67d368e1db.pem)
+
+
 ### live.fi
 
 For details, see <https://technet.microsoft.com/en-us/library/security/3046310.aspx>
@@ -198,6 +254,21 @@
 
   * [c67d722c1495be02cbf9ef1159f5ca4aa782dc832dc6aa60c9aa076a0ad1e69d.pem](c67d722c1495be02cbf9ef1159f5ca4aa782dc832dc6aa60c9aa076a0ad1e69d.pem)
 
+### Microsoft Dynamics 365
+
+https://bugzilla.mozilla.org/show_bug.cgi?id=1423400
+
+  * [3d3d823fad13dfeef32da580166d4a4992bed5a22d695d12c8b08cc3463c67a2.pem](3d3d823fad13dfeef32da580166d4a4992bed5a22d695d12c8b08cc3463c67a2.pem)
+  * [c43807a64c51a3fbde5421011698013d8b46f4e315c46186dc23aea2670cd34f.pem](c43807a64c51a3fbde5421011698013d8b46f4e315c46186dc23aea2670cd34f.pem)
+
+### revoked.badssl.com
+
+  * [2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem](2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem)
+
+### revoked.grc.com
+
+  * [53d48e7b8869a3314f213fd2e0178219ca09022dbe50053bf6f76fccd61e8112.pem](53d48e7b8869a3314f213fd2e0178219ca09022dbe50053bf6f76fccd61e8112.pem)
+
 ### SECOM
 
 For details, see <https://bugzilla.mozilla.org/show_bug.cgi?id=1188582>
@@ -239,3 +310,9 @@
   * [d487a56f83b07482e85e963394c1ecc2c9e51d0903ee946b02c301581ed99e16.pem](d487a56f83b07482e85e963394c1ecc2c9e51d0903ee946b02c301581ed99e16.pem)
   * [d6f034bd94aa233f0297eca4245b283973e447aa590f310c77f48fdf83112254.pem](d6f034bd94aa233f0297eca4245b283973e447aa590f310c77f48fdf83112254.pem)
   * [e17890ee09a3fbf4f48b9c414a17d637b7a50647e9bc752322727fcc1742a911.pem](e17890ee09a3fbf4f48b9c414a17d637b7a50647e9bc752322727fcc1742a911.pem)
+  * [4aefc3d39ef59e4d4b0304b20f53a8af2efb69edece66def74494abfc10a2d66.pem](4aefc3d39ef59e4d4b0304b20f53a8af2efb69edece66def74494abfc10a2d66.pem)
+  * [cb954e9d80a3e520ac71f1a84511657f2f309d172d0bb55e0ec2c236e74ff4b4.pem](cb954e9d80a3e520ac71f1a84511657f2f309d172d0bb55e0ec2c236e74ff4b4.pem)
+
+### www.cloudflarechallenge.com
+
+  * [e757fd60d8dd4c26f77aca6a87f63ea4d38d0b736c7f79b56cad932d4c400fb5.pem](e757fd60d8dd4c26f77aca6a87f63ea4d38d0b736c7f79b56cad932d4c400fb5.pem)
diff --git a/net/data/ssl/blacklist/a2e3bdaacaaf2d2e8204b3bc7eddc805d54d3ab8bdfe7bf102c035f67d8f898a.pem b/net/data/ssl/blacklist/a2e3bdaacaaf2d2e8204b3bc7eddc805d54d3ab8bdfe7bf102c035f67d8f898a.pem
new file mode 100644
index 0000000..f41be0c2
--- /dev/null
+++ b/net/data/ssl/blacklist/a2e3bdaacaaf2d2e8204b3bc7eddc805d54d3ab8bdfe7bf102c035f67d8f898a.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:bb:b2:fa:b9:93:6a:fe:ad:0c:7e:1d:46:bb:27:bd:71:87
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 13:09:44 2017 GMT
+            Not After : Jan 30 13:09:44 2018 GMT
+        Subject: CN = igoogle.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b0:75:6e:16:81:16:71:aa:e3:63:e1:50:14:f4:
+                    e4:a0:09:4b:f9:d7:13:e6:8b:e1:61:21:e4:00:0e:
+                    10:75:b8:d2:6f:21:73:9e:c3:28:ac:0e:1d:6a:87:
+                    57:64:47:c4:12:4a:12:f2:b6:4a:ec:cc:55:d7:5d:
+                    94:e2:3f:e7:b7:4e:44:bd:95:80:ff:46:a5:ac:90:
+                    e3:67:17:2c:f2:d4:dc:1e:52:ad:60:7f:37:58:63:
+                    5b:be:6a:66:a6:41:dd:46:f8:c5:3d:54:a1:2e:de:
+                    3a:2e:45:36:03:12:dd:4f:b2:46:67:87:b0:49:08:
+                    6b:de:f6:82:24:6b:07:e2:dd:10:dc:ed:18:ba:e9:
+                    0c:32:49:2d:ab:cc:d1:b3:ee:41:7d:e4:50:51:1f:
+                    4c:7b:35:4e:3a:93:b8:a5:6d:85:50:aa:92:3b:81:
+                    de:20:34:34:30:09:d7:bd:c3:ba:39:72:1b:88:64:
+                    20:c2:e5:fa:d4:5f:ef:a0:b9:80:e1:09:c4:9f:ed:
+                    89:a9:fa:e1:0a:d3:d9:53:ad:2f:65:7e:9e:5b:e6:
+                    98:2c:3b:1b:48:84:25:c8:90:65:59:02:76:3a:05:
+                    fa:f7:1c:55:79:7d:8b:18:bc:e4:ff:ae:16:49:d0:
+                    50:cd:30:c2:c8:08:08:67:ca:a6:62:04:a1:ab:d6:
+                    6d:15
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                0D:B7:11:96:5F:16:25:53:88:89:E8:8C:96:E9:0A:08:BE:91:61:DC
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:cpanel.igoogle.tg, DNS:igoogle.tg, DNS:mail.igoogle.tg, DNS:webdisk.igoogle.tg, DNS:webmail.igoogle.tg, DNS:www.igoogle.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         92:c0:bb:00:b6:64:ca:e4:73:04:36:64:d5:48:91:ac:ec:54:
+         cc:d0:d8:9d:3b:5c:9e:ee:a0:2c:90:1b:fa:ba:56:56:d4:e5:
+         47:f7:4b:89:97:3a:fa:32:7e:78:30:66:e3:5e:fa:41:fe:f2:
+         4f:ab:a3:e8:dc:be:22:33:d8:79:45:30:f6:90:76:48:6a:7c:
+         3f:78:7e:57:89:ed:fa:f8:7c:c4:8c:a3:b3:13:f0:96:7c:84:
+         ef:4a:37:b8:f4:40:d3:ef:64:c0:8c:45:05:f0:44:f2:57:87:
+         8f:e3:11:75:92:f3:de:89:54:8c:35:23:e1:1f:70:e7:0b:c3:
+         62:fc:6d:7b:4c:c0:09:9d:a1:b8:3c:7f:a2:91:89:b2:96:5f:
+         50:6d:c6:ab:63:da:df:4f:c4:7a:12:9b:bf:f1:56:9e:66:60:
+         de:9a:f4:84:f7:e4:e4:79:06:d9:6e:c7:6d:36:a0:6a:d5:e3:
+         10:3e:b9:8b:50:05:33:05:8e:a3:66:8f:1a:aa:e4:63:22:b9:
+         c8:a0:f0:4c:f0:83:1e:56:6b:1a:9b:f7:e8:7d:c1:e8:8f:14:
+         20:65:e5:34:74:d3:a0:1c:41:b5:2d:f3:ad:90:34:d7:4f:db:
+         e0:b7:19:85:f0:f5:ff:79:fe:b4:36:73:b1:45:aa:99:72:7b:
+         e0:6f:20:c0
+-----BEGIN CERTIFICATE-----
+MIIFUzCCBDugAwIBAgISA7uy+rmTav6tDH4dRrsnvXGHMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMzA5NDRaFw0x
+ODAxMzAxMzA5NDRaMBUxEzARBgNVBAMTCmlnb29nbGUudGcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCwdW4WgRZxquNj4VAU9OSgCUv51xPmi+FhIeQA
+DhB1uNJvIXOewyisDh1qh1dkR8QSShLytkrszFXXXZTiP+e3TkS9lYD/RqWskONn
+Fyzy1NweUq1gfzdYY1u+amamQd1G+MU9VKEu3jouRTYDEt1PskZnh7BJCGve9oIk
+awfi3RDc7Ri66QwySS2rzNGz7kF95FBRH0x7NU46k7ilbYVQqpI7gd4gNDQwCde9
+w7o5chuIZCDC5frUX++guYDhCcSf7Ymp+uEK09lTrS9lfp5b5pgsOxtIhCXIkGVZ
+AnY6Bfr3HFV5fYsYvOT/rhZJ0FDNMMLICAhnyqZiBKGr1m0VAgMBAAGjggJmMIIC
+YjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
+MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFA23EZZfFiVTiInojJbpCgi+kWHcMB8G
+A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAu
+BggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAv
+BggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
+cQYDVR0RBGowaIIRY3BhbmVsLmlnb29nbGUudGeCCmlnb29nbGUudGeCD21haWwu
+aWdvb2dsZS50Z4ISd2ViZGlzay5pZ29vZ2xlLnRnghJ3ZWJtYWlsLmlnb29nbGUu
+dGeCDnd3dy5pZ29vZ2xlLnRnMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsr
+BgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlw
+dC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25s
+eSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4g
+YWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQg
+aHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEL
+BQADggEBAJLAuwC2ZMrkcwQ2ZNVIkazsVMzQ2J07XJ7uoCyQG/q6VlbU5Uf3S4mX
+OvoyfngwZuNe+kH+8k+ro+jcviIz2HlFMPaQdkhqfD94fleJ7fr4fMSMo7MT8JZ8
+hO9KN7j0QNPvZMCMRQXwRPJXh4/jEXWS896JVIw1I+EfcOcLw2L8bXtMwAmdobg8
+f6KRibKWX1Btxqtj2t9PxHoSm7/xVp5mYN6a9IT35OR5Btlux202oGrV4xA+uYtQ
+BTMFjqNmjxqq5GMiucig8Ezwgx5Waxqb9+h9weiPFCBl5TR006AcQbUt862QNNdP
+2+C3GYXw9f95/rQ2c7FFqplye+BvIMA=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/c43807a64c51a3fbde5421011698013d8b46f4e315c46186dc23aea2670cd34f.pem b/net/data/ssl/blacklist/c43807a64c51a3fbde5421011698013d8b46f4e315c46186dc23aea2670cd34f.pem
new file mode 100644
index 0000000..f8015e05
--- /dev/null
+++ b/net/data/ssl/blacklist/c43807a64c51a3fbde5421011698013d8b46f4e315c46186dc23aea2670cd34f.pem
Binary files differ
diff --git a/net/data/ssl/blacklist/c71f33c36d8efeefbed9d44e85e21cfe96b36fb0e132c52dca2415868492bf8a.pem b/net/data/ssl/blacklist/c71f33c36d8efeefbed9d44e85e21cfe96b36fb0e132c52dca2415868492bf8a.pem
new file mode 100644
index 0000000..bf145b4
--- /dev/null
+++ b/net/data/ssl/blacklist/c71f33c36d8efeefbed9d44e85e21cfe96b36fb0e132c52dca2415868492bf8a.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:1e:89:9b:b6:a3:57:8f:6d:a8:78:1f:f6:76:27:cd:10:88
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 13:11:37 2017 GMT
+            Not After : Jan 30 13:11:37 2018 GMT
+        Subject: CN = blogger.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:f2:9a:15:5f:4c:5b:35:83:62:a5:b5:b7:0c:c1:
+                    30:35:4b:b9:7d:54:a0:6f:07:ce:8e:55:5c:14:26:
+                    30:cd:a4:59:16:09:2e:7a:c0:f4:e5:19:80:a3:16:
+                    2b:eb:f8:0c:48:f9:b2:52:7c:83:30:56:7a:21:27:
+                    aa:47:39:23:e1:19:27:ce:10:75:f4:a4:80:f7:43:
+                    10:de:da:a7:f1:53:7b:e8:4b:09:3d:d7:8c:a4:45:
+                    28:cf:d0:3f:84:37:1e:eb:15:79:16:be:cd:86:b8:
+                    c1:7b:ec:d4:42:af:bf:0c:80:70:17:d3:02:33:e9:
+                    60:41:6b:b5:41:95:9d:de:2a:07:7c:c3:7d:b5:93:
+                    30:9c:32:31:69:30:bc:e6:ca:a1:6f:f0:68:8e:3f:
+                    8a:67:f5:1a:24:74:8c:99:03:b4:d6:fa:dd:dd:44:
+                    c6:48:49:bf:06:ec:66:ee:9f:92:7f:a3:d4:44:bb:
+                    94:ed:57:28:bd:ae:76:25:29:7a:ef:ed:d0:cf:b3:
+                    48:c9:a8:e8:09:da:83:af:d5:98:5a:f3:13:61:af:
+                    0f:de:42:a7:3d:2a:2d:78:1c:55:e8:2c:4e:60:ad:
+                    dd:f1:69:0b:d4:75:79:d1:5b:79:20:4d:85:6b:4f:
+                    ef:8c:12:0b:5a:5e:ab:eb:2b:ce:b0:3e:2c:e4:e1:
+                    dc:63
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                49:A6:7F:93:AC:61:EB:CC:C7:FC:B6:EE:C2:49:77:2B:D9:D7:EF:4B
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:blogger.tg, DNS:cpanel.blogger.tg, DNS:mail.blogger.tg, DNS:webdisk.blogger.tg, DNS:webmail.blogger.tg, DNS:www.blogger.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         7a:04:0a:a7:6e:cc:ef:17:02:d0:96:ce:5d:8c:7a:0d:c0:3e:
+         ed:83:80:31:9f:58:7d:b7:2f:3c:59:06:54:49:dd:56:4e:1c:
+         32:58:61:15:7b:bd:09:30:9d:15:3f:0e:9a:4d:d7:dd:1e:8c:
+         b7:bc:08:09:1b:17:68:5e:de:d0:e1:d0:cd:0d:01:a7:ca:8f:
+         f3:0a:c9:d1:c8:8a:40:51:66:bc:7a:86:2c:5e:55:0a:72:8d:
+         e7:d7:fc:31:b3:89:c3:50:39:47:74:4d:2f:7b:c7:32:fe:17:
+         d3:3a:67:d9:11:3e:50:15:06:39:1d:fd:e7:f0:66:40:1c:e2:
+         68:be:6a:8e:53:7c:bd:e3:11:12:1b:6a:a6:8f:67:4a:2c:a2:
+         ef:2b:75:43:91:79:ce:0a:07:1f:9d:90:fa:ed:bf:75:c1:f4:
+         fb:38:64:5e:f0:7c:69:d0:06:94:d5:20:e4:b9:8a:a5:fe:90:
+         53:11:dd:be:fb:23:52:bc:85:ef:bc:dc:bf:27:b9:72:62:d8:
+         80:30:dc:5a:83:15:8a:24:7e:36:fa:3f:0c:bd:2f:74:25:00:
+         9a:60:66:fb:6a:d4:8b:51:81:e8:68:8f:93:80:0b:52:4d:64:
+         e8:c5:a2:a9:01:8b:03:e6:b6:89:76:14:a7:1f:34:4f:50:ad:
+         c6:76:a1:83
+-----BEGIN CERTIFICATE-----
+MIIFUzCCBDugAwIBAgISAx6Jm7ajV49tqHgf9nYnzRCIMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMzExMzdaFw0x
+ODAxMzAxMzExMzdaMBUxEzARBgNVBAMTCmJsb2dnZXIudGcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDymhVfTFs1g2KltbcMwTA1S7l9VKBvB86OVVwU
+JjDNpFkWCS56wPTlGYCjFivr+AxI+bJSfIMwVnohJ6pHOSPhGSfOEHX0pID3QxDe
+2qfxU3voSwk914ykRSjP0D+ENx7rFXkWvs2GuMF77NRCr78MgHAX0wIz6WBBa7VB
+lZ3eKgd8w321kzCcMjFpMLzmyqFv8GiOP4pn9RokdIyZA7TW+t3dRMZISb8G7Gbu
+n5J/o9REu5TtVyi9rnYlKXrv7dDPs0jJqOgJ2oOv1Zha8xNhrw/eQqc9Ki14HFXo
+LE5grd3xaQvUdXnRW3kgTYVrT++MEgtaXqvrK86wPizk4dxjAgMBAAGjggJmMIIC
+YjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
+MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmmf5OsYevMx/y27sJJdyvZ1+9LMB8G
+A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAu
+BggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAv
+BggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
+cQYDVR0RBGowaIIKYmxvZ2dlci50Z4IRY3BhbmVsLmJsb2dnZXIudGeCD21haWwu
+YmxvZ2dlci50Z4ISd2ViZGlzay5ibG9nZ2VyLnRnghJ3ZWJtYWlsLmJsb2dnZXIu
+dGeCDnd3dy5ibG9nZ2VyLnRnMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsr
+BgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlw
+dC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25s
+eSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4g
+YWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQg
+aHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEL
+BQADggEBAHoECqduzO8XAtCWzl2Meg3APu2DgDGfWH23LzxZBlRJ3VZOHDJYYRV7
+vQkwnRU/DppN190ejLe8CAkbF2he3tDh0M0NAafKj/MKydHIikBRZrx6hixeVQpy
+jefX/DGzicNQOUd0TS97xzL+F9M6Z9kRPlAVBjkd/efwZkAc4mi+ao5TfL3jERIb
+aqaPZ0osou8rdUORec4KBx+dkPrtv3XB9Ps4ZF7wfGnQBpTVIOS5iqX+kFMR3b77
+I1K8he+83L8nuXJi2IAw3FqDFYokfjb6Pwy9L3QlAJpgZvtq1ItRgehoj5OAC1JN
+ZOjFoqkBiwPmtol2FKcfNE9QrcZ2oYM=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/cb954e9d80a3e520ac71f1a84511657f2f309d172d0bb55e0ec2c236e74ff4b4.pem b/net/data/ssl/blacklist/cb954e9d80a3e520ac71f1a84511657f2f309d172d0bb55e0ec2c236e74ff4b4.pem
new file mode 100644
index 0000000..0604c1e5
--- /dev/null
+++ b/net/data/ssl/blacklist/cb954e9d80a3e520ac71f1a84511657f2f309d172d0bb55e0ec2c236e74ff4b4.pem
@@ -0,0 +1,107 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            5d:8f:2b:91:ef:b8:dd:65:af:4c:c1:2b:15:ef:4b:6e
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = CN, O = WoSign CA Limited, CN = WoSign CA Free SSL Certificate G2
+        Validity
+            Not Before: Jun 10 05:42:44 2015 GMT
+            Not After : Jun 10 06:03:35 2018 GMT
+        Subject: CN = schrauger.github.io
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e4:3b:a1:76:73:3c:b1:62:8d:53:6d:ef:a8:e9:
+                    5b:9e:0e:15:63:e6:57:ac:cc:31:b3:48:2b:01:74:
+                    ae:d8:7d:1c:6b:ed:2a:40:45:36:62:83:ac:d7:a5:
+                    80:9c:21:88:dc:ec:4d:ae:35:5d:65:e6:95:ee:81:
+                    7a:1f:b5:a7:e9:19:f8:7a:42:ff:dc:b4:71:63:ce:
+                    3c:70:6f:89:54:af:57:de:27:bb:79:07:54:44:68:
+                    ee:1c:7e:14:d9:eb:bc:4e:99:52:f6:b5:34:30:2c:
+                    38:63:7b:95:8a:ea:54:7e:d5:4b:f0:1d:73:3b:03:
+                    ea:12:2d:8a:3c:ea:f2:f1:04:5a:1b:8b:cf:3e:c9:
+                    98:e6:2a:69:53:67:61:d0:6b:79:33:b6:08:3a:be:
+                    dd:16:d6:02:ab:f2:6d:e0:02:be:f2:d9:13:6b:08:
+                    b7:f2:de:fa:79:d1:4c:39:f8:bb:e5:18:89:f2:2b:
+                    b6:df:59:54:9e:8a:48:0e:06:fb:eb:ad:e0:2a:b5:
+                    0a:e8:51:45:bc:ac:51:65:cf:69:de:64:8f:30:e0:
+                    d7:c6:c1:fd:30:1d:99:ea:7c:3d:d4:f6:bb:87:c9:
+                    dd:f0:e4:74:4e:92:2d:27:5e:8c:fc:42:79:7f:59:
+                    7c:f4:40:71:de:c3:b8:6e:a9:21:7e:8f:8c:7d:2c:
+                    2c:85
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication, TLS Web Server Authentication
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                F7:8A:D1:06:8A:4B:6F:1F:B2:BA:39:A6:03:D7:C7:61:E5:14:0C:05
+            X509v3 Authority Key Identifier: 
+                keyid:D2:A7:16:20:7C:AF:D9:95:9E:EB:43:0A:19:F2:E0:B9:74:0E:A8:C7
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp6.wosign.com/ca6/server1/free
+                CA Issuers - URI:http://aia6.wosign.com/ca6.server1.free.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crls6.wosign.com/ca6-server1-free.crl
+
+            X509v3 Subject Alternative Name: 
+                DNS:schrauger.github.io, DNS:schrauger.github.com, DNS:github.io, DNS:github.com, DNS:www.github.io
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.36305.6.1.2.2.1
+                  CPS: http://www.wosign.com/policy/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         36:1f:74:a6:b4:98:b6:95:b3:7e:d1:c7:91:0c:5a:35:bd:05:
+         00:3f:93:c2:1d:72:e0:b9:36:32:a3:d8:0d:91:53:f5:f9:f6:
+         30:38:d3:06:02:7a:30:aa:90:38:aa:b7:aa:06:c9:7b:9e:4c:
+         21:67:70:fd:c2:16:a3:c1:b0:73:ae:e5:b9:a6:e8:d7:f1:76:
+         ce:a4:71:be:f0:1a:81:3c:ee:7a:8e:7a:1e:b7:5d:28:89:bf:
+         62:c2:1d:75:47:b1:e5:51:95:48:f1:d5:1a:a4:71:09:c5:59:
+         79:dc:04:88:3e:40:c2:3d:b6:92:ee:4d:67:61:7a:c8:42:32:
+         e2:83:6a:0d:98:a9:69:71:12:f3:d7:f2:36:d5:7f:fa:b3:fd:
+         1e:97:16:ab:81:08:d1:f5:67:11:7a:73:3d:5d:79:35:f5:57:
+         56:ed:52:5d:86:af:07:5b:af:bd:62:87:c7:4e:c5:4f:59:fe:
+         1c:c6:35:ef:36:3c:b7:43:e8:b6:b1:b8:d9:1e:a2:fc:7c:a9:
+         f2:98:ff:3d:76:f2:75:0d:13:e4:f8:cd:f8:c5:f6:c0:60:06:
+         9c:3a:13:e0:ff:86:5a:14:a6:6e:2e:e6:ca:10:01:c0:d9:34:
+         a2:07:ab:0a:ba:19:79:c0:9c:b0:c5:97:c4:b4:64:12:c3:ce:
+         e4:c1:fd:ae
+-----BEGIN CERTIFICATE-----
+MIIE5zCCA8+gAwIBAgIQXY8rke+43WWvTMErFe9LbjANBgkqhkiG9w0BAQsFADBV
+MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV
+BAMTIVdvU2lnbiBDQSBGcmVlIFNTTCBDZXJ0aWZpY2F0ZSBHMjAeFw0xNTA2MTAw
+NTQyNDRaFw0xODA2MTAwNjAzMzVaMB4xHDAaBgNVBAMME3NjaHJhdWdlci5naXRo
+dWIuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkO6F2czyxYo1T
+be+o6VueDhVj5leszDGzSCsBdK7YfRxr7SpARTZig6zXpYCcIYjc7E2uNV1l5pXu
+gXoftafpGfh6Qv/ctHFjzjxwb4lUr1feJ7t5B1REaO4cfhTZ67xOmVL2tTQwLDhj
+e5WK6lR+1UvwHXM7A+oSLYo86vLxBFobi88+yZjmKmlTZ2HQa3kztgg6vt0W1gKr
+8m3gAr7y2RNrCLfy3vp50Uw5+LvlGInyK7bfWVSeikgOBvvrreAqtQroUUW8rFFl
+z2neZI8w4NfGwf0wHZnqfD3U9ruHyd3w5HROki0nXoz8Qnl/WXz0QHHew7huqSF+
+j4x9LCyFAgMBAAGjggHoMIIB5DALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
+BQUHAwIGCCsGAQUFBwMBMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPeK0QaKS28fsro5
+pgPXx2HlFAwFMB8GA1UdIwQYMBaAFNKnFiB8r9mVnutDChny4Ll0DqjHMH0GCCsG
+AQUFBwEBBHEwbzA0BggrBgEFBQcwAYYoaHR0cDovL29jc3A2Lndvc2lnbi5jb20v
+Y2E2L3NlcnZlcjEvZnJlZTA3BggrBgEFBQcwAoYraHR0cDovL2FpYTYud29zaWdu
+LmNvbS9jYTYuc2VydmVyMS5mcmVlLmNlcjA9BgNVHR8ENjA0MDKgMKAuhixodHRw
+Oi8vY3JsczYud29zaWduLmNvbS9jYTYtc2VydmVyMS1mcmVlLmNybDBaBgNVHREE
+UzBRghNzY2hyYXVnZXIuZ2l0aHViLmlvghRzY2hyYXVnZXIuZ2l0aHViLmNvbYIJ
+Z2l0aHViLmlvggpnaXRodWIuY29tgg13d3cuZ2l0aHViLmlvMFEGA1UdIARKMEgw
+CAYGZ4EMAQIBMDwGDSsGAQQBgptRBgECAgEwKzApBggrBgEFBQcCARYdaHR0cDov
+L3d3dy53b3NpZ24uY29tL3BvbGljeS8wDQYJKoZIhvcNAQELBQADggEBADYfdKa0
+mLaVs37Rx5EMWjW9BQA/k8IdcuC5NjKj2A2RU/X59jA40wYCejCqkDiqt6oGyXue
+TCFncP3CFqPBsHOu5bmm6Nfxds6kcb7wGoE87nqOeh63XSiJv2LCHXVHseVRlUjx
+1RqkcQnFWXncBIg+QMI9tpLuTWdheshCMuKDag2YqWlxEvPX8jbVf/qz/R6XFquB
+CNH1ZxF6cz1deTX1V1btUl2Grwdbr71ih8dOxU9Z/hzGNe82PLdD6LaxuNkeovx8
+qfKY/z128nUNE+T4zfjF9sBgBpw6E+D/hloUpm4u5soQAcDZNKIHqwq6GXnAnLDF
+l8S0ZBLDzuTB/a4=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/d0d672c2547d574ae055d9e78a993ddbcc74044c4253fbfaca573a67d368e1db.pem b/net/data/ssl/blacklist/d0d672c2547d574ae055d9e78a993ddbcc74044c4253fbfaca573a67d368e1db.pem
new file mode 100644
index 0000000..893e5a4
--- /dev/null
+++ b/net/data/ssl/blacklist/d0d672c2547d574ae055d9e78a993ddbcc74044c4253fbfaca573a67d368e1db.pem
@@ -0,0 +1,94 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C = JP, O = "Japan Certification Services, Inc.", CN = SecureSign RootCA11
+        Validity
+            Not Before: Apr  8 09:06:51 2009 GMT
+            Not After : Apr  8 04:56:47 2029 GMT
+        Subject: C = JP, O = "Japan Certification Services, Inc.", CN = SecureSign Public CA11
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:d7:ab:4d:71:6b:7b:a1:5f:b8:e6:d6:13:85:bb:
+                    b5:41:b6:fc:d7:66:98:7e:85:67:56:aa:b9:f6:53:
+                    d7:fe:22:52:33:20:aa:f5:86:ba:12:1e:53:ea:4e:
+                    2c:3d:e0:8d:ef:45:9d:c8:e3:8b:b4:69:09:91:ac:
+                    ff:6d:6a:77:c8:d6:d7:5d:8f:08:0a:e0:aa:a2:9b:
+                    0a:b8:0f:97:73:bf:c5:4b:a1:a0:bf:74:4e:3c:35:
+                    d3:91:82:9a:2e:3b:de:cc:d1:44:92:1e:e5:bb:a9:
+                    69:fa:62:40:af:50:65:76:26:96:59:35:07:a9:3d:
+                    89:70:72:ea:89:a0:ef:73:0e:97:a0:26:2d:b2:69:
+                    e5:29:a5:39:69:3b:30:4c:49:38:69:24:3b:a3:f4:
+                    a4:93:d6:25:65:e2:dd:08:00:5f:59:f3:74:97:9f:
+                    1a:77:35:1f:ac:05:e8:94:34:7d:1a:e6:f5:65:02:
+                    c5:39:fd:d1:fd:d8:71:7a:01:3a:58:39:e9:5a:46:
+                    9a:2f:d4:6b:36:1d:01:15:e8:b4:cd:53:ca:e3:d9:
+                    d4:70:68:90:89:80:f0:50:87:29:97:02:a9:46:e1:
+                    df:22:65:7a:eb:b1:79:d4:74:db:99:be:f5:c7:a1:
+                    b2:a9:5a:e5:d2:ea:9e:1c:6d:1a:67:17:3a:d8:68:
+                    b4:c1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                64:4B:B5:05:C0:56:86:5B:24:4D:8A:33:B5:1E:7E:0F:91:73:F0:93
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Certificate Policies: 
+                Policy: 1.2.392.200075.4.2
+                  CPS: https://cp.jcsinc.co.jp/SecureSign/AD/RPA.html
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://ssignadcrl01.jcsinc.co.jp/repository/crl/rca.crl
+
+                Full Name:
+                  URI:http://ssignadcrl02.jcsinc.co.jp/repository/crl/rca.crl
+
+    Signature Algorithm: sha1WithRSAEncryption
+         32:33:41:ca:ce:e8:5b:fe:dd:1d:21:cb:78:e8:56:8f:73:3b:
+         0b:ce:1f:7f:e4:45:3b:5b:33:a7:02:71:1f:6f:7f:0c:00:e9:
+         e0:f7:49:9b:90:db:e6:56:36:21:0f:1e:32:64:ac:9a:e4:fa:
+         2d:0e:93:46:40:c4:a7:ff:6a:3d:9e:69:95:38:ac:96:4f:08:
+         91:fc:a1:ee:81:d1:54:80:d3:83:04:c5:14:31:02:14:53:3e:
+         ba:1e:62:f1:28:0d:62:eb:c9:8c:d3:5e:c8:16:de:c0:05:43:
+         6e:bc:4b:fa:61:89:90:4d:40:09:a5:4d:1a:98:26:f6:49:9f:
+         8b:ce:6b:38:8c:1f:2e:9c:58:0c:ac:cd:6c:e9:c8:84:65:2b:
+         c4:c1:f2:a9:e7:7d:4a:f5:01:6a:4c:66:32:8c:ce:b9:e3:8d:
+         1d:f9:8f:39:cf:35:d5:4d:fe:a2:12:7a:e9:a2:73:64:83:f6:
+         05:0a:9f:cb:f8:d4:91:6c:df:ed:35:59:ac:24:bd:d3:c5:dc:
+         2b:cb:32:34:b3:54:ba:62:48:32:aa:2f:aa:4e:35:8e:91:c2:
+         b7:19:47:0d:43:59:64:44:f7:a8:1a:f8:79:4b:e4:56:41:5d:
+         12:77:0c:03:74:c8:00:ab:f6:25:b8:b2:07:a1:05:d5:56:0d:
+         f0:71:f3:3d
+-----BEGIN CERTIFICATE-----
+MIIEVDCCAzygAwIBAgIBAzANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr
+MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG
+A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwOTA2NTFaFw0yOTA0
+MDgwNDU2NDdaMFsxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp
+Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMR8wHQYDVQQDExZTZWN1cmVTaWduIFB1Ymxp
+YyBDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA16tNcWt7oV+4
+5tYThbu1Qbb812aYfoVnVqq59lPX/iJSMyCq9Ya6Eh5T6k4sPeCN70WdyOOLtGkJ
+kaz/bWp3yNbXXY8ICuCqopsKuA+Xc7/FS6Ggv3ROPDXTkYKaLjvezNFEkh7lu6lp
++mJAr1BldiaWWTUHqT2JcHLqiaDvcw6XoCYtsmnlKaU5aTswTEk4aSQ7o/Skk9Yl
+ZeLdCABfWfN0l58adzUfrAXolDR9Gub1ZQLFOf3R/dhxegE6WDnpWkaaL9RrNh0B
+Fei0zVPK49nUcGiQiYDwUIcplwKpRuHfImV667F51HTbmb71x6GyqVrl0uqeHG0a
+Zxc62Gi0wQIDAQABo4IBJDCCASAwHQYDVR0OBBYEFGRLtQXAVoZbJE2KM7Uefg+R
+c/CTMA4GA1UdDwEB/wQEAwIBBjBTBgNVHSAETDBKMEgGCCqDCIybCwQCMDwwOgYI
+KwYBBQUHAgEWLmh0dHBzOi8vY3AuamNzaW5jLmNvLmpwL1NlY3VyZVNpZ24vQUQv
+UlBBLmh0bWwwDwYDVR0TAQH/BAUwAwEB/zCBiAYDVR0fBIGAMH4wPaA7oDmGN2h0
+dHA6Ly9zc2lnbmFkY3JsMDEuamNzaW5jLmNvLmpwL3JlcG9zaXRvcnkvY3JsL3Jj
+YS5jcmwwPaA7oDmGN2h0dHA6Ly9zc2lnbmFkY3JsMDIuamNzaW5jLmNvLmpwL3Jl
+cG9zaXRvcnkvY3JsL3JjYS5jcmwwDQYJKoZIhvcNAQEFBQADggEBADIzQcrO6Fv+
+3R0hy3joVo9zOwvOH3/kRTtbM6cCcR9vfwwA6eD3SZuQ2+ZWNiEPHjJkrJrk+i0O
+k0ZAxKf/aj2eaZU4rJZPCJH8oe6B0VSA04MExRQxAhRTProeYvEoDWLryYzTXsgW
+3sAFQ268S/phiZBNQAmlTRqYJvZJn4vOaziMHy6cWAyszWzpyIRlK8TB8qnnfUr1
+AWpMZjKMzrnjjR35jznPNdVN/qISeumic2SD9gUKn8v41JFs3+01WawkvdPF3CvL
+MjSzVLpiSDKqL6pONY6RwrcZRw1DWWRE96ga+HlL5FZBXRJ3DAN0yACr9iW4sgeh
+BdVWDfBx8z0=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/ddd8ab9178c99cbd9685ea4ae66dc28bfdc9a5a8a166f7f69ad0b5042ad6eb28.pem b/net/data/ssl/blacklist/ddd8ab9178c99cbd9685ea4ae66dc28bfdc9a5a8a166f7f69ad0b5042ad6eb28.pem
new file mode 100644
index 0000000..0b23a83d
--- /dev/null
+++ b/net/data/ssl/blacklist/ddd8ab9178c99cbd9685ea4ae66dc28bfdc9a5a8a166f7f69ad0b5042ad6eb28.pem
@@ -0,0 +1,83 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            e4:ed:82:a7:45:5c:00:a2
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C = DK, ST = Denmark, L = "industriparken 27, 2750 Ballerup", O = Sennheiser Communications A/S, OU = R&D, CN = 127.0.0.1, emailAddress = support@senncom.com
+        Validity
+            Not Before: Jan 13 08:57:48 2017 GMT
+            Not After : Jan 13 08:57:48 2027 GMT
+        Subject: C = DK, ST = Denmark, L = "industriparken 27, 2750 Ballerup", O = Sennheiser Communications A/S, OU = R&D, CN = 127.0.0.1, emailAddress = support@senncom.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:d2:f2:ef:c7:97:06:01:c4:5f:95:d3:54:48:77:
+                    05:a0:06:75:e9:a4:23:61:94:75:24:31:77:42:ef:
+                    c1:15:01:a3:de:ec:5f:1f:a8:05:3e:a6:af:63:2f:
+                    3d:53:58:15:36:42:4e:ad:f1:61:34:99:6c:c7:ff:
+                    b1:e2:2c:55:78:4c:9d:01:3b:9c:10:af:95:fd:22:
+                    c0:2f:6b:c1:1b:7e:57:10:4c:a3:5a:11:c2:c2:d9:
+                    1b:a5:61:c2:c3:0f:a6:b1:57:6e:27:d2:26:a5:74:
+                    98:30:82:b1:9b:00:b9:1a:aa:73:73:fb:ff:f5:cb:
+                    b4:75:7d:ef:6a:5c:83:59:07:9a:71:5f:7a:49:4b:
+                    bf:19:db:1a:1f:68:5e:77:da:d4:ea:00:d0:b4:49:
+                    5d:c0:85:29:a2:bc:cc:ff:1b:d4:a4:ff:4e:b3:c8:
+                    5d:4d:34:45:8f:f4:c5:b0:c3:71:8d:e6:93:d3:05:
+                    cd:59:8e:4e:82:0c:93:f4:7d:61:4e:be:93:03:76:
+                    55:0b:6c:de:7c:38:0f:28:1a:d3:d4:2f:03:5d:e8:
+                    4f:53:e7:64:84:c3:8e:1d:a9:fb:da:b0:e9:3e:de:
+                    bd:76:f0:67:22:c6:5d:0a:c1:70:9c:c5:2c:3b:78:
+                    24:a2:65:e9:7e:74:8f:a8:d5:9a:44:5a:23:27:af:
+                    29:b5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                58:5A:52:0B:B7:A7:5F:AF:D3:87:39:44:99:39:6A:AF:11:C3:AA:0E
+            X509v3 Authority Key Identifier: 
+                keyid:58:5A:52:0B:B7:A7:5F:AF:D3:87:39:44:99:39:6A:AF:11:C3:AA:0E
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+         6d:e4:c5:3f:58:f7:58:fc:b4:be:c1:09:54:5e:32:90:8d:9b:
+         c3:6d:27:f2:13:fd:42:35:7b:8e:89:ce:c1:c6:cf:97:28:e7:
+         29:f0:bd:e6:bd:cb:e0:56:5a:f3:08:ac:10:98:60:09:c0:06:
+         68:87:39:88:06:54:67:b4:de:8e:23:69:1f:5a:32:d7:97:f9:
+         a8:9a:a9:3f:d6:9a:37:6b:3a:a7:94:54:98:30:22:42:1a:de:
+         87:20:bf:f6:b0:92:6e:45:0f:ac:b1:4a:61:f8:64:9c:ed:e8:
+         bb:0d:35:48:b8:45:fe:25:41:eb:10:28:b8:c6:b6:e6:c3:66:
+         6a:54:bf:e3:29:a4:9d:c5:43:5a:60:d5:5a:f6:15:e5:29:1e:
+         34:98:e4:ee:73:57:57:25:5f:84:eb:ed:4b:f6:05:51:b2:38:
+         cd:d5:9a:0c:b3:dc:48:40:71:27:56:0c:21:8c:13:8e:3d:3e:
+         ca:3d:be:9b:cd:11:3d:20:f3:36:51:97:08:b5:61:47:9c:50:
+         02:e2:56:b7:3f:e9:76:b1:ae:a4:bc:1e:6e:ff:84:d8:b2:5f:
+         1c:32:d3:f3:dc:17:f2:11:43:af:e2:9f:1a:6d:f4:94:57:b8:
+         09:7e:a7:0d:b8:ad:bf:d0:5b:e7:7d:60:ae:78:34:8d:d8:73:
+         63:f1:93:e4
+-----BEGIN CERTIFICATE-----
+MIIERTCCAy2gAwIBAgIJAOTtgqdFXACiMA0GCSqGSIb3DQEBBQUAMIG4MQswCQYD
+VQQGEwJESzEQMA4GA1UECAwHRGVubWFyazEpMCcGA1UEBwwgaW5kdXN0cmlwYXJr
+ZW4gMjcsIDI3NTAgQmFsbGVydXAxJjAkBgNVBAoMHVNlbm5oZWlzZXIgQ29tbXVu
+aWNhdGlvbnMgQS9TMQwwCgYDVQQLDANSJkQxEjAQBgNVBAMMCTEyNy4wLjAuMTEi
+MCAGCSqGSIb3DQEJARYTc3VwcG9ydEBzZW5uY29tLmNvbTAeFw0xNzAxMTMwODU3
+NDhaFw0yNzAxMTMwODU3NDhaMIG4MQswCQYDVQQGEwJESzEQMA4GA1UECAwHRGVu
+bWFyazEpMCcGA1UEBwwgaW5kdXN0cmlwYXJrZW4gMjcsIDI3NTAgQmFsbGVydXAx
+JjAkBgNVBAoMHVNlbm5oZWlzZXIgQ29tbXVuaWNhdGlvbnMgQS9TMQwwCgYDVQQL
+DANSJkQxEjAQBgNVBAMMCTEyNy4wLjAuMTEiMCAGCSqGSIb3DQEJARYTc3VwcG9y
+dEBzZW5uY29tLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLy
+78eXBgHEX5XTVEh3BaAGdemkI2GUdSQxd0LvwRUBo97sXx+oBT6mr2MvPVNYFTZC
+Tq3xYTSZbMf/seIsVXhMnQE7nBCvlf0iwC9rwRt+VxBMo1oRwsLZG6VhwsMPprFX
+bifSJqV0mDCCsZsAuRqqc3P7//XLtHV972pcg1kHmnFfeklLvxnbGh9oXnfa1OoA
+0LRJXcCFKaK8zP8b1KT/TrPIXU00RY/0xbDDcY3mk9MFzVmOToIMk/R9YU6+kwN2
+VQts3nw4Dyga09QvA13oT1PnZITDjh2p+9qw6T7evXbwZyLGXQrBcJzFLDt4JKJl
+6X50j6jVmkRaIyevKbUCAwEAAaNQME4wHQYDVR0OBBYEFFhaUgu3p1+v04c5RJk5
+aq8Rw6oOMB8GA1UdIwQYMBaAFFhaUgu3p1+v04c5RJk5aq8Rw6oOMAwGA1UdEwQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAG3kxT9Y91j8tL7BCVReMpCNm8NtJ/IT
+/UI1e46JzsHGz5co5ynwvea9y+BWWvMIrBCYYAnABmiHOYgGVGe03o4jaR9aMteX
++aiaqT/WmjdrOqeUVJgwIkIa3ocgv/awkm5FD6yxSmH4ZJzt6LsNNUi4Rf4lQesQ
+KLjGtubDZmpUv+MppJ3FQ1pg1Vr2FeUpHjSY5O5zV1clX4Tr7Uv2BVGyOM3Vmgyz
+3EhAcSdWDCGME449Pso9vpvNET0g8zZRlwi1YUecUALiVrc/6XaxrqS8Hm7/hNiy
+Xxwy0/PcF/IRQ6/inxpt9JRXuAl+pw24rb/QW+d9YK54NI3Yc2Pxk+Q=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/e54e9fc27e7350ff63a77764a40267b7e95ae5df3ed7df5336e8f8541356c845.pem b/net/data/ssl/blacklist/e54e9fc27e7350ff63a77764a40267b7e95ae5df3ed7df5336e8f8541356c845.pem
new file mode 100644
index 0000000..d7c65d07
--- /dev/null
+++ b/net/data/ssl/blacklist/e54e9fc27e7350ff63a77764a40267b7e95ae5df3ed7df5336e8f8541356c845.pem
@@ -0,0 +1,80 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 204199 (0x31da7)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C = FR, O = DGTPE, CN = AC DGTPE Signature Authentification
+        Validity
+            Not Before: Jul 18 10:05:28 2013 GMT
+            Not After : Jul 18 10:05:28 2014 GMT
+        Subject: C = FR, O = DG Tr\C3\A9sor, CN = AC DG Tr\C3\A9sor SSL
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c8:d1:61:52:53:26:3e:32:6b:45:92:a1:63:4d:
+                    e7:e8:17:20:e0:87:d6:f5:0b:fd:98:bd:22:2f:4f:
+                    ca:02:1f:ad:89:59:3e:6b:a5:e4:c2:67:06:97:6e:
+                    a5:9c:8d:a3:5f:ce:08:2a:68:5b:28:92:a7:e1:06:
+                    27:f8:dc:73:47:36:d3:49:9a:f2:84:df:65:5c:b8:
+                    b0:74:4a:9b:0b:47:fd:55:79:37:7d:17:df:42:d4:
+                    97:87:55:af:a7:7a:5b:a6:38:71:1f:a2:e5:fc:ad:
+                    11:6b:c4:d5:cd:21:84:d5:7a:21:0d:4f:c6:36:62:
+                    a4:5b:fd:70:2b:8a:5f:60:ee:2e:bb:e2:e1:73:2e:
+                    23:51:fe:df:cd:fc:5f:04:c6:e8:ef:f5:4f:26:f2:
+                    b9:a0:b9:df:fe:b4:6f:56:0d:16:83:27:0a:23:dd:
+                    91:42:3a:72:f9:a8:b9:d2:50:47:12:e9:3c:d6:a6:
+                    8c:cb:98:2d:89:54:ee:46:64:a1:86:77:ba:82:f4:
+                    58:dd:06:45:62:96:46:d5:20:41:92:ad:8b:f3:d9:
+                    4c:f6:bf:92:06:a8:c0:48:41:a1:4b:fe:44:98:5b:
+                    11:93:69:e7:53:3a:4d:9d:ac:51:00:a6:9f:40:10:
+                    f4:df:bf:53:70:09:60:5f:7a:0b:06:42:b1:d4:44:
+                    e3:37
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:4
+            X509v3 Subject Key Identifier: 
+                00:0C:5B:C9:49:A8:95:B4:0E:D0:2F:E6:9D:CC:8E:88:31:BE:1F:65
+            X509v3 Authority Key Identifier: 
+                keyid:E9:DB:90:8F:FD:5B:99:E4:15:3B:F0:62:5C:A7:E4:0D:58:E8:87:99
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha1WithRSAEncryption
+         b4:37:c6:1e:41:ce:2d:6d:9d:f5:f8:8c:b7:0b:64:13:00:da:
+         b8:84:89:2c:9c:82:8e:84:66:6b:0c:e6:41:b2:19:5e:ae:c7:
+         68:b9:62:55:f1:34:b1:d7:ca:52:6d:22:43:48:a6:d7:f0:a9:
+         9c:92:cf:a1:37:8a:c8:11:ef:36:ed:6e:6c:b7:36:9b:ef:5d:
+         69:b0:18:84:5d:e9:55:d2:82:fa:03:5a:03:30:57:67:d1:ad:
+         d2:9d:42:2e:4d:65:7f:c1:e0:f9:1d:74:1c:dd:88:3c:2b:fb:
+         57:f7:2b:cf:61:9a:f9:cd:b7:e0:fd:e9:7f:06:16:f3:e3:5d:
+         ed:a9:46:0a:eb:ea:a2:de:94:61:73:a5:85:e1:7b:cd:65:24:
+         1e:7e:b3:ea:db:d8:fb:da:0c:0c:72:92:50:0b:61:84:0f:c5:
+         07:9d:09:80:95:3c:f7:3c:93:bf:57:a0:63:79:5d:2b:0b:d8:
+         05:6d:d6:df:23:59:75:31:db:3f:23:6c:3c:97:61:a8:0e:79:
+         98:33:6c:b5:e1:39:61:3a:75:3f:2c:92:0d:bd:4c:49:5a:db:
+         c4:31:2b:ba:81:fa:64:4f:7d:1e:86:f8:22:1f:00:9a:7e:cc:
+         1d:96:ad:18:29:44:0a:08:d7:58:56:76:1b:16:bb:39:40:9a:
+         42:97:07:f2
+-----BEGIN CERTIFICATE-----
+MIIDbDCCAlSgAwIBAgIDAx2nMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNVBAYTAkZS
+MQ4wDAYDVQQKEwVER1RQRTEsMCoGA1UEAxMjQUMgREdUUEUgU2lnbmF0dXJlIEF1
+dGhlbnRpZmljYXRpb24wHhcNMTMwNzE4MTAwNTI4WhcNMTQwNzE4MTAwNTI4WjA+
+MQswCQYDVQQGEwJGUjETMBEGA1UECgwKREcgVHLDqXNvcjEaMBgGA1UEAwwRQUMg
+REcgVHLDqXNvciBTU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDI
+0WFSUyY+MmtFkqFjTefoFyDgh9b1C/2YvSIvT8oCH62JWT5rpeTCZwaXbqWcjaNf
+zggqaFsokqfhBif43HNHNtNJmvKE32VcuLB0SpsLR/1VeTd9F99C1JeHVa+nelum
+OHEfouX8rRFrxNXNIYTVeiENT8Y2YqRb/XAril9g7i674uFzLiNR/t/N/F8Exujv
+9U8m8rmgud/+tG9WDRaDJwoj3ZFCOnL5qLnSUEcS6TzWpozLmC2JVO5GZKGGd7qC
+9FjdBkVilkbVIEGSrYvz2Uz2v5IGqMBIQaFL/kSYWxGTaedTOk2drFEApp9AEPTf
+v1NwCWBfegsGQrHUROM3AgMBAAGjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQQwHQYD
+VR0OBBYEFAAMW8lJqJW0DtAv5p3Mjogxvh9lMB8GA1UdIwQYMBaAFOnbkI/9W5nk
+FTvwYlyn5A1Y6IeZMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA
+tDfGHkHOLW2d9fiMtwtkEwDauISJLJyCjoRmawzmQbIZXq7HaLliVfE0sdfKUm0i
+Q0im1/CpnJLPoTeKyBHvNu1ubLc2m+9dabAYhF3pVdKC+gNaAzBXZ9Gt0p1CLk1l
+f8Hg+R10HN2IPCv7V/crz2Ga+c234P3pfwYW8+Nd7alGCuvqot6UYXOlheF7zWUk
+Hn6z6tvY+9oMDHKSUAthhA/FB50JgJU89zyTv1egY3ldKwvYBW3W3yNZdTHbPyNs
+PJdhqA55mDNsteE5YTp1PyySDb1MSVrbxDEruoH6ZE99Hob4Ih8Amn7MHZatGClE
+CgjXWFZ2Gxa7OUCaQpcH8g==
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/e757fd60d8dd4c26f77aca6a87f63ea4d38d0b736c7f79b56cad932d4c400fb5.pem b/net/data/ssl/blacklist/e757fd60d8dd4c26f77aca6a87f63ea4d38d0b736c7f79b56cad932d4c400fb5.pem
new file mode 100644
index 0000000..c50140e
--- /dev/null
+++ b/net/data/ssl/blacklist/e757fd60d8dd4c26f77aca6a87f63ea4d38d0b736c7f79b56cad932d4c400fb5.pem
@@ -0,0 +1,108 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            4a:41:a4:1d:cf:8d:24:61:8b:a9:4b:3d:61:99:5c:c4
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = EssentialSSL CA
+        Validity
+            Not Before: Apr 10 00:00:00 2014 GMT
+            Not After : Jul  9 23:59:59 2014 GMT
+        Subject: OU = Domain Control Validated, OU = Free SSL, CN = cloudflarechallenge.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:9b:40:16:91:59:c3:c7:97:de:39:cb:5d:0b:de:
+                    d9:b6:0b:ed:77:6e:6e:28:a9:a1:8c:21:e9:2f:27:
+                    26:13:17:b5:46:24:52:97:f8:46:20:be:df:f0:58:
+                    3f:aa:25:33:b5:59:b9:b9:76:49:d5:41:bb:77:3c:
+                    fe:f4:eb:53:36:1f:af:db:b0:6d:cc:fb:14:df:28:
+                    af:1d:eb:f0:00:1d:66:4c:cb:4f:e9:b3:ee:5c:18:
+                    f3:b3:14:5c:0b:dc:95:70:10:56:a4:a0:4c:46:73:
+                    78:d3:e9:2f:51:96:15:39:ab:82:3e:ab:c4:1d:fa:
+                    3a:47:2f:bb:8a:7a:49:62:a4:26:fc:54:8c:e7:46:
+                    6b:46:29:82:3b:1f:4d:64:8f:25:bc:83:05:d8:3a:
+                    b5:8a:94:a0:87:38:87:11:df:62:c8:c4:77:dd:7e:
+                    fe:f6:42:34:f6:90:6b:a9:9d:ed:d3:99:70:18:fb:
+                    a7:04:2f:5d:99:a9:2d:87:09:8a:46:05:af:10:41:
+                    a6:7b:fd:d8:20:73:55:f9:38:92:f5:ca:b4:0f:f0:
+                    b7:bd:fd:f6:82:38:11:e7:d0:0e:32:cc:da:7c:ef:
+                    70:55:31:0f:bb:4f:ee:e4:d8:f0:92:b3:ba:80:7c:
+                    1d:13:76:f7:5f:40:58:8f:3c:56:93:38:30:ed:3d:
+                    60:a5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Authority Key Identifier: 
+                keyid:DA:CB:EA:AD:5B:08:5D:CC:FF:FC:26:54:CE:49:E5:55:C6:38:F4:F8
+
+            X509v3 Subject Key Identifier: 
+                6E:AC:AF:17:6B:07:B6:C8:E0:E6:2F:36:C0:13:8D:DF:97:A5:BC:D4
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication, Microsoft Server Gated Crypto, Netscape Server Gated Crypto
+            X509v3 Certificate Policies: 
+                Policy: 1.3.6.1.4.1.6449.1.2.2.7
+                  CPS: https://secure.comodo.com/CPS
+                Policy: 2.23.140.1.2.1
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crl.comodoca.com/EssentialSSLCA.crl
+
+            Authority Information Access: 
+                CA Issuers - URI:http://crt.comodoca.com/EssentialSSLCA_2.crt
+                OCSP - URI:http://ocsp.comodoca.com
+
+            X509v3 Subject Alternative Name: 
+                DNS:cloudflarechallenge.com, DNS:www.cloudflarechallenge.com
+    Signature Algorithm: sha1WithRSAEncryption
+         65:37:5e:7a:e3:1a:73:d1:fd:04:9c:28:79:74:a3:a3:a3:ab:
+         a4:fa:46:cb:cc:48:64:7d:a1:9d:e5:87:62:e1:d8:85:43:d5:
+         58:c7:7f:8b:7b:52:42:07:f6:c3:1c:c5:54:7f:09:6a:4e:95:
+         74:12:af:03:64:85:93:3b:9c:27:3f:d0:65:44:38:a5:8d:57:
+         bb:fb:2f:e3:91:0f:db:fc:1f:3c:92:60:6b:da:38:d1:f4:07:
+         ad:d6:5f:21:3a:ba:89:c9:cc:3a:01:c9:3a:17:ee:61:77:f9:
+         58:22:f6:7f:d1:81:fe:87:fa:ae:f7:f6:7a:8a:2e:ab:71:40:
+         9d:51:61:11:48:a8:93:16:c6:cc:f0:f4:66:1b:f0:b0:6f:82:
+         66:e7:63:7c:7a:fe:a6:71:56:26:c5:e0:58:20:f9:9f:e7:51:
+         c1:1c:46:a4:37:5d:e8:41:cb:9b:08:08:dd:57:df:fc:0a:e8:
+         04:32:b9:79:ea:55:29:b7:b0:58:64:c1:13:da:1e:0d:c8:20:
+         eb:7d:39:5b:15:c0:ea:40:2f:98:06:be:5d:2c:33:af:2e:97:
+         bb:4f:b0:ef:fa:bd:4f:c1:82:7e:47:40:38:24:2d:05:d9:17:
+         54:78:80:56:0b:90:b2:70:97:13:c7:88:7b:65:29:4d:79:6b:
+         45:ad:98:09
+-----BEGIN CERTIFICATE-----
+MIIFLTCCBBWgAwIBAgIQSkGkHc+NJGGLqUs9YZlcxDANBgkqhkiG9w0BAQUFADBy
+MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
+VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEYMBYGA1UE
+AxMPRXNzZW50aWFsU1NMIENBMB4XDTE0MDQxMDAwMDAwMFoXDTE0MDcwOTIzNTk1
+OVowWDEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMREwDwYDVQQL
+EwhGcmVlIFNTTDEgMB4GA1UEAxMXY2xvdWRmbGFyZWNoYWxsZW5nZS5jb20wggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbQBaRWcPHl945y10L3tm2C+13
+bm4oqaGMIekvJyYTF7VGJFKX+EYgvt/wWD+qJTO1Wbm5dknVQbt3PP7061M2H6/b
+sG3M+xTfKK8d6/AAHWZMy0/ps+5cGPOzFFwL3JVwEFakoExGc3jT6S9RlhU5q4I+
+q8Qd+jpHL7uKeklipCb8VIznRmtGKYI7H01kjyW8gwXYOrWKlKCHOIcR32LIxHfd
+fv72QjT2kGupne3TmXAY+6cEL12ZqS2HCYpGBa8QQaZ7/dggc1X5OJL1yrQP8Le9
+/faCOBHn0A4yzNp873BVMQ+7T+7k2PCSs7qAfB0TdvdfQFiPPFaTODDtPWClAgMB
+AAGjggHXMIIB0zAfBgNVHSMEGDAWgBTay+qtWwhdzP/8JlTOSeVVxjj0+DAdBgNV
+HQ4EFgQUbqyvF2sHtsjg5i82wBON35elvNQwDgYDVR0PAQH/BAQDAgWgMAwGA1Ud
+EwEB/wQCMAAwNAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3
+CgMDBglghkgBhvhCBAEwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQICBzArMCkGCCsG
+AQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAIBgZngQwBAgEw
+OwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vRXNzZW50
+aWFsU1NMQ0EuY3JsMG4GCCsGAQUFBwEBBGIwYDA4BggrBgEFBQcwAoYsaHR0cDov
+L2NydC5jb21vZG9jYS5jb20vRXNzZW50aWFsU1NMQ0FfMi5jcnQwJAYIKwYBBQUH
+MAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTA/BgNVHREEODA2ghdjbG91ZGZs
+YXJlY2hhbGxlbmdlLmNvbYIbd3d3LmNsb3VkZmxhcmVjaGFsbGVuZ2UuY29tMA0G
+CSqGSIb3DQEBBQUAA4IBAQBlN1564xpz0f0EnCh5dKOjo6uk+kbLzEhkfaGd5Ydi
+4diFQ9VYx3+Le1JCB/bDHMVUfwlqTpV0Eq8DZIWTO5wnP9BlRDiljVe7+y/jkQ/b
+/B88kmBr2jjR9Aet1l8hOrqJycw6Ack6F+5hd/lYIvZ/0YH+h/qu9/Z6ii6rcUCd
+UWERSKiTFsbM8PRmG/Cwb4Jm52N8ev6mcVYmxeBYIPmf51HBHEakN13oQcubCAjd
+V9/8CugEMrl56lUpt7BYZMET2h4NyCDrfTlbFcDqQC+YBr5dLDOvLpe7T7Dv+r1P
+wYJ+R0A4JC0F2RdUeIBWC5CycJcTx4h7ZSlNeWtFrZgJ
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/blacklist/fa5a828c9a7e732692682e60b14c634309cbb2bb79eb12aef44318d853ee97e3.pem b/net/data/ssl/blacklist/fa5a828c9a7e732692682e60b14c634309cbb2bb79eb12aef44318d853ee97e3.pem
new file mode 100644
index 0000000..006d3cf1
--- /dev/null
+++ b/net/data/ssl/blacklist/fa5a828c9a7e732692682e60b14c634309cbb2bb79eb12aef44318d853ee97e3.pem
@@ -0,0 +1,106 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:26:0c:82:e4:a8:d6:6c:b8:e3:d3:99:ab:9d:42:de:cd:d9
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
+        Validity
+            Not Before: Nov  1 13:11:39 2017 GMT
+            Not After : Jan 30 13:11:39 2018 GMT
+        Subject: CN = googlemaps.tg
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b2:69:26:59:57:b7:9b:c6:16:69:f3:4d:c4:7c:
+                    5a:12:94:4b:33:24:57:93:4b:5d:04:e7:1c:aa:d4:
+                    e0:9d:29:2e:82:56:3c:18:03:ec:33:4f:0c:eb:67:
+                    c6:2a:eb:8d:4f:f1:bf:5c:d4:26:c1:ac:1a:33:d1:
+                    e3:99:b1:78:68:92:83:4d:53:48:dd:21:21:c8:3e:
+                    e1:6c:e2:1f:45:d6:db:f9:82:7a:f0:6d:5a:1f:65:
+                    5e:fb:86:2e:72:9c:99:05:c0:e3:9d:d5:93:19:92:
+                    d5:3a:ac:7d:d0:7e:41:25:d4:f9:f0:b1:ae:6a:97:
+                    c1:d7:33:e2:0e:38:ed:f8:57:3f:5c:f6:c6:36:00:
+                    d0:9d:a9:fa:83:36:66:a2:f3:fc:06:74:18:67:7f:
+                    3d:42:e4:26:06:eb:2c:b3:de:2d:79:fe:3a:85:52:
+                    3f:e9:a8:6a:18:86:19:fc:ba:21:c1:3e:c1:bb:25:
+                    1e:df:02:6f:65:08:a5:01:43:68:82:9a:e9:76:ce:
+                    9f:ce:92:9d:7e:05:a9:a2:32:ca:bc:6f:23:8e:1c:
+                    24:ca:20:cc:08:ef:50:9c:23:cb:b7:2e:2b:0a:ec:
+                    ac:5b:d2:03:cf:e7:86:08:fc:65:30:0a:00:d0:e1:
+                    96:35:c8:ea:d6:19:e3:13:56:af:61:cb:56:8c:c3:
+                    51:bb
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                C4:78:BE:8E:9A:21:28:D2:92:4B:AE:26:EE:9A:8B:F5:91:3F:26:4E
+            X509v3 Authority Key Identifier: 
+                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
+
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.int-x3.letsencrypt.org
+                CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
+
+            X509v3 Subject Alternative Name: 
+                DNS:cpanel.googlemaps.tg, DNS:googlemaps.tg, DNS:mail.googlemaps.tg, DNS:webdisk.googlemaps.tg, DNS:webmail.googlemaps.tg
+            X509v3 Certificate Policies: 
+                Policy: 2.23.140.1.2.1
+                Policy: 1.3.6.1.4.1.44947.1.1.1
+                  CPS: http://cps.letsencrypt.org
+                  User Notice:
+                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/
+
+    Signature Algorithm: sha256WithRSAEncryption
+         47:57:12:8a:77:25:5d:48:34:63:79:2e:3f:0b:5b:7c:a2:29:
+         68:5b:07:db:4c:0d:68:a3:3a:9d:56:89:0c:70:b1:dd:c6:af:
+         44:c2:87:d0:70:2e:c9:11:5b:59:79:ce:cd:54:51:23:d2:74:
+         5f:30:57:6b:d5:28:ea:a0:ae:13:c6:db:c5:9e:77:25:7c:02:
+         64:d9:97:ee:83:17:2d:ef:ea:6f:c0:7f:53:7c:01:e0:6c:9d:
+         dd:20:3c:c0:eb:83:0b:bc:58:64:0c:a4:d0:d8:78:99:9c:4b:
+         fe:31:33:a1:8f:99:b1:13:10:5b:21:2d:87:22:23:71:6c:54:
+         b7:38:13:67:52:a3:1e:57:1b:98:21:bf:a1:85:1c:97:6e:e5:
+         81:2a:9c:65:d1:eb:64:32:2d:7d:55:4e:b9:25:75:16:cd:1d:
+         ff:52:3a:ff:3e:b5:95:3d:b6:cd:4a:b1:b7:99:43:7b:31:34:
+         61:9f:bf:1b:16:3e:5d:a0:cb:10:1c:0e:e0:12:55:d2:f6:a5:
+         07:89:af:5f:c0:2d:f5:64:a0:59:b3:38:69:8a:6a:7e:2b:1c:
+         1f:d4:84:15:ec:54:fb:82:09:1e:16:e8:c7:fe:10:93:0d:2e:
+         7d:14:18:d7:1a:e5:0c:d7:92:6e:de:36:61:58:ba:0f:50:4f:
+         24:33:4a:57
+-----BEGIN CERTIFICATE-----
+MIIFVTCCBD2gAwIBAgISAyYMguSo1my449OZq51C3s3ZMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzExMDExMzExMzlaFw0x
+ODAxMzAxMzExMzlaMBgxFjAUBgNVBAMTDWdvb2dsZW1hcHMudGcwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyaSZZV7ebxhZp803EfFoSlEszJFeTS10E
+5xyq1OCdKS6CVjwYA+wzTwzrZ8Yq641P8b9c1CbBrBoz0eOZsXhokoNNU0jdISHI
+PuFs4h9F1tv5gnrwbVofZV77hi5ynJkFwOOd1ZMZktU6rH3QfkEl1Pnwsa5ql8HX
+M+IOOO34Vz9c9sY2ANCdqfqDNmai8/wGdBhnfz1C5CYG6yyz3i15/jqFUj/pqGoY
+hhn8uiHBPsG7JR7fAm9lCKUBQ2iCmul2zp/Okp1+BamiMsq8byOOHCTKIMwI71Cc
+I8u3LisK7Kxb0gPP54YI/GUwCgDQ4ZY1yOrWGeMTVq9hy1aMw1G7AgMBAAGjggJl
+MIICYTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
+BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMR4vo6aISjSkkuuJu6ai/WRPyZO
+MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMw
+YTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9y
+ZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9y
+Zy8wcAYDVR0RBGkwZ4IUY3BhbmVsLmdvb2dsZW1hcHMudGeCDWdvb2dsZW1hcHMu
+dGeCEm1haWwuZ29vZ2xlbWFwcy50Z4IVd2ViZGlzay5nb29nbGVtYXBzLnRnghV3
+ZWJtYWlsLmdvb2dsZW1hcHMudGcwgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYG
+CysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNy
+eXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBv
+bmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBp
+biBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBh
+dCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
+AQsFAAOCAQEAR1cSinclXUg0Y3kuPwtbfKIpaFsH20wNaKM6nVaJDHCx3cavRMKH
+0HAuyRFbWXnOzVRRI9J0XzBXa9Uo6qCuE8bbxZ53JXwCZNmX7oMXLe/qb8B/U3wB
+4Gyd3SA8wOuDC7xYZAyk0Nh4mZxL/jEzoY+ZsRMQWyEthyIjcWxUtzgTZ1KjHlcb
+mCG/oYUcl27lgSqcZdHrZDItfVVOuSV1Fs0d/1I6/z61lT22zUqxt5lDezE0YZ+/
+GxY+XaDLEBwO4BJV0valB4mvX8At9WSgWbM4aYpqfiscH9SEFexU+4IJHhbox/4Q
+kw0ufRQY1xrlDNeSbt42YVi6D1BPJDNKVw==
+-----END CERTIFICATE-----
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 99151cd..ee4e7c5b 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -1242,7 +1242,7 @@
 }
 
 TEST_P(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap) {
-  std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> server_value = base::JSONReader::ReadDeprecated(
       "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\"},"
       "{\"port\":123,\"protocol_str\":\"quic\","
       "\"expiration\":\"9223372036854775807\"},{\"host\":\"example.org\","
@@ -1294,7 +1294,7 @@
 
 // Regression test for https://crbug.com/615497.
 TEST_P(HttpServerPropertiesManagerTest, DoNotLoadAltSvcForInsecureOrigins) {
-  std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> server_value = base::JSONReader::ReadDeprecated(
       "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\","
       "\"expiration\":\"9223372036854775807\"}]}");
   ASSERT_TRUE(server_value);
@@ -1515,7 +1515,7 @@
 }
 
 TEST_P(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) {
-  std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> server_value = base::JSONReader::ReadDeprecated(
       "{\"alternative_service\":["
       "{\"port\":443,\"protocol_str\":\"quic\"},"
       "{\"port\":123,\"protocol_str\":\"quic\","
@@ -1686,7 +1686,7 @@
   std::string expiration_str =
       base::NumberToString(static_cast<int64_t>(one_day_from_now_.ToTimeT()));
 
-  std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> server_value = base::JSONReader::ReadDeprecated(
       "{"
       "\"broken_alternative_services\":["
       "{\"broken_until\":\"" +
diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc
index 74c7c93..ee788d8 100644
--- a/net/http/transport_security_persister.cc
+++ b/net/http/transport_security_persister.cc
@@ -292,7 +292,8 @@
 bool TransportSecurityPersister::Deserialize(const std::string& serialized,
                                              bool* dirty,
                                              TransportSecurityState* state) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(serialized);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(serialized);
   base::DictionaryValue* dict_value = NULL;
   if (!value.get() || !value->GetAsDictionary(&dict_value))
     return false;
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 8822b6c..e8f1cae 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -239,7 +239,7 @@
     const scoped_refptr<X509Certificate>& served_certificate_chain,
     const scoped_refptr<X509Certificate>& validated_certificate_chain,
     const HashValueVector& known_pins) {
-  std::unique_ptr<base::Value> value(base::JSONReader::Read(report));
+  std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(report));
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->is_dict());
 
diff --git a/net/log/file_net_log_observer_unittest.cc b/net/log/file_net_log_observer_unittest.cc
index ce841283..19de9bd 100644
--- a/net/log/file_net_log_observer_unittest.cc
+++ b/net/log/file_net_log_observer_unittest.cc
@@ -127,7 +127,7 @@
   }
 
   base::JSONReader reader;
-  container = reader.ReadToValue(input);
+  container = reader.ReadToValueDeprecated(input);
   if (!container) {
     return ::testing::AssertionFailure() << reader.GetErrorMessage();
   }
diff --git a/net/log/trace_net_log_observer_unittest.cc b/net/log/trace_net_log_observer_unittest.cc
index 3085d6122..3d188e06 100644
--- a/net/log/trace_net_log_observer_unittest.cc
+++ b/net/log/trace_net_log_observer_unittest.cc
@@ -108,8 +108,8 @@
     trace_buffer_.Finish();
 
     std::unique_ptr<base::Value> trace_value;
-    trace_value =
-        base::JSONReader::Read(json_output_.json_output, base::JSON_PARSE_RFC);
+    trace_value = base::JSONReader::ReadDeprecated(json_output_.json_output,
+                                                   base::JSON_PARSE_RFC);
 
     ASSERT_TRUE(trace_value) << json_output_.json_output;
     base::ListValue* trace_events = nullptr;
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index 20e14ba..cceffe0 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -403,8 +403,8 @@
     if (json_value.size() > kMaxJsonSize)
       return HeaderOutcome::DISCARDED_JSON_TOO_BIG;
 
-    std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(json_value, base::JSON_PARSE_RFC, kMaxJsonDepth);
+    std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+        json_value, base::JSON_PARSE_RFC, kMaxJsonDepth);
     if (!value)
       return HeaderOutcome::DISCARDED_JSON_INVALID;
 
diff --git a/net/reporting/reporting_header_parser_fuzzer.cc b/net/reporting/reporting_header_parser_fuzzer.cc
index f050eae..56a4eba 100644
--- a/net/reporting/reporting_header_parser_fuzzer.cc
+++ b/net/reporting/reporting_header_parser_fuzzer.cc
@@ -37,7 +37,7 @@
   // Emulate what ReportingService::OnHeader does before calling
   // ReportingHeaderParser::ParseHeader.
   std::unique_ptr<base::Value> data_value =
-      base::JSONReader::Read("[" + data_json + "]");
+      base::JSONReader::ReadDeprecated("[" + data_json + "]");
   if (!data_value)
     return;
 
diff --git a/net/reporting/reporting_header_parser_unittest.cc b/net/reporting/reporting_header_parser_unittest.cc
index 253b5ec..657a5d1 100644
--- a/net/reporting/reporting_header_parser_unittest.cc
+++ b/net/reporting/reporting_header_parser_unittest.cc
@@ -26,7 +26,7 @@
  protected:
   void ParseHeader(const GURL& url, const std::string& json) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read("[" + json + "]");
+        base::JSONReader::ReadDeprecated("[" + json + "]");
     if (value)
       ReportingHeaderParser::ParseHeader(context(), url, std::move(value));
   }
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc
index 58122f8..ae9f290 100644
--- a/net/reporting/reporting_service.cc
+++ b/net/reporting/reporting_service.cc
@@ -66,8 +66,9 @@
       return;
     }
 
-    std::unique_ptr<base::Value> header_value = base::JSONReader::Read(
-        "[" + header_string + "]", base::JSON_PARSE_RFC, kMaxJsonDepth);
+    std::unique_ptr<base::Value> header_value =
+        base::JSONReader::ReadDeprecated("[" + header_string + "]",
+                                         base::JSON_PARSE_RFC, kMaxJsonDepth);
     if (!header_value) {
       ReportingHeaderParser::RecordHeaderDiscardedForJsonInvalid();
       return;
diff --git a/net/reporting/reporting_test_util.cc b/net/reporting/reporting_test_util.cc
index 321cbf4b..0eb369a 100644
--- a/net/reporting/reporting_test_util.cc
+++ b/net/reporting/reporting_test_util.cc
@@ -53,7 +53,7 @@
   const GURL& url() const override { return url_; }
   const std::string& json() const override { return json_; }
   std::unique_ptr<base::Value> GetValue() const override {
-    return base::JSONReader::Read(json_);
+    return base::JSONReader::ReadDeprecated(json_);
   }
 
   void Complete(ReportingUploader::Outcome outcome) override {
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index 6dea8c5..5ae2891 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -502,7 +502,8 @@
                                            int* port) {
   VLOG(1) << "Server data: " << server_data;
   base::JSONReader json_reader;
-  std::unique_ptr<base::Value> value(json_reader.ReadToValue(server_data));
+  std::unique_ptr<base::Value> value(
+      json_reader.ReadToValueDeprecated(server_data));
   if (!value.get() || !value->is_dict()) {
     LOG(ERROR) << "Could not parse server data: "
                << json_reader.GetErrorMessage();
diff --git a/net/test/spawned_test_server/remote_test_server_config.cc b/net/test/spawned_test_server/remote_test_server_config.cc
index 74a15b8..3b1f4d42 100644
--- a/net/test/spawned_test_server/remote_test_server_config.cc
+++ b/net/test/spawned_test_server/remote_test_server_config.cc
@@ -59,8 +59,8 @@
   if (!ReadFileToString(config_path, &config_json))
     LOG(FATAL) << "Failed to read " << config_path.value();
 
-  std::unique_ptr<base::DictionaryValue> config =
-      base::DictionaryValue::From(base::JSONReader::Read(config_json));
+  std::unique_ptr<base::DictionaryValue> config = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(config_json));
   if (!config)
     LOG(FATAL) << "Failed to parse " << config_path.value();
 
diff --git a/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc b/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc
index 40d2d1de..395ab97 100644
--- a/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc
+++ b/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc
@@ -62,7 +62,7 @@
     return false;
   }
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   if (!value.get()) {
     LOG(ERROR) << filename << ": couldn't parse JSON.";
     return false;
diff --git a/net/tools/transport_security_state_generator/input_file_parsers.cc b/net/tools/transport_security_state_generator/input_file_parsers.cc
index 1046ff6..3da453f 100644
--- a/net/tools/transport_security_state_generator/input_file_parsers.cc
+++ b/net/tools/transport_security_state_generator/input_file_parsers.cc
@@ -310,7 +310,7 @@
       "test",        "public-suffix", "google",      "custom",
       "bulk-legacy", "bulk-18-weeks", "bulk-1-year", "public-suffix-requested"};
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   base::DictionaryValue* dict_value = nullptr;
   if (!value.get() || !value->GetAsDictionary(&dict_value)) {
     LOG(ERROR) << "Could not parse the input JSON file";
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 57ac044..4dda387 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -6664,7 +6664,7 @@
   EXPECT_EQ("application/json; charset=utf-8",
             mock_report_sender.latest_content_type());
   std::unique_ptr<base::Value> value(
-      base::JSONReader::Read(mock_report_sender.latest_report()));
+      base::JSONReader::ReadDeprecated(mock_report_sender.latest_report()));
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->is_dict());
   base::DictionaryValue* report_dict;
diff --git a/printing/print_settings_conversion_unittest.cc b/printing/print_settings_conversion_unittest.cc
index 0d44a264..56e5e0e9 100644
--- a/printing/print_settings_conversion_unittest.cc
+++ b/printing/print_settings_conversion_unittest.cc
@@ -47,7 +47,8 @@
 }
 
 TEST(PrintSettingsConversionTest, ConversionTest) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(kPrinterSettings);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(kPrinterSettings);
   ASSERT_TRUE(value);
   PrintSettings settings;
   bool success = PrintSettingsFromJobSettings(
@@ -61,7 +62,8 @@
 
 #if defined(OS_CHROMEOS)
 TEST(PrintSettingsConversionTest, ConversionTest_DontSendUsername) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(kPrinterSettings);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(kPrinterSettings);
   ASSERT_TRUE(value);
   value->SetKey(kSettingSendUserInfo, base::Value(false));
   PrintSettings settings;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 352d366..9387bbd5e 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -246,7 +246,7 @@
     return;
   }
 
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(
+  std::unique_ptr<base::Value> json = base::JSONReader::ReadDeprecated(
       message.AsString(), base::JSON_ALLOW_TRAILING_COMMAS);
   base::DictionaryValue* message_dict = nullptr;
   std::string method;
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc
index d7bead4..d8802ec 100644
--- a/remoting/host/host_config.cc
+++ b/remoting/host/host_config.cc
@@ -30,7 +30,7 @@
 std::unique_ptr<base::DictionaryValue> HostConfigFromJson(
     const std::string& json) {
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS);
+      base::JSONReader::ReadDeprecated(json, base::JSON_ALLOW_TRAILING_COMMAS);
   if (!value || !value->is_dict()) {
     LOG(WARNING) << "Failed to parse host config from JSON";
     return nullptr;
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index ff72e2f..286a63bd 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -124,7 +124,8 @@
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
-  std::unique_ptr<base::Value> message_value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> message_value =
+      base::JSONReader::ReadDeprecated(message);
   if (!message_value->is_dict()) {
     LOG(ERROR) << "Received a message that's not a dictionary.";
     client_->CloseChannel(std::string());
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index e88c885..7514d63 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -93,10 +93,10 @@
   connect_message.SetString("directoryBotJid", kTestBotJid);
   connect_message.SetString("userName", kTestClientUsername);
   connect_message.SetString("authServiceWithToken", "oauth2:sometoken");
-  connect_message.Set(
-      "iceConfig",
-      base::JSONReader::Read("{ \"iceServers\": [ { \"urls\": [ \"stun:" +
-                             std::string(kTestStunServer) + "\" ] } ] }"));
+  connect_message.Set("iceConfig",
+                      base::JSONReader::ReadDeprecated(
+                          "{ \"iceServers\": [ { \"urls\": [ \"stun:" +
+                          std::string(kTestStunServer) + "\" ] } ] }"));
 
   return connect_message;
 }
@@ -355,7 +355,8 @@
       return nullptr;
     }
 
-    std::unique_ptr<base::Value> message = base::JSONReader::Read(message_json);
+    std::unique_ptr<base::Value> message =
+        base::JSONReader::ReadDeprecated(message_json);
     if (!message || !message->is_dict()) {
       LOG(ERROR) << "Malformed message:" << message_json;
       return nullptr;
diff --git a/remoting/host/native_messaging/native_messaging_pipe.cc b/remoting/host/native_messaging/native_messaging_pipe.cc
index 4d2d876..6a9fa6f 100644
--- a/remoting/host/native_messaging/native_messaging_pipe.cc
+++ b/remoting/host/native_messaging/native_messaging_pipe.cc
@@ -37,7 +37,7 @@
 
 void NativeMessagingPipe::PostMessageFromNativeHost(
     const std::string& message) {
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> json = base::JSONReader::ReadDeprecated(message);
   channel_->SendMessage(std::move(json));
 }
 
diff --git a/remoting/host/native_messaging/native_messaging_reader.cc b/remoting/host/native_messaging/native_messaging_reader.cc
index fca5737..de38084c 100644
--- a/remoting/host/native_messaging/native_messaging_reader.cc
+++ b/remoting/host/native_messaging/native_messaging_reader.cc
@@ -121,7 +121,8 @@
       return;
     }
 
-    std::unique_ptr<base::Value> message = base::JSONReader::Read(message_json);
+    std::unique_ptr<base::Value> message =
+        base::JSONReader::ReadDeprecated(message_json);
     if (!message) {
       LOG(ERROR) << "Failed to parse JSON message: " << message.get();
       NotifyEof();
diff --git a/remoting/host/native_messaging/native_messaging_writer_unittest.cc b/remoting/host/native_messaging/native_messaging_writer_unittest.cc
index 6b62f04..9441726 100644
--- a/remoting/host/native_messaging/native_messaging_writer_unittest.cc
+++ b/remoting/host/native_messaging/native_messaging_writer_unittest.cc
@@ -53,7 +53,7 @@
 
   // |content| should now contain serialized |message|.
   std::unique_ptr<base::Value> written_message =
-      base::JSONReader::Read(content);
+      base::JSONReader::ReadDeprecated(content);
   EXPECT_TRUE(message.Equals(written_message.get()));
 
   // Nothing more should have been written. Close the write-end of the pipe,
@@ -86,7 +86,7 @@
 
   // |content| should now contain serialized |message2|.
   std::unique_ptr<base::Value> written_message2 =
-      base::JSONReader::Read(content);
+      base::JSONReader::ReadDeprecated(content);
   EXPECT_TRUE(message2.Equals(written_message2.get()));
 }
 
diff --git a/remoting/host/security_key/security_key_extension_session.cc b/remoting/host/security_key/security_key_extension_session.cc
index fd46d399..7048c0b 100644
--- a/remoting/host/security_key/security_key_extension_session.cc
+++ b/remoting/host/security_key/security_key_extension_session.cc
@@ -95,7 +95,8 @@
     return false;
   }
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(message.data());
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(message.data());
   base::DictionaryValue* client_message;
   if (!value || !value->GetAsDictionary(&client_message)) {
     LOG(WARNING) << "Failed to retrieve data from gnubby-auth message.";
diff --git a/remoting/host/setup/daemon_controller_delegate_win.cc b/remoting/host/setup/daemon_controller_delegate_win.cc
index eebc05ea..cee87c1 100644
--- a/remoting/host/setup/daemon_controller_delegate_win.cc
+++ b/remoting/host/setup/daemon_controller_delegate_win.cc
@@ -75,8 +75,8 @@
   }
 
   // Parse the JSON configuration, expecting it to contain a dictionary.
-  std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(file_content, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+      file_content, base::JSON_ALLOW_TRAILING_COMMAS);
 
   base::DictionaryValue* dictionary;
   if (!value || !value->GetAsDictionary(&dictionary)) {
@@ -159,7 +159,8 @@
   }
 
   // Extract the configuration data that the user will verify.
-  std::unique_ptr<base::Value> config_value = base::JSONReader::Read(content);
+  std::unique_ptr<base::Value> config_value =
+      base::JSONReader::ReadDeprecated(content);
   if (!config_value.get()) {
     return false;
   }
diff --git a/remoting/host/setup/me2me_native_messaging_host.cc b/remoting/host/setup/me2me_native_messaging_host.cc
index 26343c3b..7d27759 100644
--- a/remoting/host/setup/me2me_native_messaging_host.cc
+++ b/remoting/host/setup/me2me_native_messaging_host.cc
@@ -96,7 +96,8 @@
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   auto response = std::make_unique<base::DictionaryValue>();
-  std::unique_ptr<base::Value> message_value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> message_value =
+      base::JSONReader::ReadDeprecated(message);
   if (!message_value->is_dict()) {
     OnError("Received a message that's not a dictionary.");
     return;
diff --git a/remoting/host/setup/me2me_native_messaging_host_unittest.cc b/remoting/host/setup/me2me_native_messaging_host_unittest.cc
index 3166b27..88375e0 100644
--- a/remoting/host/setup/me2me_native_messaging_host_unittest.cc
+++ b/remoting/host/setup/me2me_native_messaging_host_unittest.cc
@@ -421,7 +421,8 @@
       return nullptr;
     }
 
-    std::unique_ptr<base::Value> message = base::JSONReader::Read(message_json);
+    std::unique_ptr<base::Value> message =
+        base::JSONReader::ReadDeprecated(message_json);
     if (!message || !message->is_dict()) {
       return nullptr;
     }
diff --git a/remoting/host/setup/service_client.cc b/remoting/host/setup/service_client.cc
index acb2ab0..bb7ed9ef 100644
--- a/remoting/host/setup/service_client.cc
+++ b/remoting/host/setup/service_client.cc
@@ -168,7 +168,7 @@
         {
         std::string data = *response_body;
         std::unique_ptr<base::Value> message_value =
-            base::JSONReader::Read(data);
+            base::JSONReader::ReadDeprecated(data);
         base::DictionaryValue* dict;
         std::string code;
         if (message_value.get() && message_value->is_dict() &&
diff --git a/remoting/host/token_validator_base.cc b/remoting/host/token_validator_base.cc
index 58a8f07..d78637ea 100644
--- a/remoting/host/token_validator_base.cc
+++ b/remoting/host/token_validator_base.cc
@@ -287,7 +287,7 @@
   }
 
   // Decode the JSON data from the response.
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data_);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data_);
   base::DictionaryValue* dict;
   if (!value || !value->GetAsDictionary(&dict)) {
     LOG(ERROR) << "Invalid token validation response: '" << data_ << "'";
diff --git a/remoting/ios/facade/host_list_fetcher.cc b/remoting/ios/facade/host_list_fetcher.cc
index d70a5111..8ce7eb18 100644
--- a/remoting/ios/facade/host_list_fetcher.cc
+++ b/remoting/ios/facade/host_list_fetcher.cc
@@ -102,7 +102,7 @@
   }
 
   std::unique_ptr<base::Value> response_value(
-      base::JSONReader::Read(response_string));
+      base::JSONReader::ReadDeprecated(response_string));
   if (!response_value || !response_value->is_dict()) {
     LOG(ERROR) << "Failed to parse response string to JSON";
     return false;
diff --git a/remoting/protocol/ice_config.cc b/remoting/protocol/ice_config.cc
index 32fd3a0..8b1a867a 100644
--- a/remoting/protocol/ice_config.cc
+++ b/remoting/protocol/ice_config.cc
@@ -197,7 +197,8 @@
 
 // static
 IceConfig IceConfig::Parse(const std::string& config_json) {
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(config_json);
+  std::unique_ptr<base::Value> json =
+      base::JSONReader::ReadDeprecated(config_json);
   if (!json) {
     return IceConfig();
   }
diff --git a/remoting/test/host_list_fetcher.cc b/remoting/test/host_list_fetcher.cc
index a427833..1fa28706 100644
--- a/remoting/test/host_list_fetcher.cc
+++ b/remoting/test/host_list_fetcher.cc
@@ -58,7 +58,7 @@
   }
 
   std::unique_ptr<base::Value> response_value(
-      base::JSONReader::Read(response_string));
+      base::JSONReader::ReadDeprecated(response_string));
   if (!response_value || !response_value->is_dict()) {
     LOG(ERROR) << "Failed to parse response string to JSON";
     return false;
diff --git a/remoting/test/refresh_token_store.cc b/remoting/test/refresh_token_store.cc
index 44847be..7c24ad0a 100644
--- a/remoting/test/refresh_token_store.cc
+++ b/remoting/test/refresh_token_store.cc
@@ -72,7 +72,7 @@
   }
 
   std::unique_ptr<base::Value> token_data(
-      base::JSONReader::Read(file_contents));
+      base::JSONReader::ReadDeprecated(file_contents));
   base::DictionaryValue* tokens = nullptr;
   if (!token_data || !token_data->GetAsDictionary(&tokens)) {
     LOG(ERROR) << "Refresh token file contents were not valid JSON, "
@@ -115,7 +115,7 @@
   }
 
   std::unique_ptr<base::Value> token_data(
-      base::JSONReader::Read(file_contents));
+      base::JSONReader::ReadDeprecated(file_contents));
   base::DictionaryValue* tokens = nullptr;
   if (!token_data || !token_data->GetAsDictionary(&tokens)) {
     LOG(ERROR) << "Invalid refresh token file format, could not store token.";
diff --git a/services/data_decoder/json_parser_impl.cc b/services/data_decoder/json_parser_impl.cc
index 3ba458af..7118f9d6 100644
--- a/services/data_decoder/json_parser_impl.cc
+++ b/services/data_decoder/json_parser_impl.cc
@@ -21,8 +21,9 @@
 void JsonParserImpl::Parse(const std::string& json, ParseCallback callback) {
   int error_code;
   std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, &error_code, &error);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(json, base::JSON_PARSE_RFC,
+                                                     &error_code, &error);
   if (value) {
     std::move(callback).Run(base::make_optional(std::move(*value)),
                             base::nullopt);
diff --git a/services/data_decoder/public/cpp/json_sanitizer_unittest.cc b/services/data_decoder/public/cpp/json_sanitizer_unittest.cc
index dbb9824..a4f59d1b 100644
--- a/services/data_decoder/public/cpp/json_sanitizer_unittest.cc
+++ b/services/data_decoder/public/cpp/json_sanitizer_unittest.cc
@@ -62,15 +62,16 @@
 void JsonSanitizerTest::CheckSuccess(const std::string& json) {
   SCOPED_TRACE(json);
   Sanitize(json);
-  std::unique_ptr<base::Value> parsed = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> parsed = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(parsed);
   EXPECT_EQ(State::STATE_SUCCESS, state_) << "Error: " << error_;
 
   // The JSON parser should accept the result.
   int error_code;
   std::string error;
-  std::unique_ptr<base::Value> reparsed = base::JSONReader::ReadAndReturnError(
-      result_, base::JSON_PARSE_RFC, &error_code, &error);
+  std::unique_ptr<base::Value> reparsed =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          result_, base::JSON_PARSE_RFC, &error_code, &error);
   EXPECT_TRUE(reparsed) << "Invalid result: " << error;
 
   // The parsed values should be equal.
diff --git a/services/data_decoder/public/cpp/safe_json_parser_android.cc b/services/data_decoder/public/cpp/safe_json_parser_android.cc
index 22cd156..294bc8d 100644
--- a/services/data_decoder/public/cpp/safe_json_parser_android.cc
+++ b/services/data_decoder/public/cpp/safe_json_parser_android.cc
@@ -40,8 +40,9 @@
 
   int error_code;
   std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      sanitized_json, base::JSON_PARSE_RFC, &error_code, &error);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          sanitized_json, base::JSON_PARSE_RFC, &error_code, &error);
 
   if (!value) {
     error_callback_.Run(error);
diff --git a/services/data_decoder/public/cpp/testing_json_parser.cc b/services/data_decoder/public/cpp/testing_json_parser.cc
index c3eac72..2cddd953 100644
--- a/services/data_decoder/public/cpp/testing_json_parser.cc
+++ b/services/data_decoder/public/cpp/testing_json_parser.cc
@@ -47,8 +47,9 @@
 void TestingJsonParser::Start() {
   int error_code;
   std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      unsafe_json_, base::JSON_PARSE_RFC, &error_code, &error);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          unsafe_json_, base::JSON_PARSE_RFC, &error_code, &error);
 
   // Run the callback asynchronously. Post the delete task first, so that the
   // completion callbacks may quit the run loop without leaking |this|.
diff --git a/services/data_decoder/xml_parser_unittest.cc b/services/data_decoder/xml_parser_unittest.cc
index ed5bf06..b544d57f 100644
--- a/services/data_decoder/xml_parser_unittest.cc
+++ b/services/data_decoder/xml_parser_unittest.cc
@@ -46,7 +46,8 @@
   EXPECT_FALSE(error) << "Unexpected error: " << *error;
   EXPECT_TRUE(actual_value);
 
-  std::unique_ptr<base::Value> expected_value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> expected_value =
+      base::JSONReader::ReadDeprecated(json);
   DCHECK(expected_value) << "Bad test, incorrect JSON: " << json;
 
   EXPECT_EQ(*expected_value, *actual_value);
diff --git a/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java b/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
index 035f836..55b32c2 100644
--- a/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
+++ b/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
@@ -43,6 +43,12 @@
 @RunWith(ParameterizedRobolectricTestRunner.class)
 @Config(sdk = 21, manifest = Config.NONE)
 public class LocationProviderTest {
+    static {
+        // Setting robolectric.offline which tells Robolectric to look for runtime dependency
+        // JARs from a local directory and to not download them from Maven.
+        System.setProperty("robolectric.offline", "true");
+    }
+
     public static enum LocationProviderType { MOCK, ANDROID, GMS_CORE }
 
     @Parameters
diff --git a/services/device/geolocation/network_location_provider_unittest.cc b/services/device/geolocation/network_location_provider_unittest.cc
index 71fb266..24dae46b 100644
--- a/services/device/geolocation/network_location_provider_unittest.cc
+++ b/services/device/geolocation/network_location_provider_unittest.cc
@@ -249,8 +249,8 @@
 
     std::string json_parse_error_msg;
     std::unique_ptr<base::Value> parsed_json =
-        base::JSONReader::ReadAndReturnError(upload_data, base::JSON_PARSE_RFC,
-                                             nullptr, &json_parse_error_msg);
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            upload_data, base::JSON_PARSE_RFC, nullptr, &json_parse_error_msg);
     EXPECT_TRUE(json_parse_error_msg.empty());
     ASSERT_TRUE(parsed_json);
 
diff --git a/services/device/geolocation/network_location_request.cc b/services/device/geolocation/network_location_request.cc
index d928b62..86cc806 100644
--- a/services/device/geolocation/network_location_request.cc
+++ b/services/device/geolocation/network_location_request.cc
@@ -386,8 +386,8 @@
   // Parse the response, ignoring comments.
   std::string error_msg;
   std::unique_ptr<base::Value> response_value =
-      base::JSONReader::ReadAndReturnError(response_body, base::JSON_PARSE_RFC,
-                                           NULL, &error_msg);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          response_body, base::JSON_PARSE_RFC, NULL, &error_msg);
   if (response_value == NULL) {
     LOG(WARNING) << "ParseServerResponse() : JSONReader failed : " << error_msg;
     return false;
diff --git a/services/device/public/cpp/hid/hid_collection.cc b/services/device/public/cpp/hid/hid_collection.cc
index 60c7b34..c77ffc8f 100644
--- a/services/device/public/cpp/hid/hid_collection.cc
+++ b/services/device/public/cpp/hid/hid_collection.cc
@@ -26,6 +26,9 @@
 // computing the maximum report size.
 static constexpr uint64_t kMaxReasonableReportLengthBits =
     std::numeric_limits<uint16_t>::max() * 8;
+
+// Limit the maximum depth of the parser when inspecting nested collections.
+static constexpr int kMaxReasonableCollectionDepth = 50;
 }  // namespace
 
 HidCollection::HidCollection(HidCollection* parent,
@@ -43,6 +46,7 @@
   // This HID report descriptor parser implements a state machine described
   // in the HID specification. See section 6.2.2 Report Descriptor.
   HidItemStateTable state;
+  int depth = 0;
   for (const auto& current_item : items) {
     switch (current_item->tag()) {
       case HidReportDescriptorItem::kTagCollection:
@@ -50,15 +54,20 @@
         // separate components of the device and are often treated as separate
         // devices. Nested components represent logical collections of fields
         // within a report.
-        AddCollection(*current_item, collections, state);
+        ++depth;
+        if (depth <= kMaxReasonableCollectionDepth)
+          AddCollection(*current_item, collections, state);
         state.local.Reset();
         break;
       case HidReportDescriptorItem::kTagEndCollection:
-        // Mark the end of the current collection. Subsequent items describe
-        // reports associated with the parent collection.
-        if (state.collection)
-          state.collection = state.collection->parent_;
+        if (depth <= kMaxReasonableCollectionDepth) {
+          // Mark the end of the current collection. Subsequent items describe
+          // reports associated with the parent collection.
+          if (state.collection)
+            state.collection = state.collection->parent_;
+        }
         state.local.Reset();
+        --depth;
         break;
       case HidReportDescriptorItem::kTagInput:
       case HidReportDescriptorItem::kTagOutput:
diff --git a/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc b/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
index ff83d0b..932cb65 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
+++ b/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
@@ -1678,4 +1678,41 @@
                       kUnreasonablyHugeReportDescriptorSize);
 }
 
+TEST_F(HidReportDescriptorTest, HighlyNestedReportLimitsDepth) {
+  // The HID report descriptor parser sets a maximum depth to prevent issues
+  // with descriptors that define many nested collections. The descriptor below
+  // nests a single constant inside 51 collections.
+  static const uint8_t kHighlyNestedReportDescriptor[] = {
+      0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+      0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+      0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+      0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+      0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+
+      0x95, 0x01,  // Report Count (1)
+      0x75, 0x08,  // Report Size (8)
+      0x90         // Output
+  };
+  static const size_t kHighlyNestedReportDescriptorSize =
+      base::size(kHighlyNestedReportDescriptor);
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(0, 0);
+  AddTopCollectionInfo(std::move(info));
+  // The item in the innermost collection should still be reflected in the
+  // maximum report size.
+  ValidateDetails(false, 0, 1, 0, kHighlyNestedReportDescriptor,
+                  kHighlyNestedReportDescriptorSize);
+
+  // Construct nested collections up to the depth limit. The item from the
+  // innermost collection should be propagated to all its parents even though
+  // the depth limit has been reached.
+  auto* parent = AddTopCollection(0, kCollectionTypePhysical);
+  for (size_t i = 1; i < 50; ++i)
+    parent = AddChild(parent, 0, kCollectionTypePhysical);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(parent, kOutput, kNonNullableArray);
+  ValidateCollections(kHighlyNestedReportDescriptor,
+                      kHighlyNestedReportDescriptorSize);
+}
+
 }  // namespace device
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS
index 547d0d50..31d2f2e 100644
--- a/services/identity/public/cpp/DEPS
+++ b/services/identity/public/cpp/DEPS
@@ -2,6 +2,7 @@
   "+components/prefs/testing_pref_service.h",
   "+components/signin/core/browser/account_fetcher_service.h",
   "+components/signin/core/browser/account_info.h",
+  "+components/signin/core/browser/child_account_info_fetcher_android.h",
   "+components/signin/core/browser/fake_account_fetcher_service.h",
   "+components/signin/core/browser/gaia_cookie_manager_service.h",
   "+components/signin/core/browser/list_accounts_test_utils.h",
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index 82a14e5..42c95513 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -28,6 +28,10 @@
 #include "services/identity/public/cpp/accounts_mutator_impl.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "components/signin/core/browser/child_account_info_fetcher_android.h"
+#endif
+
 namespace identity {
 
 class IdentityManagerDependenciesOwner {
@@ -532,6 +536,12 @@
 
 void IdentityTestEnvironment::
     EnableOnAccountUpdatedAndOnAccountRemovedWithInfoCallbacks() {
+#if defined(OS_ANDROID)
+  // Enabling network fetches in AccountFetcherService in a testing
+  // context will cause a Java exception to go off on Android if the
+  // below call isn't made.
+  ChildAccountInfoFetcherAndroid::InitializeForTests();
+#endif
   account_fetcher_service_->EnableNetworkFetchesForTest();
 }
 
diff --git a/services/image_annotation/BUILD.gn b/services/image_annotation/BUILD.gn
index 751197f2..9ffdee9 100644
--- a/services/image_annotation/BUILD.gn
+++ b/services/image_annotation/BUILD.gn
@@ -12,6 +12,7 @@
 
   deps = [
     "//base",
+    "//components/google/core/common",
     "//mojo/public/cpp/bindings",
     "//net",
     "//services/image_annotation/public/mojom",
diff --git a/services/image_annotation/DEPS b/services/image_annotation/DEPS
index 6a2652f..af92bdd5 100644
--- a/services/image_annotation/DEPS
+++ b/services/image_annotation/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/google",
   "+net",
   "+services/network",
   "+third_party/skia",
diff --git a/services/image_annotation/annotator.cc b/services/image_annotation/annotator.cc
index 9fd9d54..4ca996a 100644
--- a/services/image_annotation/annotator.cc
+++ b/services/image_annotation/annotator.cc
@@ -13,6 +13,7 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
+#include "components/google/core/common/google_util.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "url/gurl.h"
@@ -90,7 +91,7 @@
     return {};
 
   const std::unique_ptr<base::Value> response =
-      base::JSONReader::Read(*json_response);
+      base::JSONReader::ReadDeprecated(*json_response);
   if (!response || !response->is_dict())
     return {};
 
@@ -133,8 +134,11 @@
 
 }  // namespace
 
+constexpr char Annotator::kGoogApiKeyHeader[];
+
 Annotator::Annotator(
     GURL server_url,
+    std::string api_key,
     const base::TimeDelta throttle,
     const int batch_size,
     const double min_ocr_confidence,
@@ -146,6 +150,7 @@
           base::BindRepeating(&Annotator::SendRequestBatchToServer,
                               base::Unretained(this))),
       server_url_(std::move(server_url)),
+      api_key_(std::move(api_key)),
       batch_size_(batch_size),
       min_ocr_confidence_(min_ocr_confidence) {}
 
@@ -237,6 +242,7 @@
 // static
 std::unique_ptr<network::SimpleURLLoader> Annotator::MakeOcrRequestLoader(
     const GURL& server_url,
+    const std::string& api_key,
     const HttpRequestQueue::iterator begin_it,
     const HttpRequestQueue::iterator end_it) {
   auto resource_request = std::make_unique<network::ResourceRequest>();
@@ -250,6 +256,13 @@
                                  net::LOAD_DO_NOT_SEND_COOKIES |
                                  net::LOAD_DO_NOT_SEND_AUTH_DATA;
 
+  // Put API key in request's header if a key exists, and the endpoint is
+  // trusted by Google.
+  if (!api_key.empty() && server_url.SchemeIs(url::kHttpsScheme) &&
+      google_util::IsGoogleAssociatedDomainUrl(server_url)) {
+    resource_request->headers.SetHeader(kGoogApiKeyHeader, api_key);
+  }
+
   // TODO(crbug.com/916420): update this annotation to be more general and to
   //                         reflect specfics of the UI when it is implemented.
   const net::NetworkTrafficAnnotationTag traffic_annotation =
@@ -332,7 +345,8 @@
   }
 
   // Kick off server communication.
-  http_requests_.push_back(MakeOcrRequestLoader(server_url_, begin_it, end_it));
+  http_requests_.push_back(
+      MakeOcrRequestLoader(server_url_, api_key_, begin_it, end_it));
   http_requests_.back()->DownloadToString(
       url_loader_factory_.get(),
       base::BindOnce(&Annotator::OnServerResponseReceived,
diff --git a/services/image_annotation/annotator.h b/services/image_annotation/annotator.h
index 96a5f71..3d5a40a5 100644
--- a/services/image_annotation/annotator.h
+++ b/services/image_annotation/annotator.h
@@ -38,11 +38,17 @@
 // images) or image pixels to the external server.
 class Annotator : public mojom::Annotator {
  public:
+  // The HTTP request header in which the API key should be transmitted.
+  static constexpr char kGoogApiKeyHeader[] = "X-Goog-Api-Key";
+
   // Constructs an annotator.
   //  |server_url|        : the URL of the server with which the annotator
   //                        communicates. The annotator gracefully handles (i.e.
   //                        returns errors when constructed with) an empty
   //                        server URL.
+  //  |api_key|           : the Google API key used to authenticate
+  //                        communication with the image annotation server. If
+  //                        empty, no API key header will be sent.
   //  |throttle|          : the miminum amount of time to wait between sending
   //                        new HTTP requests to the image annotation server.
   //  |batch_size|        : The maximum number of image annotation requests that
@@ -51,6 +57,7 @@
   //  |min_ocr_confidence|: The minimum confidence value needed to return an OCR
   //                        result.
   Annotator(GURL server_url,
+            std::string api_key,
             base::TimeDelta throttle,
             int batch_size,
             double min_ocr_confidence,
@@ -90,6 +97,7 @@
   // request for the given images.
   static std::unique_ptr<network::SimpleURLLoader> MakeOcrRequestLoader(
       const GURL& server_url,
+      const std::string& api_key,
       HttpRequestQueue::iterator begin_it,
       HttpRequestQueue::iterator end_it);
 
@@ -149,6 +157,8 @@
 
   const GURL server_url_;
 
+  const std::string api_key_;
+
   const int batch_size_;
 
   const double min_ocr_confidence_;
diff --git a/services/image_annotation/annotator_unittest.cc b/services/image_annotation/annotator_unittest.cc
index 790dba06..713855a3 100644
--- a/services/image_annotation/annotator_unittest.cc
+++ b/services/image_annotation/annotator_unittest.cc
@@ -5,6 +5,7 @@
 #include "services/image_annotation/annotator.h"
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/optional.h"
@@ -29,7 +30,7 @@
 using testing::IsEmpty;
 using testing::SizeIs;
 
-constexpr char kTestServerUrl[] = "https://test_ia_server.com/v1:ocr";
+constexpr char kTestServerUrl[] = "https://ia-pa.googleapis.com/v1/ocr";
 
 // Example image URLs.
 
@@ -224,13 +225,20 @@
     return *loader_factory_.pending_requests();
   }
 
-  // Expects that the earliest received request has the given URL and body, and
-  // replies with the given response.
+  // Expects that the earliest received request has the given URL, headers and
+  // body, and replies with the given response.
+  //
+  // |expected_headers| is a map from header key string to either:
+  //   a) a null optional, if the given header should not be present, or
+  //   b) a non-null optional, if the given header should be present and match
+  //      the optional value.
   //
   // Consumes the earliest received request (i.e. a subsequent call will apply
   // to the second-earliest received request and so on).
   void ExpectRequestAndSimulateResponse(
       const std::string& expected_url_suffix,
+      const std::map<std::string, base::Optional<std::string>>&
+          expected_headers,
       const std::string& expected_body,
       const std::string& response,
       const net::HttpStatusCode response_code) {
@@ -245,6 +253,18 @@
     // Assert that the earliest request is for the given URL.
     CHECK_EQ(request.url, GURL(expected_url));
 
+    // Expect that specified headers are accurate.
+    for (const auto& kv : expected_headers) {
+      if (kv.second.has_value()) {
+        std::string actual_value;
+        EXPECT_THAT(request.headers.GetHeader(kv.first, &actual_value),
+                    Eq(true));
+        EXPECT_THAT(actual_value, Eq(*kv.second));
+      } else {
+        EXPECT_THAT(request.headers.HasHeader(kv.first), Eq(false));
+      }
+    }
+
     // Extract request body.
     std::string actual_body;
     if (request.request_body) {
@@ -279,7 +299,8 @@
 // Returns a "canonically" formatted version of a JSON string by parsing and
 // then rewriting it.
 std::string ReformatJson(const std::string& in) {
-  const std::unique_ptr<base::Value> json = base::JSONReader::Read(in);
+  const std::unique_ptr<base::Value> json =
+      base::JSONReader::ReadDeprecated(in);
   CHECK(json);
 
   std::string out;
@@ -306,9 +327,11 @@
 TEST(AnnotatorTest, SuccessAndCache) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
   TestImageProcessor processor;
@@ -338,7 +361,7 @@
 
     // HTTP request should have been made.
     test_url_factory.ExpectRequestAndSimulateResponse(
-        "ocr",
+        "ocr", {} /* expected_headers */,
         ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
         kSuccessResponse, net::HTTP_OK);
     test_task_env.RunUntilIdle();
@@ -370,9 +393,11 @@
 TEST(AnnotatorTest, HttpError) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -399,7 +424,7 @@
 
   // HTTP request should have been made.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       "", net::HTTP_INTERNAL_SERVER_ERROR);
   test_task_env.RunUntilIdle();
@@ -413,9 +438,11 @@
 TEST(AnnotatorTest, BackendError) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -442,7 +469,7 @@
 
   // HTTP request should have been made.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       kErrorResponse, net::HTTP_OK);
   test_task_env.RunUntilIdle();
@@ -457,9 +484,11 @@
 TEST(AnnotatorTest, ServerError) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -486,7 +515,7 @@
 
   // HTTP request should have been made; respond with nonsense string.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       "Hello, world!", net::HTTP_OK);
   test_task_env.RunUntilIdle();
@@ -501,9 +530,11 @@
 TEST(AnnotatorTest, ProcessorFails) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -545,7 +576,7 @@
 
   // HTTP request for image 1 should have been made.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       kSuccessResponse, net::HTTP_OK);
   test_task_env.RunUntilIdle();
@@ -562,9 +593,11 @@
 TEST(AnnotatorTest, ProcessorDies) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -605,7 +638,7 @@
 
   // HTTP request for image 1 should have been made.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       kSuccessResponse, net::HTTP_OK);
   test_task_env.RunUntilIdle();
@@ -622,9 +655,11 @@
 TEST(AnnotatorTest, ConcurrentSameBatch) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 3 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 3 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -666,7 +701,8 @@
 
   // A single HTTP request for all images should have been sent.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr", ReformatJson(kBatchRequest), kBatchResponse, net::HTTP_OK);
+      "ocr", {} /* expected_headers */, ReformatJson(kBatchRequest),
+      kBatchResponse, net::HTTP_OK);
   test_task_env.RunUntilIdle();
 
   // Annotator should have called each callback with its corresponding text or
@@ -680,9 +716,11 @@
 TEST(AnnotatorTest, ConcurrentSeparateBatches) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 3 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 3 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -729,7 +767,7 @@
   // still waiting to make the batch that will include the request for image
   // 2).
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       R"({
            "results": [{
@@ -753,7 +791,7 @@
 
   // Now the HTTP request for image 2 should have been made.
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage2Url, "BAUG")),
       R"({
            "results": [{
@@ -783,9 +821,11 @@
 TEST(AnnotatorTest, DuplicateWork) {
   base::test::ScopedTaskEnvironment test_task_env(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory("https://test_ia_server.com/v1:");
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
 
-  Annotator annotator(GURL(kTestServerUrl), kThrottle, 1 /* batch_size */,
+  Annotator annotator(GURL(kTestServerUrl), std::string() /* api_key */,
+                      kThrottle, 1 /* batch_size */,
                       1.0 /* min_ocr_confidence */,
                       test_url_factory.AsSharedURLLoaderFactory());
 
@@ -856,7 +896,7 @@
   // HTTP request for the image should have been made (with bytes obtained from
   // processor 1).
   test_url_factory.ExpectRequestAndSimulateResponse(
-      "ocr",
+      "ocr", {} /* expected_headers */,
       ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
       kSuccessResponse, net::HTTP_OK);
   test_task_env.RunUntilIdle();
@@ -869,4 +909,102 @@
                           "Region 1\nRegion 2", "Region 1\nRegion 2"));
 }
 
+// Test that the specified API key is sent, but only to Google-associated server
+// domains.
+TEST(AnnotatorTest, ApiKey) {
+  base::test::ScopedTaskEnvironment test_task_env(
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
+
+  // A call to a secure Google-owner server URL should include the specified API
+  // key.
+  {
+    TestServerURLLoaderFactory test_url_factory(
+        "https://ia-pa.googleapis.com/v1/");
+
+    Annotator annotator(GURL(kTestServerUrl), "my_api_key", kThrottle,
+                        1 /* batch_size */, 1.0 /* min_ocr_confidence */,
+                        test_url_factory.AsSharedURLLoaderFactory());
+    TestImageProcessor processor;
+
+    annotator.AnnotateImage(kImage1Url, processor.GetPtr(), base::DoNothing());
+    test_task_env.RunUntilIdle();
+
+    // Annotator should have asked processor for pixels.
+    ASSERT_THAT(processor.callbacks(), SizeIs(1));
+
+    // Send back image data.
+    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    processor.callbacks().pop_back();
+    test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
+    test_task_env.RunUntilIdle();
+
+    // HTTP request should have been made with the API key included.
+    test_url_factory.ExpectRequestAndSimulateResponse(
+        "ocr", {{Annotator::kGoogApiKeyHeader, "my_api_key"}},
+        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
+        kSuccessResponse, net::HTTP_OK);
+  }
+
+  // A call to a Google-owned server URL should not include the API key if the
+  // requests are made insecurely.
+  {
+    // Note: not HTTPS.
+    TestServerURLLoaderFactory test_url_factory(
+        "http://ia-pa.googleapis.com/v1/");
+
+    Annotator annotator(GURL("http://ia-pa.googleapis.com/v1/ocr"),
+                        "my_api_key", kThrottle, 1 /* batch_size */,
+                        1.0 /* min_ocr_confidence */,
+                        test_url_factory.AsSharedURLLoaderFactory());
+    TestImageProcessor processor;
+
+    annotator.AnnotateImage(kImage1Url, processor.GetPtr(), base::DoNothing());
+    test_task_env.RunUntilIdle();
+
+    // Annotator should have asked processor for pixels.
+    ASSERT_THAT(processor.callbacks(), SizeIs(1));
+
+    // Send back image data.
+    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    processor.callbacks().pop_back();
+    test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
+    test_task_env.RunUntilIdle();
+
+    // HTTP request should have been made without the API key included.
+    test_url_factory.ExpectRequestAndSimulateResponse(
+        "ocr", {{Annotator::kGoogApiKeyHeader, base::nullopt}},
+        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
+        kSuccessResponse, net::HTTP_OK);
+  }
+
+  // A call to a non-Google-owned URL should not include the API key.
+  {
+    TestServerURLLoaderFactory test_url_factory("https://datascraper.com/");
+
+    Annotator annotator(GURL("https://datascraper.com/ocr"), "my_api_key",
+                        kThrottle, 1 /* batch_size */,
+                        1.0 /* min_ocr_confidence */,
+                        test_url_factory.AsSharedURLLoaderFactory());
+    TestImageProcessor processor;
+
+    annotator.AnnotateImage(kImage1Url, processor.GetPtr(), base::DoNothing());
+    test_task_env.RunUntilIdle();
+
+    // Annotator should have asked processor for pixels.
+    ASSERT_THAT(processor.callbacks(), SizeIs(1));
+
+    // Send back image data.
+    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    processor.callbacks().pop_back();
+    test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
+    test_task_env.RunUntilIdle();
+
+    // HTTP request should have been made without the API key included.
+    test_url_factory.ExpectRequestAndSimulateResponse(
+        "ocr", {{Annotator::kGoogApiKeyHeader, base::nullopt}},
+        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
+        kSuccessResponse, net::HTTP_OK);
+  }
+}
+
 }  // namespace image_annotation
diff --git a/services/image_annotation/image_annotation_service.cc b/services/image_annotation/image_annotation_service.cc
index 25cae578..45d015b 100644
--- a/services/image_annotation/image_annotation_service.cc
+++ b/services/image_annotation/image_annotation_service.cc
@@ -14,15 +14,18 @@
 
 constexpr base::Feature ImageAnnotationService::kExperiment;
 constexpr base::FeatureParam<std::string> ImageAnnotationService::kServerUrl;
+constexpr base::FeatureParam<std::string> ImageAnnotationService::kApiKey;
 constexpr base::FeatureParam<int> ImageAnnotationService::kThrottleMs;
 constexpr base::FeatureParam<int> ImageAnnotationService::kBatchSize;
 constexpr base::FeatureParam<double> ImageAnnotationService::kMinOcrConfidence;
 
 ImageAnnotationService::ImageAnnotationService(
     service_manager::mojom::ServiceRequest request,
+    std::string api_key,
     scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory)
     : service_binding_(this, std::move(request)),
       annotator_(GURL(kServerUrl.Get()),
+                 kApiKey.Get().empty() ? std::move(api_key) : kApiKey.Get(),
                  base::TimeDelta::FromMilliseconds(kThrottleMs.Get()),
                  kBatchSize.Get(),
                  kMinOcrConfidence.Get(),
diff --git a/services/image_annotation/image_annotation_service.h b/services/image_annotation/image_annotation_service.h
index 681b1e6..9cfc8d2 100644
--- a/services/image_annotation/image_annotation_service.h
+++ b/services/image_annotation/image_annotation_service.h
@@ -29,6 +29,7 @@
 
   ImageAnnotationService(
       service_manager::mojom::ServiceRequest request,
+      std::string api_key,
       scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory);
   ~ImageAnnotationService() override;
 
@@ -39,6 +40,10 @@
   // is empty. This ensures graceful behavior when |kExperiment| is disabled.
   static constexpr base::FeatureParam<std::string> kServerUrl{&kExperiment,
                                                               "server_url", ""};
+  // An override Google API key. If empty, the API key with which the browser
+  // was built (if any) will be used instead.
+  static constexpr base::FeatureParam<std::string> kApiKey{&kExperiment,
+                                                           "api_key", ""};
   static constexpr base::FeatureParam<int> kThrottleMs{&kExperiment,
                                                        "throttle_ms", 300};
   static constexpr base::FeatureParam<int> kBatchSize{&kExperiment,
diff --git a/services/network/expect_ct_reporter_unittest.cc b/services/network/expect_ct_reporter_unittest.cc
index ec86c81..bf8f9a6 100644
--- a/services/network/expect_ct_reporter_unittest.cc
+++ b/services/network/expect_ct_reporter_unittest.cc
@@ -215,7 +215,8 @@
                          const net::HostPortPair& host_port,
                          const std::string& expiration,
                          const net::SSLInfo& ssl_info) {
-  std::unique_ptr<base::Value> value(base::JSONReader::Read(serialized_report));
+  std::unique_ptr<base::Value> value(
+      base::JSONReader::ReadDeprecated(serialized_report));
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->is_dict());
 
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 56bfbba..703072d4 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -816,9 +816,15 @@
       corb_analyzer_->LogAllowedResponse();
     }
   }
-  if ((options_ & mojom::kURLLoadOptionSniffMimeType) &&
-      ShouldSniffContent(url_request_.get(), response_.get())) {
-    is_more_mime_sniffing_needed_ = true;
+  if ((options_ & mojom::kURLLoadOptionSniffMimeType)) {
+    if (ShouldSniffContent(url_request_.get(), response_.get())) {
+      is_more_mime_sniffing_needed_ = true;
+    } else if (response_->head.mime_type.empty()) {
+      // Ugg.  The server told us not to sniff the content but didn't give us
+      // a mime type.  What's a browser to do?  Turns out, we're supposed to
+      // treat the response as "text/plain".  This is the most secure option.
+      response_->head.mime_type.assign("text/plain");
+    }
   }
   if (!is_more_mime_sniffing_needed_ && !is_more_corb_sniffing_needed_) {
     // Treat feed types as text/plain.
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index ec496847..2e73c43 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -829,7 +829,7 @@
   set_sniff();
   EXPECT_EQ(net::OK, Load(test_server()->GetURL("/nosniff-test.html")));
   EXPECT_FALSE(did_mime_sniff());
-  ASSERT_TRUE(mime_type().empty());
+  ASSERT_EQ(std::string("text/plain"), mime_type());
 }
 
 TEST_F(URLLoaderTest, SniffTextPlainDoesNotResultInHTML) {
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc
index 1f4db61..92f2064 100644
--- a/services/tracing/perfetto/json_trace_exporter.cc
+++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -427,7 +427,7 @@
         metadata_->SetBoolean(metadata.name(), metadata.bool_value());
       } else if (metadata.has_json_value()) {
         std::unique_ptr<base::Value> value(
-            base::JSONReader::Read(metadata.json_value()));
+            base::JSONReader::ReadDeprecated(metadata.json_value()));
         metadata_->Set(metadata.name(), std::move(value));
       } else {
         NOTREACHED();
diff --git a/services/tracing/perfetto/json_trace_exporter_unittest.cc b/services/tracing/perfetto/json_trace_exporter_unittest.cc
index 85b77fe9..52f24b1 100644
--- a/services/tracing/perfetto/json_trace_exporter_unittest.cc
+++ b/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -79,7 +79,7 @@
     CHECK(!has_more);
 
     parsed_trace_data_ =
-        base::DictionaryValue::From(base::JSONReader::Read(json));
+        base::DictionaryValue::From(base::JSONReader::ReadDeprecated(json));
     EXPECT_TRUE(parsed_trace_data_);
     if (!parsed_trace_data_) {
       LOG(ERROR) << "Couldn't parse json: \n" << json;
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
index a740034..697a934 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -258,7 +258,7 @@
   EXPECT_TRUE(entry.has_json_value());
 
   std::unique_ptr<base::Value> child_dict =
-      base::JSONReader::Read(entry.json_value());
+      base::JSONReader::ReadDeprecated(entry.json_value());
   EXPECT_EQ(*child_dict, value);
 }
 
diff --git a/services/ws/client_root.cc b/services/ws/client_root.cc
index 22d34d9f..3ea18392 100644
--- a/services/ws/client_root.cc
+++ b/services/ws/client_root.cc
@@ -6,12 +6,13 @@
 
 #include "base/bind.h"
 #include "base/callback_forward.h"
-#include "base/debug/stack_trace.h"
+#include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "services/ws/client_change.h"
 #include "services/ws/client_change_tracker.h"
+#include "services/ws/common/switches.h"
 #include "services/ws/proxy_window.h"
 #include "services/ws/window_service.h"
 #include "services/ws/window_tree.h"
@@ -90,8 +91,14 @@
       window_->env()->context_factory_private()->GetHostFrameSinkManager();
   viz::FrameSinkId frame_sink_id =
       ProxyWindow::GetMayBeNull(window_)->frame_sink_id();
+  // This code only needs first-surface-activation for tests.
+  const bool wants_first_surface_activation =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseTestConfig);
   host_frame_sink_manager->RegisterFrameSinkId(
-      frame_sink_id, this, viz::ReportFirstSurfaceActivation::kYes);
+      frame_sink_id, this,
+      wants_first_surface_activation ? viz::ReportFirstSurfaceActivation::kYes
+                                     : viz::ReportFirstSurfaceActivation::kNo);
   window_->SetEmbedFrameSinkId(frame_sink_id);
 
   UpdateLocalSurfaceIdAndClientSurfaceEmbedder();
@@ -244,11 +251,13 @@
   const viz::SurfaceId surface_id(
       window_->GetFrameSinkId(),
       proxy_window->local_surface_id_allocation()->local_surface_id());
+  const bool surface_id_changed =
+      surface_id != client_surface_embedder_->GetSurfaceId();
   client_surface_embedder_->SetSurfaceId(surface_id);
 
   // This triggers holding events until the frame has been activated. This
   // ensures smooth resizes.
-  if (ShouldAssignLocalSurfaceId() && window_->GetHost())
+  if (surface_id_changed && ShouldAssignLocalSurfaceId() && window_->GetHost())
     window_->GetHost()->compositor()->OnChildResizing();
 }
 
@@ -401,6 +410,8 @@
 
 void ClientRoot::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
+  // NOTE: this function is only called if kUseTestConfig is supplied. See
+  // call to RegisterFrameSinkId().
   if (window_tree_->client_name().empty())
     return;
 
diff --git a/testing/android/junit/java/src/org/chromium/testing/local/CustomShadowUserManager.java b/testing/android/junit/java/src/org/chromium/testing/local/CustomShadowUserManager.java
index 51c8b26a..d62787d0 100644
--- a/testing/android/junit/java/src/org/chromium/testing/local/CustomShadowUserManager.java
+++ b/testing/android/junit/java/src/org/chromium/testing/local/CustomShadowUserManager.java
@@ -27,6 +27,7 @@
         return bundle != null ? bundle : new Bundle();
     }
 
+    @Override
     public void setApplicationRestrictions(String packageName, Bundle applicationRestrictions) {
         mApplicationRestrictions.put(packageName, applicationRestrictions);
     }
diff --git a/testing/android/junit/java/src/org/chromium/testing/local/GNManifestFactory.java b/testing/android/junit/java/src/org/chromium/testing/local/GNManifestFactory.java
index fd6468c7..1d346f6 100644
--- a/testing/android/junit/java/src/org/chromium/testing/local/GNManifestFactory.java
+++ b/testing/android/junit/java/src/org/chromium/testing/local/GNManifestFactory.java
@@ -7,10 +7,8 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.internal.ManifestFactory;
 import org.robolectric.internal.ManifestIdentifier;
-import org.robolectric.manifest.AndroidManifest;
 import org.robolectric.res.Fs;
 import org.robolectric.res.FsFile;
-import org.robolectric.res.ResourcePath;
 
 import java.io.File;
 import java.net.MalformedURLException;
@@ -37,14 +35,17 @@
             throw new RuntimeException("Specify manifest path in GN build file.");
         }
 
-        return new ManifestIdentifier(null, null, null, config.packageName(), null);
-    }
-
-    @Override
-    public AndroidManifest create(ManifestIdentifier manifestIdentifier) {
         String manifestPath = System.getProperty(CHROMIUM_MANIFEST_PATH);
         String resourceDirs = System.getProperty(CHROMIUM_RES_DIRECTORIES);
 
+        FsFile manifestFile = null;
+        if (manifestPath != null) {
+            try {
+                manifestFile = Fs.fromURL(new File(manifestPath).toURI().toURL());
+            } catch (MalformedURLException e) {
+            }
+        }
+
         final List<FsFile> resourceDirsList = new ArrayList<FsFile>();
         if (resourceDirs != null) {
             for (String resourceDir : resourceDirs.split(":")) {
@@ -55,23 +56,11 @@
             }
         }
 
-        FsFile manifestFile = null;
-        if (manifestPath != null) {
-            try {
-                manifestFile = Fs.fromURL(new File(manifestPath).toURI().toURL());
-            } catch (MalformedURLException e) {
-            }
+        List<ManifestIdentifier> libraries = new ArrayList<>();
+        for (FsFile resDir : resourceDirsList) {
+            libraries.add(new ManifestIdentifier(config.packageName(), null, resDir, null, null));
         }
 
-        return new AndroidManifest(manifestFile, null, null, manifestIdentifier.getPackageName()) {
-            @Override
-            public List<ResourcePath> getIncludedResourcePaths() {
-                List<ResourcePath> paths = super.getIncludedResourcePaths();
-                for (FsFile resourceDir : resourceDirsList) {
-                    paths.add(new ResourcePath(getRClass(), resourceDir, getAssetsDirectory()));
-                }
-                return paths;
-            }
-        };
+        return new ManifestIdentifier(config.packageName(), manifestFile, null, null, libraries);
     }
 }
diff --git a/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java b/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java
index 210a4d56..6ecb3e7 100644
--- a/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java
+++ b/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java
@@ -13,7 +13,7 @@
  * A custom Robolectric Junit4 Test Runner with Chromium specific settings.
  */
 public class LocalRobolectricTestRunner extends RobolectricTestRunner {
-    public static final int DEFAULT_SDK = 26;
+    public static final int DEFAULT_SDK = 28;
     private static final String DEFAULT_PACKAGE_NAME = "org.robolectric.default";
 
     static {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index f75012b..e988fd09 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -15537,6 +15537,54 @@
       },
       {
         "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--refimg-cloud-storage-bucket",
+          "chromium-gpu-archive/reference-images",
+          "--os-type",
+          "linux",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}",
+          "--use-skia-gold"
+        ],
+        "experiment_percentage": 100,
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "pixel_skia_gold_test",
+        "non_precommit_args": [
+          "--upload-refimg-to-cloud-storage"
+        ],
+        "precommit_args": [
+          "--download-refimg-from-cloud-storage",
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-17.1.4",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
           "trace_test",
           "--show-stdout",
           "--browser=release",
@@ -15818,6 +15866,63 @@
       },
       {
         "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--refimg-cloud-storage-bucket",
+          "chromium-gpu-archive/reference-images",
+          "--os-type",
+          "linux",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}",
+          "--use-skia-gold"
+        ],
+        "experiment_percentage": 100,
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "pixel_skia_gold_test",
+        "non_precommit_args": [
+          "--upload-refimg-to-cloud-storage"
+        ],
+        "precommit_args": [
+          "--download-refimg-from-cloud-storage",
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-384.90",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"10de:1cb3-384.90\", \"os\": \"Ubuntu\", \"pool\": \"Chrome-GPU\"}, {\"gpu\": \"10de:1cb3-410.78\", \"os\": \"Ubuntu\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
           "trace_test",
           "--show-stdout",
           "--browser=release",
diff --git a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
index 5beb44da..fd5ded74 100644
--- a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
@@ -309,7 +309,6 @@
 # disabled.
 # https://crbug.com/827327
 -PictureInPictureWindowControllerBrowserTest.*
--ControlPictureInPictureWindowControllerBrowserTest.*
 -BrowserActionApiTest.TestPictureInPictureOnBrowserActionIconClick
 -PlatformAppBrowserTest.PictureInPicture
 -PictureInPictureLazyBackgroundPageApiTest.PictureInPictureInBackgroundPage
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index b4b10d4..dcaf5a0dc 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -3473,6 +3473,43 @@
       },
     },
 
+    'gpu_telemetry_tests_for_skia_gold_testing': {
+      'pixel': {
+        'name': 'pixel_skia_gold_test',
+        'args': [
+          '--dont-restore-color-profile-after-test',
+          '--refimg-cloud-storage-bucket',
+          'chromium-gpu-archive/reference-images',
+          '--os-type',
+          '${os_type}',
+          '--build-revision',
+          '${got_revision}',
+          '--test-machine-name',
+          '${buildername}',
+          '--use-skia-gold',
+        ],
+        'non_precommit_args': [
+          '--upload-refimg-to-cloud-storage',
+        ],
+        'precommit_args': [
+          '--download-refimg-from-cloud-storage',
+          # Gerrit issue ID
+          '--review-patch-issue',
+          '${patch_issue}',
+          # Patch set number
+          '--review-patch-set',
+          '${patch_set}',
+          # Buildbucket ID
+          '--buildbucket-build-id',
+          '${buildbucket_build_id}',
+        ],
+        'experiment_percentage': 100,
+        'swarming': {
+          'service_account': 'chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com'
+        }
+      },
+    },
+
     'gpu_webgl_conformance_d3d11_validating_tests': {
       'webgl_conformance_d3d11_validating': {
         'telemetry_test_name': 'webgl_conformance',
@@ -4752,6 +4789,7 @@
       'gpu_common_and_optional_telemetry_tests',
       'gpu_fyi_and_optional_win_and_linux_specific_telemetry_tests',
       'gpu_fyi_optional_and_v8_desktop_release_specific_telemetry_tests',
+      'gpu_telemetry_tests_for_skia_gold_testing',
     ],
 
     'gpu_fyi_optional_telemetry_tests': [
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py
index f795877..4628d63d 100755
--- a/testing/scripts/run_performance_tests.py
+++ b/testing/scripts/run_performance_tests.py
@@ -29,19 +29,21 @@
 It currently runs several benchmarks. The benchmarks it will execute are
 based on the shard it is running on and the sharding_map_path.
 
-If this is executed with a non-telemetry perf test, the flag --non-telemetry
+If this is executed with a gtest perf test, the flag --non-telemetry
 has to be passed in to the script so the script knows it is running
 an executable and not the run_benchmark command.
 
 The results of running the benchmark are put in separate directories per
 benchmark. Two files will be present in each directory; perf_results.json, which
-is the perf specific results (with unenforced format, could be histogram,
-legacy, or chartjson), and test_results.json, which is a JSON test results
+is the perf specific results (with unenforced format, could be histogram or
+graph json), and test_results.json, which is a JSON test results
 format file
-(https://www.chromium.org/developers/the-json-test-results-format)
+https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md
 
-This script was derived from run_telemetry_benchmark_as_googletest, and calls
-into that script.
+TESTING:
+To test changes to this script, please run
+cd tools/perf
+./run_tests ScriptsSmokeTest.testRunPerformanceTests
 """
 
 import argparse
@@ -73,30 +75,39 @@
 # (it seems to unset DISPLAY).
 CHROME_SANDBOX_ENV = 'CHROME_DEVEL_SANDBOX'
 CHROME_SANDBOX_PATH = '/opt/chromium/chrome_sandbox'
+SHARD_MAPS_DIRECTORY = os.path.join(
+    os.path.dirname(__file__), '..', '..', 'tools', 'perf', 'core',
+    'shard_maps')
 
 
-def get_sharding_map_path(args):
-  return os.path.join(
-      os.path.dirname(__file__), '..', '..', 'tools', 'perf', 'core',
-      'shard_maps', args.test_shard_map_filename)
+class OutputFilePaths(object):
+  """Provide paths to where results outputs should be written.
 
-def write_results(
-    perf_test_name, perf_results, json_test_results, benchmark_log,
-    isolated_out_dir, encoded):
-  benchmark_path = os.path.join(isolated_out_dir, perf_test_name)
+  The process_perf_results.py merge script later will pull all of these
+  together, so that's why they aren't in the standard locations. Also,
+  note that because of the OBBS (One Build Bot Step), Telemetry
+  has multiple tests running on a single shard, so we need to prefix
+  these locations with a directory named by the benchmark name.
+  """
 
-  os.makedirs(benchmark_path)
-  with open(os.path.join(benchmark_path, 'perf_results.json'), 'w') as f:
-    # non telemetry perf results are already json encoded
-    if encoded:
-      f.write(perf_results)
-    else:
-      json.dump(perf_results, f)
-  with open(os.path.join(benchmark_path, 'test_results.json'), 'w') as f:
-    json.dump(json_test_results, f)
+  def __init__(self, isolated_out_dir, perf_test_name):
+    self.benchmark_path = os.path.join(isolated_out_dir, perf_test_name)
 
-  with open(os.path.join(benchmark_path, 'benchmark_log.txt'), 'w') as f:
-    f.write(benchmark_log)
+  def SetUp(self):
+    os.makedirs(self.benchmark_path)
+    return self
+
+  @property
+  def perf_results(self):
+    return os.path.join(self.benchmark_path, 'perf_results.json')
+
+  @property
+  def test_results(self):
+    return os.path.join(self.benchmark_path, 'test_results.json')
+
+  @property
+  def logs(self):
+    return os.path.join(self.benchmark_path, 'benchmark_log.txt')
 
 
 def print_duration(step, start):
@@ -107,131 +118,243 @@
   return sys.platform == 'cygwin' or sys.platform.startswith('win')
 
 
-def execute_gtest_perf_test(args, rest_args):
+class GtestCommandGenerator(object):
+  def __init__(self, options):
+    self._options = options
+
+  def generate(self):
+    """Generate the command to run to start the gtest perf test.
+
+    Returns:
+      list of strings, the executable and its arguments.
+    """
+    return ([self._get_executable()] +
+            self._generate_filter_args() +
+            self._generate_repeat_args() +
+            self._generate_also_run_disabled_tests_args() +
+            self._generate_output_args() +
+            self._get_passthrough_args()
+           )
+
+  def _get_executable(self):
+    executable = self._options.executable
+    if IsWindows():
+      return r'.\%s.exe' % executable
+    else:
+      return './%s' % executable
+
+  def _get_passthrough_args(self):
+    return self._options.passthrough_args
+
+  def _generate_filter_args(self):
+    if self._options.isolated_script_test_filter:
+      filter_list = common.extract_filter_list(
+        self._options.isolated_script_test_filter)
+      return ['--gtest_filter=' + ':'.join(filter_list)]
+    return []
+
+  def _generate_repeat_args(self):
+    # TODO(crbug.com/920002): Support --isolated-script-test-repeat.
+    return []
+
+  def _generate_also_run_disabled_tests_args(self):
+    # TODO(crbug.com/920002): Support
+    # --isolated-script-test-also-run-disabled-tests.
+    return []
+
+  def _generate_output_args(self):
+    output_args = []
+    # These flags are to make sure that test output perf metrics in the log.
+    if not '--verbose' in self._options.passthrough_args:
+      output_args.append('--verbose')
+    if (not '--test-launcher-print-test-stdio=always'
+        in self._options.passthrough_args):
+      output_args.append('--test-launcher-print-test-stdio=always')
+    return output_args
+
+
+def write_legacy_test_results(return_code, output_filepath):
+  # TODO(crbug.com/920002): Fix to output
+  # https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md
+  valid = (return_code == 0)
+  failures = [] if valid else ['(entire test suite)']
+  output_json = {
+      'valid': valid,
+      'failures': failures,
+  }
+  with open(output_filepath, 'w') as fh:
+    json.dump(output_json, fh)
+
+
+def execute_gtest_perf_test(command_generator, output_paths, use_xvfb=False):
   env = os.environ.copy()
   # Assume we want to set up the sandbox environment variables all the
   # time; doing so is harmless on non-Linux platforms and is needed
   # all the time on Linux.
   env[CHROME_SANDBOX_ENV] = CHROME_SANDBOX_PATH
+  env['CHROME_HEADLESS'] = '1'
 
-  rc = 0
+  return_code = 0
   try:
-    executable = rest_args[0]
-    extra_flags = []
-    if len(rest_args) > 1:
-      extra_flags = rest_args[1:]
-
-    # These flags are to make sure that test output perf metrics in the log.
-    if not '--verbose' in extra_flags:
-      extra_flags.append('--verbose')
-    if not '--test-launcher-print-test-stdio=always' in extra_flags:
-      extra_flags.append('--test-launcher-print-test-stdio=always')
-    if args.isolated_script_test_filter:
-      filter_list = common.extract_filter_list(
-        args.isolated_script_test_filter)
-      extra_flags.append('--gtest_filter=' + ':'.join(filter_list))
-
-    if IsWindows():
-      executable = '.\%s.exe' % executable
+    command = command_generator.generate()
+    if use_xvfb:
+      return_code = xvfb.run_executable(
+          command, env, stdoutfile=output_paths.logs)
     else:
-      executable = './%s' % executable
-    with common.temporary_file() as tempfile_path:
-      env['CHROME_HEADLESS'] = '1'
-      cmd = [executable] + extra_flags
-
-      if args.xvfb:
-        rc = xvfb.run_executable(cmd, env, stdoutfile=tempfile_path)
-      else:
-        rc = test_env.run_command_with_output(cmd, env=env,
-                                              stdoutfile=tempfile_path)
-
-      # Now get the correct json format from the stdout to write to the perf
-      # results file
-      results_processor = (
-          generate_legacy_perf_dashboard_json.LegacyResultsProcessor())
-      charts = results_processor.GenerateJsonResults(tempfile_path)
+      return_code = test_env.run_command_with_output(
+          command, env=env, stdoutfile=output_paths.logs)
+    # Get the correct json format from the stdout to write to the perf
+    # results file.
+    results_processor = generate_legacy_perf_dashboard_json.\
+        LegacyResultsProcessor()
+    graph_json_string = results_processor.GenerateJsonResults(
+        output_paths.logs)
+    with open(output_paths.perf_results, 'w') as fh:
+      fh.write(graph_json_string)
   except Exception:
     traceback.print_exc()
-    rc = 1
+    return_code = 1
+  write_legacy_test_results(return_code, output_paths.test_results)
+  return return_code
 
-  valid = (rc == 0)
-  failures = [] if valid else ['(entire test suite)']
-  output_json = {
-      'valid': valid,
-      'failures': failures,
-    }
-  return rc, charts, output_json
+
+class TelemetryCommandGenerator(object):
+  def __init__(self, benchmark, options,
+               stories=None, is_reference=False):
+    self.benchmark = benchmark
+    self._options = options
+    self._stories = stories
+    self._is_reference = is_reference
+
+  def generate(self, output_dir):
+    """Generate the command to run to start the benchmark.
+
+    Args:
+      output_dir: The directory to configure the command to put output files
+        into.
+
+    Returns:
+      list of strings, the executable and its arguments.
+    """
+    return ([sys.executable, self._options.executable] +
+            [self.benchmark] +
+            self._generate_filter_args() +
+            self._generate_repeat_args() +
+            self._generate_also_run_disabled_tests_args() +
+            self._generate_output_args(output_dir) +
+            self._generate_story_range_args() +
+            # passthrough args must be before reference args: crbug.com/928928
+            self._get_passthrough_args() +
+            self._generate_reference_build_args()
+           )
+
+  def _get_passthrough_args(self):
+    return self._options.passthrough_args
+
+  def _generate_filter_args(self):
+    if self._options.isolated_script_test_filter:
+      filter_list = common.extract_filter_list(
+          self._options.isolated_script_test_filter)
+      # Need to convert this to a valid regex.
+      filter_regex = '(' + '|'.join(filter_list) + ')'
+      return ['--story-filter=' + filter_regex]
+    return []
+
+  def _generate_repeat_args(self):
+    if self._options.isolated_script_test_repeat:
+      return ['--pageset-repeat=' + str(
+          self._options.isolated_script_test_repeat)]
+    return []
+
+  def _generate_also_run_disabled_tests_args(self):
+    if self._options.isolated_script_test_also_run_disabled_tests:
+      return ['--also-run-disabled-tests']
+    return []
+
+  def _generate_output_args(self, output_dir):
+    return ['--output-format=json-test-results',
+            '--output-format=histograms',
+            '--output-dir=' + output_dir]
+
+  def _generate_story_range_args(self):
+    """Returns arguments that limit the stories to be run inside the benchmark.
+    """
+    range_arguments = []
+    if self._stories:
+      if 'begin' in self._stories.keys():
+        range_arguments.append('--story-shard-begin-index=%d' % (
+            self._stories['begin']))
+      if 'end' in self._stories.keys():
+        range_arguments.append('--story-shard-end-index=%d' % (
+            self._stories['end']))
+    return range_arguments
+
+  def _generate_reference_build_args(self):
+    if self._is_reference:
+      return ['--browser=reference',
+              '--max-failures=5',
+              '--output-trace-tag=_ref']
+    return []
 
 
 def execute_telemetry_benchmark(
-    benchmark, isolated_out_dir, args, rest_args, is_reference, stories=None):
+    command_generator, output_paths, use_xvfb=False):
   start = time.time()
-  # While we are between chartjson and histogram set we need
-  # to determine which output format to look for or see if it was
-  # already passed in in which case that format applies to all benchmarks
-  # in this run.
-  is_histograms = append_output_format(args, rest_args)
-  # Insert benchmark name as first argument to run_benchmark call
-  # which is the first argument in the rest_args.  Also need to append
-  # output format and smoke test mode.
-  per_benchmark_args = (rest_args[:1] + [benchmark] + rest_args[1:])
-  benchmark_name = benchmark
-  if is_reference:
-    # Telemetry uses the last argument for --browser, so it's okay
-    # to not check for an existing browser argument. See crbug.com/928928.
-    per_benchmark_args.append('--browser=reference')
-    per_benchmark_args.append('--max-failures=5')
-    per_benchmark_args.append('--output-trace-tag=_ref')
-    benchmark_name = benchmark + '.reference'
 
-  # If we are only running a subset of stories, add in the begin and end
-  # index.
-  if stories:
-    if 'begin' in stories.keys():
-      per_benchmark_args.append(
-          ('--story-shard-begin-index=%d' % stories['begin']))
-    if 'end' in stories.keys():
-      per_benchmark_args.append(
-          ('--story-shard-end-index=%d' % stories['end']))
+  env = os.environ.copy()
+  env['CHROME_HEADLESS'] = '1'
+  # Assume we want to set up the sandbox environment variables all the
+  # time; doing so is harmless on non-Linux platforms and is needed
+  # all the time on Linux.
+  env[CHROME_SANDBOX_ENV] = CHROME_SANDBOX_PATH
 
-  # We don't care exactly what these are. In particular, the perf results
-  # could be any format (chartjson, legacy, histogram). We just pass these
-  # through, and expose these as results for this task.
-  rc, perf_results, json_test_results, benchmark_log = (
-      execute_telemetry_benchmark_helper(
-          args, per_benchmark_args, is_histograms))
+  return_code = 1
+  temp_dir = tempfile.mkdtemp('telemetry')
+  try:
+    command = command_generator.generate(temp_dir)
+    if use_xvfb:
+      return_code = xvfb.run_executable(
+          command, env=env, stdoutfile=output_paths.logs)
+    else:
+      return_code = test_env.run_command_with_output(
+          command, env=env, stdoutfile=output_paths.logs)
+    expected_perf_filename = os.path.join(temp_dir, 'histograms.json')
+    shutil.move(expected_perf_filename, output_paths.perf_results)
+    expected_results_filename = os.path.join(temp_dir, 'test-results.json')
+    shutil.move(expected_results_filename, output_paths.test_results)
+  except Exception:
+    print ('The following exception may have prevented the code from '
+           'outputing structured test results and perf results output:')
+    print traceback.format_exc()
+  finally:
+    # Add ignore_errors=True because otherwise rmtree may fail due to leaky
+    # processes of tests are still holding opened handles to files under
+    # |tempfile_dir|. For example, see crbug.com/865896
+    shutil.rmtree(temp_dir, ignore_errors=True)
 
-  write_results(
-      benchmark_name, perf_results, json_test_results, benchmark_log,
-      isolated_out_dir, False)
+  print_duration('executing benchmark %s' % command_generator.benchmark, start)
 
-  print_duration('executing benchmark %s' % benchmark_name, start)
-  return rc
+  if return_code:
+    return return_code
+  return 0
 
-
-def execute_telemetry_benchmark_helper(args, rest_args, histogram_results):
-  """Run benchmark with args.
-
-  Args:
-    args: the option object resulted from parsing commandline args required for
-      IsolatedScriptTest contract (see
-      https://cs.chromium.org/chromium/build/scripts/slave/recipe_modules/chromium_tests/steps.py?rcl=d31f256fb860701e6dc02544f2beffe4e17c9b92&l=1639).
-    rest_args: the args (list of strings) for running Telemetry benchmark.
-    histogram_results: a boolean describes whether to output histograms format
-      for the benchmark.
-
-  Returns: a tuple of (rc, perf_results, json_test_results, benchmark_log)
-    rc: the return code of benchmark
-    perf_results: json object contains the perf test results
-    json_test_results: json object contains the Pass/Fail data of the benchmark.
-    benchmark_log: string contains the stdout/stderr of the benchmark run.
-  """
-  # TODO(crbug.com/920002): These arguments cannot go into
-  # run_performance_tests.py because
-  # run_gtest_perf_tests.py does not yet support them. Note that ideally
-  # we would use common.BaseIsolatedScriptArgsAdapter, but this will take
-  # a good deal of refactoring to accomplish.
+def parse_arguments(args):
   parser = argparse.ArgumentParser()
+  parser.add_argument('executable', help='The name of the executable to run.')
+  parser.add_argument(
+      '--isolated-script-test-output', required=True)
+  # The following two flags may be passed in sometimes by Pinpoint
+  # or by the recipe, but they don't do anything. crbug.com/927482.
+  parser.add_argument(
+      '--isolated-script-test-chartjson-output', required=False)
+  parser.add_argument(
+      '--isolated-script-test-perf-output', required=False)
+
+  parser.add_argument(
+      '--isolated-script-test-filter', type=str, required=False)
+
+  # Note that the following three arguments are only supported by Telemetry
+  # tests right now. See crbug.com/920002.
   parser.add_argument(
       '--isolated-script-test-repeat', type=int, required=False)
   parser.add_argument(
@@ -240,126 +363,6 @@
   parser.add_argument(
       '--isolated-script-test-also-run-disabled-tests',
       default=False, action='store_true', required=False)
-  # Parse leftover args not already parsed in run_performance_tests.py or in
-  # main().
-  args, rest_args = parser.parse_known_args(args=rest_args, namespace=args)
-
-  env = os.environ.copy()
-  env['CHROME_HEADLESS'] = '1'
-
-  # Assume we want to set up the sandbox environment variables all the
-  # time; doing so is harmless on non-Linux platforms and is needed
-  # all the time on Linux.
-  env[CHROME_SANDBOX_ENV] = CHROME_SANDBOX_PATH
-  tempfile_dir = tempfile.mkdtemp('telemetry')
-  benchmark_log = ''
-  stdoutfile = os.path.join(tempfile_dir, 'benchmark_log.txt')
-  valid = True
-  num_failures = 0
-  perf_results = None
-  json_test_results = None
-
-  results = None
-  cmd_args = rest_args
-  if args.isolated_script_test_filter:
-    filter_list = common.extract_filter_list(args.isolated_script_test_filter)
-    # Need to convert this to a valid regex.
-    filter_regex = '(' + '|'.join(filter_list) + ')'
-    cmd_args.append('--story-filter=' + filter_regex)
-  if args.isolated_script_test_repeat:
-    cmd_args.append('--pageset-repeat=' + str(args.isolated_script_test_repeat))
-  if args.isolated_script_test_also_run_disabled_tests:
-    cmd_args.append('--also-run-disabled-tests')
-  cmd_args.append('--output-dir=' + tempfile_dir)
-  cmd_args.append('--output-format=json-test-results')
-  cmd = [sys.executable] + cmd_args
-  rc = 1  # Set default returncode in case there is an exception.
-  try:
-    if args.xvfb:
-      rc = xvfb.run_executable(cmd, env=env, stdoutfile=stdoutfile)
-    else:
-      rc = test_env.run_command_with_output(cmd, env=env, stdoutfile=stdoutfile)
-
-    with open(stdoutfile) as f:
-      benchmark_log = f.read()
-
-    # If we have also output chartjson read it in and return it.
-    # results-chart.json is the file name output by telemetry when the
-    # chartjson output format is included
-    tempfile_name = None
-    if histogram_results:
-      tempfile_name = os.path.join(tempfile_dir, 'histograms.json')
-    else:
-      tempfile_name = os.path.join(tempfile_dir, 'results-chart.json')
-
-    if tempfile_name is not None:
-      with open(tempfile_name) as f:
-        perf_results = json.load(f)
-
-    # test-results.json is the file name output by telemetry when the
-    # json-test-results format is included
-    tempfile_name = os.path.join(tempfile_dir, 'test-results.json')
-    with open(tempfile_name) as f:
-      json_test_results = json.load(f)
-    num_failures = json_test_results['num_failures_by_type'].get('FAIL', 0)
-    valid = bool(rc == 0 or num_failures != 0)
-
-  except Exception:
-    traceback.print_exc()
-    if results:
-      print 'results, which possibly caused exception: %s' % json.dumps(
-          results, indent=2)
-    valid = False
-  finally:
-    # Add ignore_errors=True because otherwise rmtree may fail due to leaky
-    # processes of tests are still holding opened handles to files under
-    # |tempfile_dir|. For example, see crbug.com/865896
-    shutil.rmtree(tempfile_dir, ignore_errors=True)
-
-  if not valid and num_failures == 0:
-    if rc == 0:
-      rc = 1  # Signal an abnormal exit.
-
-  return rc, perf_results, json_test_results, benchmark_log
-
-
-def append_output_format(args, rest_args):
-  # We need to determine if the output format is already passed in
-  # or if we need to define it for this benchmark
-  perf_output_specified = False
-  is_histograms = False
-  if args.output_format:
-    for output_format in args.output_format:
-      if 'histograms' in output_format:
-        perf_output_specified = True
-        is_histograms = True
-      if 'chartjson' in output_format:
-        perf_output_specified = True
-      rest_args.append('--output-format=' + output_format)
-  # When crbug.com/744736 is resolved we no longer have to check
-  # the type of format per benchmark and can rely on it being passed
-  # in as an arg as all benchmarks will output the same format.
-  if not perf_output_specified:
-    rest_args.append('--output-format=histograms')
-    is_histograms = True
-  return is_histograms
-
-
-def main():
-  parser = argparse.ArgumentParser()
-  parser.add_argument(
-      '--isolated-script-test-output', required=True)
-  # These two flags are passed in from the swarming recipe
-  # but will no longer be needed when we migrate to this new recipe.
-  # For now we need to recognize them so they don't get passed
-  # through to telemetry.
-  parser.add_argument(
-      '--isolated-script-test-chartjson-output', required=False)
-  parser.add_argument(
-      '--isolated-script-test-perf-output', required=False)
-
-  parser.add_argument(
-      '--isolated-script-test-filter', type=str, required=False)
   parser.add_argument('--xvfb', help='Start xvfb.', action='store_true')
   parser.add_argument('--non-telemetry',
                       help='Type of perf test', type=bool, default=False)
@@ -374,76 +377,103 @@
   # Some executions may have a different sharding scheme and/or set of tests.
   # These files must live in src/tools/perf/core/shard_maps
   parser.add_argument('--test-shard-map-filename', type=str, required=False)
-  parser.add_argument('--output-format', action='append')
   parser.add_argument('--run-ref-build',
                       help='Run test on reference browser', action='store_true')
+  parser.add_argument('--passthrough-arg',
+                      help='Arguments to pass directly through to the test '
+                      'executable.', action='append',
+                      dest='passthrough_args',
+                      default=[])
+  options, leftover_args = parser.parse_known_args(args)
+  options.passthrough_args.extend(leftover_args)
+  return options
 
-  args, rest_args = parser.parse_known_args()
-  isolated_out_dir = os.path.dirname(args.isolated_script_test_output)
-  return_code = 0
 
-  if args.non_telemetry:
-    benchmark_name = args.gtest_benchmark_name
+def main():
+  args = sys.argv[1:]  # Skip program name.
+  options = parse_arguments(args)
+  isolated_out_dir = os.path.dirname(options.isolated_script_test_output)
+  overall_return_code = 0
+
+  if options.non_telemetry:
+    command_generator = GtestCommandGenerator(options)
+    benchmark_name = options.gtest_benchmark_name
     # Fallback to use the name of the executable if flag isn't set.
     # TODO(crbug.com/870899): remove fallback logic and raise parser error if
-    # -non-telemetry is set but --gtest-benchmark-name is not set once pinpoint
+    # --non-telemetry is set but --gtest-benchmark-name is not set once pinpoint
     # is converted to always pass --gtest-benchmark-name flag.
     if not benchmark_name:
-      benchmark_name = rest_args[0]
-    return_code, charts, output_json = execute_gtest_perf_test(
-        args, rest_args)
-
-    write_results(benchmark_name, charts, output_json,
-                  benchmark_log='Not available for C++ perf test',
-                  isolated_out_dir=isolated_out_dir, encoded=True)
+      benchmark_name = options.executable
+    output_paths = OutputFilePaths(isolated_out_dir, benchmark_name).SetUp()
+    overall_return_code = execute_gtest_perf_test(
+        command_generator, output_paths, options.xvfb)
   else:
     # If the user has supplied a list of benchmark names, execute those instead
-    # of the entire suite of benchmarks.
-    if args.benchmarks:
-      benchmarks = args.benchmarks.split(',')
+    # of using the shard map.
+    if options.benchmarks:
+      benchmarks = options.benchmarks.split(',')
       for benchmark in benchmarks:
-        return_code = (execute_telemetry_benchmark(
-            benchmark, isolated_out_dir, args, rest_args, False) or return_code)
-    else:
+        output_paths = OutputFilePaths(isolated_out_dir, benchmark).SetUp()
+        command_generator = TelemetryCommandGenerator(
+            benchmark, options)
+        return_code = execute_telemetry_benchmark(
+            command_generator, output_paths, options.xvfb)
+        overall_return_code = return_code or overall_return_code
+      if options.run_ref_build:
+        print ('Not running reference build. --run-ref-build argument is only '
+               'supported for sharded benchmarks. It is simple to support '
+               'this for unsharded --benchmarks if needed.')
+    elif options.test_shard_map_filename:
       # First determine what shard we are running on to know how to
-      # index into the bot map to get list of benchmarks to run.
+      # index into the bot map to get list of telemetry benchmarks to run.
       total_shards = None
       shard_index = None
-
+      shard_map_path = os.path.join(SHARD_MAPS_DIRECTORY,
+                                    options.test_shard_map_filename)
       env = os.environ.copy()
       if 'GTEST_TOTAL_SHARDS' in env:
         total_shards = env['GTEST_TOTAL_SHARDS']
       if 'GTEST_SHARD_INDEX' in env:
         shard_index = env['GTEST_SHARD_INDEX']
-
-      if not (total_shards or shard_index):
-        raise Exception('Shard indicators must be present for perf tests')
-
-      sharding_map_path = get_sharding_map_path(args)
-
-      # Copy sharding map file to isolated_out_dir so that the collect script
+      if not total_shards or not shard_index:
+        raise Exception(
+            'Sharded Telemetry perf tests must either specify --benchmarks '
+            'list or have shard indicator environment variables present.')
+      # Copy sharding map file to isolated_out_dir so that the merge script
       # can collect it later.
+      # TODO(crouleau): Move this step over to merge script
+      # (process_perf_results.py).
       shutil.copyfile(
-          sharding_map_path,
+          shard_map_path,
           os.path.join(isolated_out_dir, 'benchmarks_shard_map.json'))
+      with open(shard_map_path) as f:
+        shard_map = json.load(f)
+      benchmarks_and_stories = shard_map[shard_index]['benchmarks']
 
-      with open(sharding_map_path) as f:
-        sharding_map = json.load(f)
-      sharding = sharding_map[shard_index]['benchmarks']
-
-      for benchmark, stories in sharding.iteritems():
-        # Need to run the benchmark twice on browser and reference build
-        return_code = (execute_telemetry_benchmark(
-            benchmark, isolated_out_dir, args, rest_args,
-            False, stories=stories) or return_code)
-        # We ignore the return code of the reference build since we do not
-        # monitor it.
-        if args.run_ref_build:
+      for benchmark, stories in benchmarks_and_stories.iteritems():
+        # Need to run the benchmark on both latest browser and reference build.
+        output_paths = OutputFilePaths(isolated_out_dir, benchmark).SetUp()
+        command_generator = TelemetryCommandGenerator(
+            benchmark, options, stories=stories)
+        return_code = execute_telemetry_benchmark(
+            command_generator, output_paths, options.xvfb)
+        overall_return_code = return_code or overall_return_code
+        if options.run_ref_build:
+          reference_benchmark_foldername = benchmark + '.reference'
+          reference_output_paths = OutputFilePaths(
+              isolated_out_dir, reference_benchmark_foldername).SetUp()
+          reference_command_generator = TelemetryCommandGenerator(
+              benchmark, options,
+              stories=stories, is_reference=True)
+          # We intentionally ignore the return code of the reference build.
           execute_telemetry_benchmark(
-              benchmark, isolated_out_dir, args, rest_args, True,
-              stories=stories)
+              reference_command_generator, reference_output_paths,
+              options.xvfb)
+    else:
+      raise Exception('Telemetry tests must provide either a shard map or a '
+                      '--benchmarks list so that we know which stories to run.')
 
-  return return_code
+  return overall_return_code
 
 
 # This is not really a "script test" so does not need to manually add
diff --git a/testing/test.gni b/testing/test.gni
index a7dd581..eac0fdd 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -353,6 +353,9 @@
         data = []
       }
 
+      # We use a special trigger script for CrOS hardware tests.
+      data += [ "//testing/trigger_scripts/chromeos_device_trigger.py" ]
+
       testonly = true
       output_name = target_name
       write_runtime_deps = _runtime_deps_file
diff --git a/testing/trigger_scripts/chromeos_device_trigger.py b/testing/trigger_scripts/chromeos_device_trigger.py
index 61ce229..7ac28fa2 100755
--- a/testing/trigger_scripts/chromeos_device_trigger.py
+++ b/testing/trigger_scripts/chromeos_device_trigger.py
@@ -101,8 +101,17 @@
   # Insert our modified dimension args in between the 1st and 2nd args of the
   # initial `swarming.py` invocation. This avoids the presence of the special
   # `--` arg from causing swarming.py to ignore them.
+  needs_device_status = True
   for k, v in args.dimensions:
     new_args.extend(['--dimension', k, v])
+    if k == 'device_status':
+      needs_device_status = False
+
+  # Only CrOS device bots with a device_status dimension of "available" should
+  # run tests. So target those explicitly if we aren't already.
+  if needs_device_status:
+    new_args.extend(['--dimension', 'device_status', 'available'])
+
   new_args.extend([
       '--optional-dimension',
       'device_os',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b43c5eb..59d8a06 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -778,6 +778,7 @@
             "platforms": [
                 "android",
                 "chromeos",
+                "ios",
                 "linux",
                 "mac",
                 "windows"
@@ -1828,7 +1829,7 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled",
+                    "name": "Enabled_20190215",
                     "enable_features": [
                         "ExploreSites"
                     ]
@@ -4517,7 +4518,7 @@
             ]
         }
     ],
-    "SimpleCachePrefetchExperiment": [
+    "SimpleCachePrefetchExperiment2": [
         {
             "platforms": [
                 "android",
@@ -4526,7 +4527,7 @@
             ],
             "experiments": [
                 {
-                    "name": "PrefetchTrailerHint2",
+                    "name": "PrefetchTrailerHint0",
                     "params": {
                         "FullPrefetchBytes": "0",
                         "TrailerPrefetchHint": "true"
diff --git a/third_party/androidx/BUILD.gn b/third_party/androidx/BUILD.gn
index f4b6be0c..c4c92f381 100644
--- a/third_party/androidx/BUILD.gn
+++ b/third_party/androidx/BUILD.gn
@@ -5,22 +5,42 @@
 import("//build/config/android/rules.gni")
 
 android_aar_prebuilt("androidx_core_java") {
-  # If this is not test only, there are security implecations.
+  # If this is not test only, there are security implications.
   # Any changes from test only will need a review from security@chromium.org.
   testonly = true
   aar_path = "lib/core-1.0.0.aar"
+  deps = [
+    ":androidx_monitor_java",
+    ":lifecycle-common-2.0.0_java",
+  ]
 }
 
 android_aar_prebuilt("androidx_junit_java") {
-  # If this is not test only, there are security implecations.
+  # If this is not test only, there are security implications.
   # Any changes from test only will need a review from security@chromium.org.
   testonly = true
   aar_path = "lib/junit-1.0.0.aar"
+  deps = [
+    "//third_party/junit:junit",
+  ]
 }
 
 android_aar_prebuilt("androidx_monitor_java") {
-  # If this is not test only, there are security implecations.
+  # If this is not test only, there are security implications.
   # Any changes from test only will need a review from security@chromium.org.
   testonly = true
   aar_path = "lib/monitor-1.1.0.aar"
 }
+
+android_java_prebuilt("annotation-1.0.0_java") {
+  testonly = true
+  jar_path = "lib/annotation-1.0.0.jar"
+}
+
+android_java_prebuilt("lifecycle-common-2.0.0_java") {
+  testonly = true
+  jar_path = "lib/lifecycle-common-2.0.0.jar"
+  deps = [
+    ":annotation-1.0.0_java",
+  ]
+}
diff --git a/third_party/androidx/OWNERS b/third_party/androidx/OWNERS
index ccaab5d..6ad440ed 100644
--- a/third_party/androidx/OWNERS
+++ b/third_party/androidx/OWNERS
@@ -1,3 +1,4 @@
+jbudorick@chromium.org
 bjoyce@chromium.org
 yliuyliu@chromium.org
 yzjr@chromium.org
diff --git a/third_party/androidx/cipd.yaml b/third_party/androidx/cipd.yaml
index ee5f9ac..3d2c3af 100644
--- a/third_party/androidx/cipd.yaml
+++ b/third_party/androidx/cipd.yaml
@@ -10,3 +10,5 @@
   - file: lib/core-1.0.0.aar
   - file: lib/junit-1.0.0.aar
   - file: lib/monitor-1.1.0.aar
+  - file: lib/annotation-1.0.0.jar
+  - file: lib/lifecycle-common-2.0.0.jar
diff --git a/third_party/blink/common/origin_policy/origin_policy_parser.cc b/third_party/blink/common/origin_policy/origin_policy_parser.cc
index df42efe..8c03c232 100644
--- a/third_party/blink/common/origin_policy/origin_policy_parser.cc
+++ b/third_party/blink/common/origin_policy/origin_policy_parser.cc
@@ -28,7 +28,8 @@
   if (policy_text.empty())
     return false;
 
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(policy_text);
+  std::unique_ptr<base::Value> json =
+      base::JSONReader::ReadDeprecated(policy_text);
   if (!json || !json->is_dict())
     return false;
 
diff --git a/third_party/blink/common/origin_trials/trial_token.cc b/third_party/blink/common/origin_trials/trial_token.cc
index 44be9a6a..5680f9f 100644
--- a/third_party/blink/common/origin_trials/trial_token.cc
+++ b/third_party/blink/common/origin_trials/trial_token.cc
@@ -168,8 +168,8 @@
     return nullptr;
   }
 
-  std::unique_ptr<base::DictionaryValue> datadict =
-      base::DictionaryValue::From(base::JSONReader::Read(token_payload));
+  std::unique_ptr<base::DictionaryValue> datadict = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(token_payload));
   if (!datadict) {
     return nullptr;
   }
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index e068fe33..a10f589 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -641,7 +641,6 @@
       [ "//third_party/blink/renderer/platform:blink_platform_public_deps" ]
   sources = [
     "platform/autoplay.mojom",
-    "platform/media_download_in_product_help.mojom",
     "platform/mime_registry.mojom",
     "platform/modules/app_banner/app_banner.mojom",
     "platform/modules/background_sync/background_sync.mojom",
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index de3e820..28387e2 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -88,7 +88,6 @@
     "origin_trials/trial_token.h",
     "origin_trials/trial_token_validator.h",
     "page/launching_process_state.h",
-    "picture_in_picture/picture_in_picture_control_info.h",
     "privacy_preferences.h",
     "screen_orientation/web_screen_orientation_lock_type.h",
     "screen_orientation/web_screen_orientation_type.h",
diff --git a/third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h b/third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h
deleted file mode 100644
index e27a29e..0000000
--- a/third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h
+++ /dev/null
@@ -1,38 +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.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_CONTROL_INFO_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_CONTROL_INFO_H_
-
-#include <string>
-#include <vector>
-#include "ui/gfx/geometry/size.h"
-#include "url/gurl.h"
-
-namespace blink {
-
-// PictureInPictureControlInfo passes information about the desired custom
-// controls for a Picture-in-Picture window from the Web API to the
-// OverlayWindow.
-struct PictureInPictureControlInfo {
-  // These vectors represent the members of a deserialized MediaImage.
-  struct Icon {
-    GURL src;
-    std::vector<gfx::Size> sizes;
-    std::string type;
-  };
-
-  // |id| is the unique name of the custom control.
-  std::string id;
-
-  // |label| is the descriptive text used for accessibility and hover text.
-  std::string label;
-
-  // |icons| contains the images used for the custom control.
-  std::vector<Icon> icons;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_CONTROL_INFO_H_
diff --git a/third_party/blink/public/platform/media_download_in_product_help.mojom b/third_party/blink/public/platform/media_download_in_product_help.mojom
deleted file mode 100644
index 84cf04e..0000000
--- a/third_party/blink/public/platform/media_download_in_product_help.mojom
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module blink.mojom;
-
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// Browser-side service used by the renderer for showing the InProductHelp UI
-// widget/popup for the media download button.
-interface MediaDownloadInProductHelp {
-  // The position of the button in the frame's local coordinate space, where the
-  // UI widget should be anchored.
-  // The request_id denotes the element making the request.
-  ShowInProductHelpWidget(gfx.mojom.Rect button_rect);
-};
\ No newline at end of file
diff --git a/third_party/blink/public/platform/scheduler/web_rail_mode_observer.h b/third_party/blink/public/platform/scheduler/web_rail_mode_observer.h
index 8768f40..0e2012f9 100644
--- a/third_party/blink/public/platform/scheduler/web_rail_mode_observer.h
+++ b/third_party/blink/public/platform/scheduler/web_rail_mode_observer.h
@@ -6,7 +6,10 @@
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_SCHEDULER_WEB_RAIL_MODE_OBSERVER_H_
 
 #include "third_party/blink/public/platform/web_common.h"
-#include "v8/include/v8.h"
+
+namespace v8 {
+enum RAILMode : unsigned;
+}
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/public/platform/scheduler/web_thread_scheduler.h b/third_party/blink/public/platform/scheduler/web_thread_scheduler.h
index 77378f8..7043dd4 100644
--- a/third_party/blink/public/platform/scheduler/web_thread_scheduler.h
+++ b/third_party/blink/public/platform/scheduler/web_thread_scheduler.h
@@ -18,7 +18,6 @@
 #include "third_party/blink/public/platform/web_input_event.h"
 #include "third_party/blink/public/platform/web_input_event_result.h"
 #include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
-#include "v8/include/v8.h"
 
 namespace base {
 namespace trace_event {
diff --git a/third_party/blink/public/platform/web_keyboard_event.h b/third_party/blink/public/platform/web_keyboard_event.h
index 93b7d8c..4518dc7d 100644
--- a/third_party/blink/public/platform/web_keyboard_event.h
+++ b/third_party/blink/public/platform/web_keyboard_event.h
@@ -21,31 +21,31 @@
   static const size_t kTextLengthCap = 4;
 
   // |windows_key_code| is the Windows key code associated with this key
-  // event.  Sometimes it's direct from the event (i.e. on Windows),
-  // sometimes it's via a mapping function.  If you want a list, see
-  // WebCore/platform/chromium/KeyboardCodes* . Note that this should
+  // event. Sometimes it's direct from the event (i.e. on Windows),
+  // sometimes it's via a mapping function. If you want a list, see
+  // ui/events/keycodes/keyboard_codes_* . Note that this should
   // ALWAYS store the non-locational version of a keycode as this is
   // what is returned by the Windows API. For example, it should
   // store VK_SHIFT instead of VK_RSHIFT. The location information
   // should be stored in |modifiers|.
   int windows_key_code;
 
-  // The actual key code genenerated by the platform.  The DOM spec runs
+  // The actual key code genenerated by the platform. The DOM spec runs
   // on Windows-equivalent codes (thus |windows_key_code| above) but it
   // doesn't hurt to have this one around.
   int native_key_code;
 
-  // The DOM code enum of the key pressed as passed by the embedder. DOM
-  // code enum are defined in ui/events/keycodes/dom4/keycode_converter_data.h.
+  // The DOM code enum of the key pressed as passed by the embedder. DOM code
+  // enums are defined in ui/events/keycodes/dom/keycode_converter_data.inc.
   int dom_code;
 
   // The DOM key enum of the key pressed as passed by the embedder. DOM
-  // key enum are defined in ui/events/keycodes/dom3/dom_key_data.h
+  // key enums are defined in ui/events/keycodes/dom/dom_key_data.inc.
   int dom_key;
 
-  // This identifies whether this event was tagged by the system as being
-  // a "system key" event (see
-  // http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx for
+  // This identifies whether this event was tagged by the system as being a
+  // "system key" event (see
+  // https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-syskeydown for
   // details). Other platforms don't have this concept, but it's just
   // easier to leave it always false than ifdef.
   bool is_system_key;
diff --git a/third_party/blink/public/platform/web_media_player.h b/third_party/blink/public/platform/web_media_player.h
index 820549f..fbbd030 100644
--- a/third_party/blink/public/platform/web_media_player.h
+++ b/third_party/blink/public/platform/web_media_player.h
@@ -62,7 +62,6 @@
 enum class WebFullscreenVideoStatus;
 struct WebRect;
 struct WebSize;
-struct PictureInPictureControlInfo;
 
 class WebMediaPlayer {
  public:
@@ -154,9 +153,6 @@
   // method should make sure the player is set up for this and has a SurfaceId
   // as it will be needed.
   virtual void OnRequestPictureInPicture() = 0;
-  // Assign custom controls to the Picture-in-Picture window.
-  virtual void SetPictureInPictureCustomControls(
-      const std::vector<PictureInPictureControlInfo>&) = 0;
 
   virtual void RequestRemotePlayback() {}
   virtual void RequestRemotePlaybackControl() {}
diff --git a/third_party/blink/public/platform/web_media_player_client.h b/third_party/blink/public/platform/web_media_player_client.h
index 571e6da4..5a34acc 100644
--- a/third_party/blink/public/platform/web_media_player_client.h
+++ b/third_party/blink/public/platform/web_media_player_client.h
@@ -127,11 +127,6 @@
   // Informs that Picture-in-Picture mode has stopped for the media element.
   virtual void PictureInPictureStopped() = 0;
 
-  // Informs that a custom Picture-in-Picture control was clicked for the media
-  // element. |control_id| is the identifier for its custom control. This is
-  // defined by the site that calls the web API.
-  virtual void PictureInPictureControlClicked(const WebString& control_id) = 0;
-
   // Returns whether the media element has native controls. It does not mean
   // that the controls are currently visible.
   virtual bool HasNativeControls() = 0;
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h
index 11dfe26..b28241e 100644
--- a/third_party/blink/public/web/web_settings.h
+++ b/third_party/blink/public/web/web_settings.h
@@ -273,7 +273,6 @@
   virtual void SetXSSAuditorEnabled(bool) = 0;
   virtual void SetMediaControlsEnabled(bool) = 0;
   virtual void SetDoNotUpdateSelectionOnMutatingSelectionRange(bool) = 0;
-  virtual void SetMediaDownloadInProductHelpEnabled(bool) = 0;
   virtual void SetLowPriorityIframesThreshold(WebEffectiveConnectionType) = 0;
   virtual void SetLazyLoadEnabled(bool) = 0;
   virtual void SetLazyFrameLoadingDistanceThresholdPxUnknown(int) = 0;
diff --git a/third_party/blink/renderer/bindings/core/v8/BUILD.gn b/third_party/blink/renderer/bindings/core/v8/BUILD.gn
index a339271..3c65fc5c 100644
--- a/third_party/blink/renderer/bindings/core/v8/BUILD.gn
+++ b/third_party/blink/renderer/bindings/core/v8/BUILD.gn
@@ -160,6 +160,8 @@
   "$bindings_core_v8_output_dir/v8_idle_request_callback.h",
   "$bindings_core_v8_output_dir/v8_intersection_observer_callback.cc",
   "$bindings_core_v8_output_dir/v8_intersection_observer_callback.h",
+  "$bindings_core_v8_output_dir/v8_layout_callback.cc",
+  "$bindings_core_v8_output_dir/v8_layout_callback.h",
   "$bindings_core_v8_output_dir/v8_mojo_watch_callback.cc",
   "$bindings_core_v8_output_dir/v8_mojo_watch_callback.h",
   "$bindings_core_v8_output_dir/v8_mutation_callback.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/script_module_test.cc b/third_party/blink/renderer/bindings/core/v8/script_module_test.cc
index 3418dcf1..d07b2dba 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_module_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_module_test.cc
@@ -35,9 +35,9 @@
  private:
   // Implements ScriptModuleResolver:
 
-  void RegisterModuleScript(ModuleScript*) override { NOTREACHED(); }
-  void UnregisterModuleScript(ModuleScript*) override { NOTREACHED(); }
-  ModuleScript* GetHostDefined(const ScriptModule&) const override {
+  void RegisterModuleScript(const ModuleScript*) override { NOTREACHED(); }
+  void UnregisterModuleScript(const ModuleScript*) override { NOTREACHED(); }
+  const ModuleScript* GetHostDefined(const ScriptModule&) const override {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
index 84209a8..3e56600f 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
@@ -45,7 +45,7 @@
 }
 
 // Check previously stored timestamp.
-bool IsResourceHotForCaching(SingleCachedMetadataHandler* cache_handler,
+bool IsResourceHotForCaching(const SingleCachedMetadataHandler* cache_handler,
                              int hot_hours) {
   const double hot_seconds = hot_hours * 60 * 60;
   scoped_refptr<CachedMetadata> cached_metadata =
@@ -62,7 +62,8 @@
 
 }  // namespace
 
-bool V8CodeCache::HasCodeCache(SingleCachedMetadataHandler* cache_handler) {
+bool V8CodeCache::HasCodeCache(
+    const SingleCachedMetadataHandler* cache_handler) {
   if (!cache_handler)
     return false;
 
@@ -71,7 +72,7 @@
 }
 
 v8::ScriptCompiler::CachedData* V8CodeCache::CreateCachedData(
-    SingleCachedMetadataHandler* cache_handler) {
+    const SingleCachedMetadataHandler* cache_handler) {
   DCHECK(cache_handler);
   uint32_t code_cache_tag = V8CodeCache::TagForCodeCache(cache_handler);
   scoped_refptr<CachedMetadata> cached_metadata =
@@ -238,12 +239,12 @@
 }
 
 uint32_t V8CodeCache::TagForCodeCache(
-    SingleCachedMetadataHandler* cache_handler) {
+    const SingleCachedMetadataHandler* cache_handler) {
   return CacheTag(kCacheTagCode, cache_handler->Encoding());
 }
 
 uint32_t V8CodeCache::TagForTimeStamp(
-    SingleCachedMetadataHandler* cache_handler) {
+    const SingleCachedMetadataHandler* cache_handler) {
   return CacheTag(kCacheTagTimeStamp, cache_handler->Encoding());
 }
 
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.h b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.h
index ddeaef8..af95798 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.h
@@ -40,14 +40,13 @@
     kProduceCodeCache,
   };
 
-  static uint32_t TagForParserCache(SingleCachedMetadataHandler*);
-  static uint32_t TagForCodeCache(SingleCachedMetadataHandler*);
-  static uint32_t TagForTimeStamp(SingleCachedMetadataHandler*);
+  static uint32_t TagForCodeCache(const SingleCachedMetadataHandler*);
+  static uint32_t TagForTimeStamp(const SingleCachedMetadataHandler*);
   static void SetCacheTimeStamp(SingleCachedMetadataHandler*);
 
   // Returns true iff the SingleCachedMetadataHandler contains a code cache
   // that can be consumed by V8.
-  static bool HasCodeCache(SingleCachedMetadataHandler*);
+  static bool HasCodeCache(const SingleCachedMetadataHandler*);
 
   static std::tuple<v8::ScriptCompiler::CompileOptions,
                     ProduceCacheOptions,
@@ -55,7 +54,7 @@
   GetCompileOptions(V8CacheOptions, const ScriptSourceCode&);
 
   static v8::ScriptCompiler::CachedData* CreateCachedData(
-      SingleCachedMetadataHandler*);
+      const SingleCachedMetadataHandler*);
 
   static void ProduceCache(v8::Isolate*,
                            v8::Local<v8::Script>,
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc b/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc
index e16d33a..15fcda9a 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc
@@ -109,7 +109,7 @@
 
 bool V8ObjectParser::ParseCSSPropertyList(
     v8::Local<v8::Context> context,
-    v8::Local<v8::Function> constructor,
+    v8::Local<v8::Object> constructor,
     const AtomicString list_name,
     Vector<CSSPropertyID>* native_properties,
     Vector<AtomicString>* custom_properties,
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_object_parser.h b/third_party/blink/renderer/bindings/core/v8/v8_object_parser.h
index 2aa5cd1..5e7c589 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_object_parser.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_object_parser.h
@@ -47,7 +47,7 @@
   // Vector<String> type. It does not fail if the list contains invalid CSS
   // properties, to ensure forward compatibility.
   static bool ParseCSSPropertyList(v8::Local<v8::Context>,
-                                   v8::Local<v8::Function> constructor,
+                                   v8::Local<v8::Object> constructor,
                                    const AtomicString list_name,
                                    Vector<CSSPropertyID>* native_properties,
                                    Vector<AtomicString>* custom_properties,
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 3fbe7a8..107f8ae 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -352,7 +352,6 @@
     "events/mutation_event.idl",
     "events/overscroll_event.idl",
     "events/page_transition_event.idl",
-    "events/picture_in_picture_control_event.idl",
     "events/pointer_event.idl",
     "events/pop_state_event.idl",
     "events/progress_event.idl",
@@ -1973,6 +1972,7 @@
     "html/parser/html_document_parser_test.cc",
     "html/parser/html_entity_parser_test.cc",
     "html/parser/html_parser_idioms_test.cc",
+    "html/parser/html_preload_scanner_document_test.cc",
     "html/parser/html_preload_scanner_test.cc",
     "html/parser/html_resource_preloader_test.cc",
     "html/parser/html_srcset_parser_test.cc",
@@ -2235,6 +2235,7 @@
     "workers/worker_thread_test_helper.h",
     "workers/worklet_module_responses_map_test.cc",
     "xml/parser/shared_buffer_reader_test.cc",
+    "xml/parser/xml_document_parser_test.cc",
     "xml/xpath_functions_test.cc",
   ]
 
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index 33b5a2f..791eeb8 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -161,7 +161,6 @@
                     "events/mutation_event.idl",
                     "events/overscroll_event.idl",
                     "events/page_transition_event.idl",
-                    "events/picture_in_picture_control_event.idl",
                     "events/pointer_event.idl",
                     "events/pop_state_event.idl",
                     "events/portal_activate_event.idl",
@@ -636,7 +635,6 @@
                     "events/mouse_event_init.idl",
                     "events/overscroll_event_init.idl",
                     "events/page_transition_event_init.idl",
-                    "events/picture_in_picture_control_event_init.idl",
                     "events/pointer_event_init.idl",
                     "events/pop_state_event_init.idl",
                     "events/progress_event_init.idl",
diff --git a/third_party/blink/renderer/core/css/font_face_set_document.h b/third_party/blink/renderer/core/css/font_face_set_document.h
index f6b2a63..7d3e4ee 100644
--- a/third_party/blink/renderer/core/css/font_face_set_document.h
+++ b/third_party/blink/renderer/core/css/font_face_set_document.h
@@ -36,7 +36,6 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
diff --git a/third_party/blink/renderer/core/css/font_face_set_worker.h b/third_party/blink/renderer/core/css/font_face_set_worker.h
index bf397c4..645f11a1 100644
--- a/third_party/blink/renderer/core/css/font_face_set_worker.h
+++ b/third_party/blink/renderer/core/css/font_face_set_worker.h
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/core/css/font_face_set.h"
 #include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 2aea99fa..a51bfea 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3312,8 +3312,7 @@
   // This is the way to make it possible to navigate to (focus) elements
   // which web designer meant for being active (made them respond to click
   // events).
-  if (!IsSpatialNavigationEnabled(GetDocument().GetFrame()) ||
-      SpatialNavigationIgnoresEventHandlers(GetDocument().GetFrame()))
+  if (!IsSpatialNavigationEnabled(GetDocument().GetFrame()))
     return false;
   if (HasEventListeners(event_type_names::kClick) ||
       HasEventListeners(event_type_names::kKeydown) ||
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index 525cb36..2efc1db 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -34,12 +34,7 @@
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/editing/iterators/backwards_character_iterator.h"
-#include "third_party/blink/renderer/core/editing/iterators/backwards_text_buffer.h"
 #include "third_party/blink/renderer/core/editing/iterators/character_iterator.h"
-#include "third_party/blink/renderer/core/editing/iterators/forwards_text_buffer.h"
-#include "third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator.h"
-#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
 #include "third_party/blink/renderer/core/editing/local_caret_rect.h"
 #include "third_party/blink/renderer/core/editing/position.h"
 #include "third_party/blink/renderer/core/editing/position_iterator.h"
diff --git a/third_party/blink/renderer/core/events/BUILD.gn b/third_party/blink/renderer/core/events/BUILD.gn
index b6f51c73..c831eb37 100644
--- a/third_party/blink/renderer/core/events/BUILD.gn
+++ b/third_party/blink/renderer/core/events/BUILD.gn
@@ -52,8 +52,6 @@
     "overscroll_event.h",
     "page_transition_event.cc",
     "page_transition_event.h",
-    "picture_in_picture_control_event.cc",
-    "picture_in_picture_control_event.h",
     "pointer_event.cc",
     "pointer_event.h",
     "pointer_event_factory.cc",
diff --git a/third_party/blink/renderer/core/events/event_type_names.json5 b/third_party/blink/renderer/core/events/event_type_names.json5
index df904c6..c618805 100644
--- a/third_party/blink/renderer/core/events/event_type_names.json5
+++ b/third_party/blink/renderer/core/events/event_type_names.json5
@@ -202,7 +202,6 @@
     "paymentmethodchange",
     "paymentrequest",
     "periodicsync",
-    "pictureinpicturecontrolclick",
     "play",
     "playing",
     "pointercancel",
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event.cc b/third_party/blink/renderer/core/events/picture_in_picture_control_event.cc
deleted file mode 100644
index 17e4158..0000000
--- a/third_party/blink/renderer/core/events/picture_in_picture_control_event.cc
+++ /dev/null
@@ -1,38 +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.
-
-#include "third_party/blink/renderer/core/events/picture_in_picture_control_event.h"
-
-namespace blink {
-
-PictureInPictureControlEvent* PictureInPictureControlEvent::Create(
-    const AtomicString& type,
-    String id) {
-  return MakeGarbageCollected<PictureInPictureControlEvent>(type, id);
-}
-
-PictureInPictureControlEvent* PictureInPictureControlEvent::Create(
-    const AtomicString& type,
-    const PictureInPictureControlEventInit* initializer) {
-  return MakeGarbageCollected<PictureInPictureControlEvent>(type, initializer);
-}
-
-String PictureInPictureControlEvent::id() const {
-  return id_;
-}
-void PictureInPictureControlEvent::setId(String id) {
-  id_ = id;
-}
-
-PictureInPictureControlEvent::PictureInPictureControlEvent(
-    AtomicString const& type,
-    String id)
-    : Event(type, Bubbles::kYes, Cancelable::kNo), id_(id) {}
-
-PictureInPictureControlEvent::PictureInPictureControlEvent(
-    AtomicString const& type,
-    const PictureInPictureControlEventInit* initializer)
-    : Event(type, initializer), id_(initializer->id()) {}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event.h b/third_party/blink/renderer/core/events/picture_in_picture_control_event.h
deleted file mode 100644
index 718b80317..0000000
--- a/third_party/blink/renderer/core/events/picture_in_picture_control_event.h
+++ /dev/null
@@ -1,40 +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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PICTURE_IN_PICTURE_CONTROL_EVENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PICTURE_IN_PICTURE_CONTROL_EVENT_H_
-
-#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/events/picture_in_picture_control_event_init.h"
-
-namespace blink {
-
-// A PictureInPictureControlEvent is a subclass of Event with an additional
-// string. This string is used to convey to the browser the name of a custom
-// control on a Picture in Picture window.
-class CORE_EXPORT PictureInPictureControlEvent final : public Event {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static PictureInPictureControlEvent* Create(const AtomicString&, String);
-  static PictureInPictureControlEvent* Create(
-      const AtomicString&,
-      const PictureInPictureControlEventInit*);
-
-  PictureInPictureControlEvent(AtomicString const&, String);
-  PictureInPictureControlEvent(AtomicString const&,
-                               const PictureInPictureControlEventInit*);
-
-  String id() const;
-  void setId(String id);
-
- private:
-  // id_ holds the id of a PictureIncPictureControlEvent, which is used to
-  // convey which custom control fired the event by being clicked.
-  String id_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PICTURE_IN_PICTURE_CONTROL_EVENT_H_
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event.idl b/third_party/blink/renderer/core/events/picture_in_picture_control_event.idl
deleted file mode 100644
index 550f1e6..0000000
--- a/third_party/blink/renderer/core/events/picture_in_picture_control_event.idl
+++ /dev/null
@@ -1,11 +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.
-
-[
-    RuntimeEnabled=PictureInPictureControl,
-    Constructor(DOMString type, PictureInPictureControlEventInit eventInitDict)
-]
-interface PictureInPictureControlEvent : Event {
-    attribute DOMString id;
-};
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event_init.idl b/third_party/blink/renderer/core/events/picture_in_picture_control_event_init.idl
deleted file mode 100644
index a34e0a4..0000000
--- a/third_party/blink/renderer/core/events/picture_in_picture_control_event_init.idl
+++ /dev/null
@@ -1,7 +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.
-
-dictionary PictureInPictureControlEventInit : EventInit {
-    required DOMString id;
-};
\ No newline at end of file
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 be8728b..e313073e 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
@@ -77,9 +77,7 @@
     return MakeGarbageCollected<PagePopupChromeClient>(popup);
   }
 
-  explicit PagePopupChromeClient(WebPagePopupImpl* popup) : popup_(popup) {
-    DCHECK(popup_->WidgetClient());
-  }
+  explicit PagePopupChromeClient(WebPagePopupImpl* popup) : popup_(popup) {}
 
   void SetWindowRect(const IntRect& rect, LocalFrame&) override {
     popup_->SetWindowRect(rect);
@@ -88,7 +86,11 @@
   bool IsPopup() override { return true; }
 
  private:
-  void CloseWindowSoon() override { popup_->ClosePopup(); }
+  void CloseWindowSoon() override {
+    // This skips past the PopupClient by calling ClosePopup() instead of
+    // Cancel().
+    popup_->ClosePopup();
+  }
 
   IntRect RootWindowRect(LocalFrame&) override {
     // There is only one frame/widget in a WebPagePopup, so we can ignore the
@@ -278,8 +280,6 @@
   page_->GetSettings().SetAcceleratedCompositingEnabled(true);
   page_->GetSettings().SetScriptEnabled(true);
   page_->GetSettings().SetAllowScriptsToCloseWindows(true);
-  page_->GetSettings().SetDeviceSupportsTouch(
-      main_settings.GetDeviceSupportsTouch());
   page_->GetSettings().SetMinimumFontSize(main_settings.GetMinimumFontSize());
   page_->GetSettings().SetMinimumLogicalFontSize(
       main_settings.GetMinimumLogicalFontSize());
@@ -337,9 +337,7 @@
 }
 
 void WebPagePopupImpl::DestroyPage() {
-  if (!page_)
-    return;
-
+  page_->WillCloseLayerTreeView(*layer_tree_view_, nullptr);
   page_->WillBeDestroyed();
   page_.Clear();
 }
@@ -402,9 +400,8 @@
 
 void WebPagePopupImpl::PaintContent(cc::PaintCanvas* canvas,
                                     const WebRect& rect) {
-  if (!closing_) {
+  if (!closing_)
     PageWidgetDelegate::PaintContent(canvas, rect, MainFrame());
-  }
 }
 
 void WebPagePopupImpl::Resize(const WebSize& new_size_in_viewport) {
@@ -517,45 +514,71 @@
 }
 
 void WebPagePopupImpl::Close() {
-  // TODO(danakj): |layer_tree_view_| should never be null here.
-  if (page_ && layer_tree_view_)
-    page_->WillCloseLayerTreeView(*layer_tree_view_, nullptr);
+  // If the popup is closed from the renderer via Cancel(), then ClosePopup()
+  // has already run on another stack, and destroyed |page_|. If the popup is
+  // closed from the browser via IPC to RenderWidget, then we come here first
+  // and want to synchronously Cancel() immediately.
+  if (page_) {
+    // We set |closing_| here to inform ClosePopup() that it is being run
+    // synchronously from inside Close().
+    closing_ = true;
+    // This should end up running ClosePopup() though the PopupClient.
+    Cancel();
+  }
 
   is_accelerated_compositing_active_ = false;
   layer_tree_view_ = nullptr;
   animation_host_ = nullptr;
-
-  closing_ = true;
-  // In case closePopup() was not called.
-  if (page_)
-    Cancel();
   widget_client_ = nullptr;
+
+  // Self-delete on Close().
   Release();
 }
 
 void WebPagePopupImpl::ClosePopup() {
+  // There's always a |page_| when we get here because if we Close() this object
+  // due to CloseWidgetSoon(), it will see the |page_| destroyed and not run
+  // this method again. And the renderer does not close the same popup more than
+  // once.
+  DCHECK(page_);
+
+  // If the popup is closed from the renderer via Cancel(), then we want to
+  // initiate closing immediately here, but send a request for completing the
+  // close process through the browser via CloseWidgetSoon(), which will close
+  // the RenderWidget and come back to this class to Close().
+  // If |closing_| is already true, then the browser initiated the close on its
+  // own, via IPC to the RenderWidget, which means ClosePopup() is being run
+  // inside the same stack, and does not need to request the browser to close
+  // the RenderWidget.
+  const bool running_inside_close = closing_;
+  if (!running_inside_close) {
+    // Bounce through the browser to get it to close the RenderWidget, which
+    // will Close() this object too. Only if we're not currently already
+    // responding to the browser closing us though.
+    widget_client_->CloseWidgetSoon();
+  }
+
+  closing_ = true;
+
   {
     // This function can be called in EventDispatchForbiddenScope for the main
     // document, and the following operations dispatch some events.  It's safe
     // because web authors can't listen the events.
     EventDispatchForbiddenScope::AllowUserAgentEvents allow_events;
 
-    if (page_) {
-      MainFrame().Loader().StopAllLoaders();
-      PagePopupSupplement::Uninstall(MainFrame());
-    }
-    bool close_already_called = closing_;
-    closing_ = true;
-
+    MainFrame().Loader().StopAllLoaders();
+    PagePopupSupplement::Uninstall(MainFrame());
     DestroyPage();
-
-    // |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();
-    }
   }
+
+  // Informs the client to drop any references to this popup as it will be
+  // destroyed.
   popup_client_->DidClosePopup();
+
+  // Drops the reference to the popup from WebViewImpl, making |this| the only
+  // owner of itself. Note however that WebViewImpl may briefly extend the
+  // lifetime of this object since it owns a reference, but it should only be
+  // to call HasSamePopupClient().
   web_view_->CleanupPagePopup();
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.h b/third_party/blink/renderer/core/exported/web_page_popup_impl.h
index 815537e..a34e969 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.h
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.h
@@ -59,26 +59,55 @@
 
  public:
   ~WebPagePopupImpl() override;
+
   void Initialize(WebViewImpl*, PagePopupClient*);
+
+  // Cancel informs the PopupClient that it should initiate shutdown of this
+  // popup via ClosePopup(). It is called to indicate the popup was closed due
+  // to a user gesture outside the popup or other such reasons, where a default
+  // cancelled response can be made.
+  //
+  // When the user chooses a value in the popup and thus it is closed, or if the
+  // origin in the DOM disppears, then the Cancel() step would be skipped and go
+  // directly to ClosePopup().
+  void Cancel();
+  // Once ClosePopup() has been called, the WebPagePopupImpl should be disowned
+  // by any clients, and will be reaped when then browser closes its
+  // RenderWidget which closes this object. This will call back to the
+  // PopupClient to say DidClosePopup(), and to the WebViewImpl to cleanup
+  // its reference to the popup.
+  //
+  // Only HasSamePopupClient() may still be called after ClosePopup() runs.
   void ClosePopup();
-  WebWidgetClient* WidgetClient() const { return widget_client_; }
+
+  // Returns whether another WebPagePopupImpl has the same PopupClient as this
+  // instance. May be called after ClosePopup() has run still, in order to
+  // determine if a popup sharing the same client was created immediately after
+  // closing one.
   bool HasSamePopupClient(WebPagePopupImpl* other) {
     return other && popup_client_ == other->popup_client_;
   }
+
+  WebWidgetClient* WidgetClient() const { return widget_client_; }
+
   LocalDOMWindow* Window();
+
+  // WebWidget implementation.
   void CompositeAndReadbackAsync(
       base::OnceCallback<void(const SkBitmap&)> callback) override;
-  WebPoint PositionRelativeToOwner() override;
-  void PostMessageToPopup(const String& message) override;
-  void Cancel();
-
-  // PageWidgetEventHandler functions.
-  WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) override;
-
   WebInputEventResult DispatchBufferedTouchEvents() override;
 
+  // WebPagePopup implementation.
+  WebPoint PositionRelativeToOwner() override;
+
+  // PagePopup implementation.
+  void PostMessageToPopup(const String& message) override;
+
+  // PageWidgetEventHandler implementation.
+  WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) override;
+
  private:
-  // WebWidget functions
+  // WebWidget implementation.
   void SetLayerTreeView(WebLayerTreeView*, cc::AnimationHost*) override;
   void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) final;
   void BeginFrame(base::TimeTicks last_frame_time,
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc
index 37b1913e..8dcd68c9 100644
--- a/third_party/blink/renderer/core/exported/web_settings_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -681,10 +681,6 @@
   settings_->SetDoNotUpdateSelectionOnMutatingSelectionRange(enabled);
 }
 
-void WebSettingsImpl::SetMediaDownloadInProductHelpEnabled(bool enabled) {
-  settings_->SetMediaDownloadInProductHelpEnabled(enabled);
-}
-
 void WebSettingsImpl::SetLowPriorityIframesThreshold(
     WebEffectiveConnectionType effective_connection_type) {
   settings_->SetLowPriorityIframesThreshold(effective_connection_type);
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h
index 783d5e3..aa6503a0 100644
--- a/third_party/blink/renderer/core/exported/web_settings_impl.h
+++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -197,7 +197,6 @@
   void SetXSSAuditorEnabled(bool) override;
   void SetMediaControlsEnabled(bool) override;
   void SetDoNotUpdateSelectionOnMutatingSelectionRange(bool) override;
-  void SetMediaDownloadInProductHelpEnabled(bool) override;
   void SetLowPriorityIframesThreshold(WebEffectiveConnectionType) override;
 
   void SetLazyLoadEnabled(bool) override;
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 86caa260..66748699 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -369,6 +369,13 @@
   // If there is a popup open, close it as the user is clicking on the page
   // (outside of the popup). We also save it so we can prevent a click on an
   // element from immediately reopening the same popup.
+  //
+  // The popup would not be destroyed in this stack normally as it is owned by
+  // closership from the RenderWidget, which is owned by the browser via the
+  // Close IPC. However if a nested message loop were to happen then the browser
+  // close of the RenderWidget and WebPagePopupImpl could feasibly occur inside
+  // this method, so holding a reference here ensures we can use the
+  // |page_popup| even if it is closed.
   scoped_refptr<WebPagePopupImpl> page_popup;
   if (event.button == WebMouseEvent::Button::kLeft) {
     page_popup = page_popup_;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 60d70f5..46a12c4 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -627,7 +627,11 @@
   // Represents whether or not this object should process incoming IME events.
   bool ime_accept_events_ = true;
 
-  // The popup associated with an input/select element.
+  // The popup associated with an input/select element. The popup is owned via
+  // closership (self-owned-but-deleted-via-close) by RenderWidget. We also hold
+  // a reference here because we can extend the lifetime of the popup while
+  // handling input events in order to compare its popup client after it was
+  // closed.
   scoped_refptr<WebPagePopupImpl> page_popup_;
 
   // This stores the last hidden page popup. If a GestureTap attempts to open
diff --git a/third_party/blink/renderer/core/fetch/multipart_parser.h b/third_party/blink/renderer/core/fetch/multipart_parser.h
index 81289ca..8dec658 100644
--- a/third_party/blink/renderer/core/fetch/multipart_parser.h
+++ b/third_party/blink/renderer/core/fetch/multipart_parser.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/network/http_header_map.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -53,6 +54,8 @@
 
  private:
   class Matcher {
+    DISALLOW_NEW();
+
    public:
     Matcher();
     Matcher(const char* data, size_t num_matched_bytes, size_t);
diff --git a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
index 87d82d73..32eb893 100644
--- a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
+++ b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
@@ -13,7 +13,6 @@
 
 class HTMLVideoElement;
 class ScriptPromiseResolver;
-struct PictureInPictureControlInfo;
 
 // PictureInPictureController allows to know if Picture-in-Picture is allowed
 // for a video element in Blink outside of modules/ module. It
@@ -72,17 +71,6 @@
   virtual void RemoveFromAutoPictureInPictureElementsList(
       HTMLVideoElement*) = 0;
 
-  // Should be called when a custom control on a video element in
-  // Picture-in-Picture is clicked. |control_id| is the identifier for its
-  // custom control. This is defined by the site that calls the web API.
-  virtual void OnPictureInPictureControlClicked(
-      const WebString& control_id) = 0;
-
-  // Assign custom controls to be added to the Picture-in-Picture window.
-  virtual void SetPictureInPictureCustomControls(
-      HTMLVideoElement*,
-      const std::vector<PictureInPictureControlInfo>&) = 0;
-
   // Notifies that one of the states used by Picture-in-Picture has changed.
   virtual void OnPictureInPictureStateChange() = 0;
 
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5
index 085700f..b47ca3eb 100644
--- a/third_party/blink/renderer/core/frame/settings.json5
+++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -273,17 +273,6 @@
       initial: false,
     },
 
-    // Limited use by features which behave differently depending on the input
-    // devices available.  For example, the pointer and hover media queries.
-    // Note that we need to be careful when basing behavior or UI on this -
-    // just because a device is present doesn't mean the user cares about it
-    // or uses it (i.e. Chromebook Pixel users generally don't want to give up
-    // screen real estate just because they happen to have a touchscreen).
-    {
-      name: "deviceSupportsTouch",
-      initial: false,
-    },
-
     // This value indicates the number of simultaneous multi-touch points supported
     // by the currently connected screen/digitizer that supports the most points.
     // From Pointer Events spec:
@@ -921,10 +910,6 @@
       invalidate: "Paint",
     },
     {
-      name: "mediaDownloadInProductHelpEnabled",
-      initial: false,
-    },
-    {
       name: "navigatorPlatformOverride",
       type: "String",
     },
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index df21bde..47169c7 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -168,6 +168,7 @@
     NOTREACHED();
     return nullptr;
   }
+  virtual void ProvideBackBufferToResourceProvider() const { NOTREACHED(); }
   virtual int ExternallyAllocatedBufferCountPerPixel() {
     NOTREACHED();
     return 0;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index 4d859af..4a2ea288 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -98,7 +98,7 @@
         CanvasResourceProvider::ResourceUsage usage;
         if (SharedGpuContext::IsGpuCompositingEnabled()) {
           if (LowLatencyEnabled())
-            usage = CanvasResourceProvider::kAcceleratedDirectResourceUsage;
+            usage = CanvasResourceProvider::kAcceleratedDirect3DResourceUsage;
           else
             usage = CanvasResourceProvider::kAcceleratedCompositedResourceUsage;
         } else {
@@ -125,7 +125,7 @@
         CanvasResourceProvider::ResourceUsage usage;
         if (want_acceleration) {
           if (LowLatencyEnabled())
-            usage = CanvasResourceProvider::kAcceleratedDirectResourceUsage;
+            usage = CanvasResourceProvider::kAcceleratedDirect2DResourceUsage;
           else
             usage = CanvasResourceProvider::kAcceleratedCompositedResourceUsage;
         } else {
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 3e6826a..fff9cac 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -429,14 +429,23 @@
 
   if (LowLatencyEnabled() && !dirty_rect_.IsEmpty()) {
     if (GetOrCreateCanvasResourceProvider(kPreferAcceleration)) {
-      ResourceProvider()->TryEnableSingleBuffering();
-      if (canvas2d_bridge_)
+      // TryEnableSingleBuffering() the first time we FinalizeFrame().
+      if (!ResourceProvider()->IsSingleBuffered()) {
+        ResourceProvider()->TryEnableSingleBuffering();
+        if (Is3d() && RuntimeEnabledFeatures::WebGLImageChromiumEnabled())
+          context_->ProvideBackBufferToResourceProvider();
+      }
+
+      if (canvas2d_bridge_) {
         canvas2d_bridge_->FlushRecording();
-      // Push a frame
-      base::TimeTicks start_time = WTF::CurrentTimeTicks();
-      if (Is3d())
-        context_->PaintRenderingResultsToCanvas(kBackBuffer);
-      scoped_refptr<CanvasResource> canvas_resource =
+      } else {
+        DCHECK(Is3d());
+        if (!RuntimeEnabledFeatures::WebGLImageChromiumEnabled())
+          context_->PaintRenderingResultsToCanvas(kBackBuffer);
+      }
+
+      const base::TimeTicks start_time = WTF::CurrentTimeTicks();
+      const scoped_refptr<CanvasResource> canvas_resource =
           ResourceProvider()->ProduceFrame();
       const FloatRect src_rect(0, 0, Size().Width(), Size().Height());
       dirty_rect_.Intersect(src_rect);
@@ -451,13 +460,12 @@
     }
   }
 
-  // If the canvas is visible, notifying listeners is taken
-  // care of in the in doDeferredPaintInvalidation, which allows
-  // the frame to be grabbed prior to compositing, which is
-  // critically important because compositing may clear the canvas's
-  // image. (e.g. WebGL context with preserveDrawingBuffer=false).
-  // If the canvas is not visible, doDeferredPaintInvalidation
-  // will not get called, so we need to take care of business here.
+  // If the canvas is visible, notifying listeners is taken care of in
+  // DoDeferredPaintInvalidation(), which allows the frame to be grabbed prior
+  // to compositing, which is critically important because compositing may clear
+  // the canvas's image. (e.g. WebGL context with preserveDrawingBuffer=false).
+  // If the canvas is not visible, DoDeferredPaintInvalidation will not get
+  // called, so we need to take care of business here.
   if (!did_notify_listeners_for_current_frame_)
     NotifyListenersCanvasChanged();
   did_notify_listeners_for_current_frame_ = false;
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 1693c67e..64a04a6 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -138,10 +138,23 @@
 }
 
 bool HTMLLinkElement::ShouldLoadLink() {
+  // Common case: We should load <link> on document that will be rendered.
+  if (!InActiveDocument()) {
+    // Handle rare cases.
+
+    if (!isConnected())
+      return false;
+
+    // Load:
+    // - <link> tags for stylesheets regardless of its document state
+    //   (TODO: document why this is the case. kouhei@ doesn't know.)
+    // - <link> tags on html import documents.
+    if (!rel_attribute_.IsStyleSheet() && !GetDocument().IsHTMLImport())
+      return false;
+  }
+
   const KURL& href = GetNonEmptyURLAttribute(kHrefAttr);
-  return (IsInDocumentTree() ||
-          (isConnected() && rel_attribute_.IsStyleSheet())) &&
-         !href.PotentiallyDanglingMarkup();
+  return !href.PotentiallyDanglingMarkup();
 }
 
 bool HTMLLinkElement::IsLinkCreatedByParser() {
@@ -175,7 +188,11 @@
 
   if (!link_) {
     if (rel_attribute_.IsImport() &&
-        origin_trials::HTMLImportsEnabled(&GetDocument())) {
+        origin_trials::HTMLImportsEnabled(&GetDocument()) &&
+        // HTMLImportsOnlyChrome lets the document import only chrome resource.
+        (!RuntimeEnabledFeatures::HTMLImportsOnlyChromeEnabled() ||
+         (Href().Protocol() == "chrome" ||
+          Href().Protocol() == "chrome-extension"))) {
       link_ = LinkImport::Create(this);
     } else if (rel_attribute_.IsManifest()) {
       link_ = LinkManifest::Create(this);
diff --git a/third_party/blink/renderer/core/html/media/html_audio_element.h b/third_party/blink/renderer/core/html/media/html_audio_element.h
index b6076b7..7582d03f 100644
--- a/third_party/blink/renderer/core/html/media/html_audio_element.h
+++ b/third_party/blink/renderer/core/html/media/html_audio_element.h
@@ -52,9 +52,6 @@
       const WebString& remote_device_friendly_name) override {}
   void MediaRemotingStopped(WebLocalizedString::Name error_msg) override {}
   void PictureInPictureStopped() override { NOTREACHED(); }
-  void PictureInPictureControlClicked(const WebString& control_id) override {
-    NOTREACHED();
-  }
   void OnPictureInPictureStateChange() final { NOTREACHED(); }
 };
 
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 6b58137..d25274e 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -663,26 +663,11 @@
          PictureInPictureController::Status::kEnabled;
 }
 
-void HTMLVideoElement::SendCustomControlsToPipWindow() {
-  // TODO(sawtelle): Allow setting controls multiple times for a video, even
-  // when not active, https://crbug.com/869133
-  if (!GetWebMediaPlayer() || !HasPictureInPictureCustomControls())
-    return;
-  GetWebMediaPlayer()->SetPictureInPictureCustomControls(
-      GetPictureInPictureCustomControls());
-}
-
 void HTMLVideoElement::PictureInPictureStopped() {
   PictureInPictureController::From(GetDocument())
       .OnExitedPictureInPicture(nullptr);
 }
 
-void HTMLVideoElement::PictureInPictureControlClicked(
-    const WebString& control_id) {
-  PictureInPictureController::From(GetDocument())
-      .OnPictureInPictureControlClicked(control_id);
-}
-
 WebMediaPlayer::DisplayType HTMLVideoElement::DisplayType() const {
   if (is_auto_picture_in_picture_ ||
       PictureInPictureController::IsElementInPictureInPicture(this)) {
@@ -732,20 +717,6 @@
     GetWebMediaPlayer()->OnDisplayTypeChanged(DisplayType());
 }
 
-void HTMLVideoElement::SetPictureInPictureCustomControls(
-    const std::vector<PictureInPictureControlInfo>& pip_custom_controls) {
-  pip_custom_controls_ = pip_custom_controls;
-}
-
-const std::vector<PictureInPictureControlInfo>&
-HTMLVideoElement::GetPictureInPictureCustomControls() const {
-  return pip_custom_controls_;
-}
-
-bool HTMLVideoElement::HasPictureInPictureCustomControls() const {
-  return !pip_custom_controls_.empty();
-}
-
 void HTMLVideoElement::SetIsEffectivelyFullscreen(
     blink::WebFullscreenVideoStatus status) {
   is_effectively_fullscreen_ =
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h
index 9db2894..41daa2f7d 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -26,7 +26,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_HTML_VIDEO_ELEMENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_HTML_VIDEO_ELEMENT_H_
 
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_image_source.h"
 #include "third_party/blink/renderer/core/html/html_image_loader.h"
@@ -175,9 +174,7 @@
 
   void MediaRemotingStarted(const WebString& remote_device_friendly_name) final;
   bool SupportsPictureInPicture() const final;
-  void SendCustomControlsToPipWindow();
   void PictureInPictureStopped() final;
-  void PictureInPictureControlClicked(const WebString& control_id) final;
   void MediaRemotingStopped(WebLocalizedString::Name error_msg) final;
   WebMediaPlayer::DisplayType DisplayType() const final;
   bool IsInAutoPIP() const final;
@@ -188,12 +185,6 @@
   void OnEnteredPictureInPicture();
   void OnExitedPictureInPicture();
 
-  void SetPictureInPictureCustomControls(
-      const std::vector<PictureInPictureControlInfo>& pip_custom_controls);
-  const std::vector<PictureInPictureControlInfo>&
-  GetPictureInPictureCustomControls() const;
-  bool HasPictureInPictureCustomControls() const;
-
   void SetIsEffectivelyFullscreen(blink::WebFullscreenVideoStatus);
 
   void SetImageForTest(ImageResourceContent* content) {
@@ -254,10 +245,6 @@
   // Whether this element is in overlay fullscreen mode.
   bool in_overlay_fullscreen_video_;
 
-  // Holds the most recently set custom controls. These will be persistent
-  // across active/inactive windows until new controls are passed in.
-  std::vector<PictureInPictureControlInfo> pip_custom_controls_;
-
   // Whether the video element should be considered as fullscreen with regards
   // to display type and other UI features. This does not mean the DOM element
   // is fullscreen.
diff --git a/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/third_party/blink/renderer/core/html/media/html_video_element_test.cc
index 1dbf6e8..f637980f1 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element_test.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element_test.cc
@@ -7,7 +7,6 @@
 #include "cc/layers/layer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
 #include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -97,16 +96,6 @@
   GetDocument().body()->removeChild(video());
 }
 
-TEST_F(HTMLVideoElementTest, setPictureInPictureControls) {
-  EXPECT_FALSE(video()->HasPictureInPictureCustomControls());
-
-  std::vector<PictureInPictureControlInfo> test_controls;
-  test_controls.push_back(PictureInPictureControlInfo());
-  video()->SetPictureInPictureCustomControls(test_controls);
-
-  EXPECT_TRUE(video()->HasPictureInPictureCustomControls());
-}
-
 TEST_F(HTMLVideoElementTest, EffectivelyFullscreen_DisplayType) {
   EXPECT_EQ(WebMediaPlayer::DisplayType::kInline, video()->DisplayType());
 
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index ef1b680e..e438068 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -140,7 +140,6 @@
               ? HTMLParserScheduler::Create(this, loading_task_runner_.get())
               : nullptr),
       xss_auditor_delegate_(&document),
-      preloader_(HTMLResourcePreloader::Create(document)),
       pending_csp_meta_token_(nullptr),
       should_use_threading_(sync_policy == kAllowAsynchronousParsing),
       end_was_delayed_(false),
@@ -156,6 +155,22 @@
   DCHECK(ShouldUseThreading() || (token_ && tokenizer_));
   // Threading is not allowed in prefetch mode.
   DCHECK(!document.IsPrefetchOnly() || !ShouldUseThreading());
+
+  // Don't create preloader for parsing clipboard content.
+  if (content_policy == kDisallowScriptingAndPluginContent)
+    return;
+
+  // Create preloader only when the document is:
+  // - attached to a frame (likely the prefetched resources will be loaded
+  // soon),
+  // - a HTML import document (blocks rendering and also resources will be
+  // loaded soon), or
+  // - is for no-state prefetch (made specifically for running preloader).
+  if (!document.GetFrame() && !document.IsHTMLImport() &&
+      !document.IsPrefetchOnly())
+    return;
+
+  preloader_ = HTMLResourcePreloader::Create(document);
 }
 
 HTMLDocumentParser::~HTMLDocumentParser() = default;
@@ -333,29 +348,31 @@
         &chunk->tokens.at(chunk->pending_csp_meta_token_index);
   }
 
-  bool appcache_initialized = GetDocument()->documentElement();
-  if (!appcache_initialized) {
-    appcache_queueing_start_time_ = CurrentTimeTicks();
-  }
-  // Delay sending some requests if meta tag based CSP is present or
-  // if AppCache was not yet initialized.
-  if (pending_csp_meta_token_ || !appcache_initialized) {
-    PreloadRequestStream link_rel_preloads;
-    for (auto& request : chunk->preloads) {
-      // Link rel preloads don't need to wait for AppCache but they
-      // should probably wait for CSP.
-      if (!pending_csp_meta_token_ && request->IsLinkRelPreload())
-        link_rel_preloads.push_back(std::move(request));
-      else
-        queued_preloads_.push_back(std::move(request));
+  if (preloader_) {
+    bool appcache_initialized = GetDocument()->documentElement();
+    if (!appcache_initialized) {
+      appcache_queueing_start_time_ = CurrentTimeTicks();
     }
-    preloader_->TakeAndPreload(link_rel_preloads);
-  } else {
-    // We can safely assume that there are no queued preloads request after the
-    // document element is available, as we empty the queue immediately after
-    // the document element is created in documentElementAvailable().
-    DCHECK(queued_preloads_.IsEmpty());
-    preloader_->TakeAndPreload(chunk->preloads);
+    // Delay sending some requests if meta tag based CSP is present or
+    // if AppCache was not yet initialized.
+    if (pending_csp_meta_token_ || !appcache_initialized) {
+      PreloadRequestStream link_rel_preloads;
+      for (auto& request : chunk->preloads) {
+        // Link rel preloads don't need to wait for AppCache but they
+        // should probably wait for CSP.
+        if (!pending_csp_meta_token_ && request->IsLinkRelPreload())
+          link_rel_preloads.push_back(std::move(request));
+        else
+          queued_preloads_.push_back(std::move(request));
+      }
+      preloader_->TakeAndPreload(link_rel_preloads);
+    } else {
+      // We can safely assume that there are no queued preloads request after
+      // the document element is available, as we empty the queue immediately
+      // after the document element is created in documentElementAvailable().
+      DCHECK(queued_preloads_.IsEmpty());
+      preloader_->TakeAndPreload(chunk->preloads);
+    }
   }
 
   speculations_.push_back(std::move(chunk));
@@ -690,10 +707,6 @@
   if (IsPaused()) {
     DCHECK_EQ(tokenizer_->GetState(), HTMLTokenizer::kDataState);
 
-    DCHECK(preloader_);
-    // TODO(kouhei): preloader_ should be always available for synchronous
-    // parsing case, adding paranoia if for speculative crash fix for
-    // crbug.com/465478
     if (preloader_) {
       if (!preload_scanner_) {
         preload_scanner_ = CreatePreloadScanner(
@@ -908,7 +921,7 @@
   tree_builder_->Finished();
 
   // All preloads should be done.
-  preloader_.Clear();
+  preloader_ = nullptr;
 
   DocumentParser::StopParsing();
 }
@@ -1251,7 +1264,8 @@
           kWebLoadingBehaviorAmpDocumentLoaded);
     }
   }
-  FetchQueuedPreloads();
+  if (preloader_)
+    FetchQueuedPreloads();
 }
 
 std::unique_ptr<HTMLPreloadScanner> HTMLDocumentParser::CreatePreloadScanner(
@@ -1263,6 +1277,9 @@
 }
 
 void HTMLDocumentParser::ScanAndPreload(HTMLPreloadScanner* scanner) {
+  if (!preloader_)
+    return;
+
   bool seen_csp_meta_tag = false;
   PreloadRequestStream requests = scanner->Scan(
       GetDocument()->ValidBaseElementURL(), nullptr, seen_csp_meta_tag);
@@ -1270,6 +1287,8 @@
 }
 
 void HTMLDocumentParser::FetchQueuedPreloads() {
+  DCHECK(preloader_);
+
   if (pending_csp_meta_token_ || !GetDocument()->documentElement())
     return;
 
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_document_test.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_document_test.cc
new file mode 100644
index 0000000..289f87a
--- /dev/null
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_document_test.cc
@@ -0,0 +1,105 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_prescient_networking.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+
+namespace blink {
+
+class MockPrescientNetworking : public WebPrescientNetworking {
+ public:
+  bool DidDnsPrefetch() const { return did_dns_prefetch_; }
+  bool DidPreconnect() const { return did_preconnect_; }
+
+ private:
+  void PrefetchDNS(const WebString&) override { did_dns_prefetch_ = true; }
+
+  void Preconnect(const WebURL&, const bool) override {
+    did_preconnect_ = true;
+  }
+
+  bool did_dns_prefetch_ = false;
+  bool did_preconnect_ = false;
+};
+
+class TestingPlatformSupportWithMockPrescientNetworking
+    : public TestingPlatformSupport {
+ public:
+  MockPrescientNetworking& GetMockPrescientNetworking() {
+    return mock_prescient_networking_;
+  }
+
+ private:
+  WebPrescientNetworking* PrescientNetworking() override {
+    return &mock_prescient_networking_;
+  }
+
+  MockPrescientNetworking mock_prescient_networking_;
+};
+
+// HTMLPreloadScannerDocumentTest tests if network hints are
+// properly committed/suppressed on various HTMLDocumentParser uses.
+//
+// HTMLPreloadScannerDocumentTest uses SimTest so we have a valid
+// ResourceFetcher. SimTest disables asynchronous parsing mode, so we rely on
+// web_tests for asynchronous parsing testing cases.
+//
+// See also: web_tests/http/tests/preload and web_tests/fast/preloader.
+class HTMLPreloadScannerDocumentTest : public SimTest {
+ private:
+  void SetUp() override {
+    SimTest::SetUp();
+
+    constexpr const char kTestUrl[] = "https://example.com/test.html";
+    main_resource_ = std::make_unique<SimRequest>(kTestUrl, "text/html");
+    LoadURL(kTestUrl);
+  }
+
+ protected:
+  ScopedTestingPlatformSupport<
+      TestingPlatformSupportWithMockPrescientNetworking>
+      platform_;
+  std::unique_ptr<SimRequest> main_resource_;
+};
+
+TEST_F(HTMLPreloadScannerDocumentTest, DOMParser) {
+  main_resource_->Complete(R"(<script>
+    var p = new DOMParser();
+    p.parseFromString(
+      '<link rel="preconnect" href="https://target.example.com/"/>',
+      'text/html');
+  </script>)");
+
+  EXPECT_FALSE(platform_->GetMockPrescientNetworking().DidDnsPrefetch());
+  EXPECT_FALSE(platform_->GetMockPrescientNetworking().DidPreconnect());
+}
+
+TEST_F(HTMLPreloadScannerDocumentTest, DetachedDocumentInnerHTML) {
+  main_resource_->Complete(R"(<script>
+    var doc = document.implementation.createHTMLDocument('');
+    doc.body.innerHTML =
+        '<link rel="preconnect" href="https://target.example.com/"/>';
+  </script>)");
+
+  EXPECT_FALSE(platform_->GetMockPrescientNetworking().DidDnsPrefetch());
+  EXPECT_FALSE(platform_->GetMockPrescientNetworking().DidPreconnect());
+}
+
+TEST_F(HTMLPreloadScannerDocumentTest, XHRResponseDocument) {
+  main_resource_->Complete(R"(<script>
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', 'data:text/html,' +
+        '<link rel="preconnect" href="https://target.example.com/"/>');
+    xhr.responseType = 'document';
+    xhr.send();
+  </script>)");
+
+  EXPECT_FALSE(platform_->GetMockPrescientNetworking().DidDnsPrefetch());
+  EXPECT_FALSE(platform_->GetMockPrescientNetworking().DidPreconnect());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h
index d8dbcb2..4792b6c 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
 
@@ -19,6 +20,8 @@
 class ImageBitmapOptions;
 
 class CORE_EXPORT ImageBitmapSource {
+  DISALLOW_NEW();
+
  public:
   virtual IntSize BitmapSourceSize() const { return IntSize(); }
   virtual ScriptPromise CreateImageBitmap(ScriptState*,
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.h b/third_party/blink/renderer/core/input/pointer_event_manager.h
index d6d1bf0..a6b8ba1c6 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.h
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.h
@@ -108,11 +108,6 @@
   WebInputEventResult FlushEvents();
 
  private:
-  typedef HeapHashMap<PointerId,
-                      Member<Element>,
-                      WTF::IntHash<PointerId>,
-                      WTF::UnsignedWithZeroKeyHashTraits<PointerId>>
-      PointerCapturingMap;
   class EventTargetAttributes {
     DISALLOW_NEW();
 
@@ -122,6 +117,16 @@
     EventTargetAttributes() : target(nullptr) {}
     EventTargetAttributes(Element* target) : target(target) {}
   };
+  // We use int64_t to cover the whole range for PointerId with no
+  // deleted hash value.
+  template <typename T>
+  using PointerIdKeyMap =
+      HeapHashMap<int64_t,
+                  T,
+                  WTF::IntHash<int64_t>,
+                  WTF::UnsignedWithZeroKeyHashTraits<int64_t>>;
+  using PointerCapturingMap = PointerIdKeyMap<Member<Element>>;
+  using ElementUnderPointerMap = PointerIdKeyMap<EventTargetAttributes>;
 
   class PointerEventBoundaryEventDispatcher : public BoundaryEventDispatcher {
    public:
@@ -243,11 +248,6 @@
   // which might be different than m_nodeUnderMouse in EventHandler. That one
   // keeps track of any compatibility mouse event positions but this map for
   // the pointer with id=1 is only taking care of true mouse related events.
-  using ElementUnderPointerMap =
-      HeapHashMap<PointerId,
-                  EventTargetAttributes,
-                  WTF::IntHash<PointerId>,
-                  WTF::UnsignedWithZeroKeyHashTraits<PointerId>>;
   ElementUnderPointerMap element_under_pointer_;
 
   PointerCapturingMap pointer_capture_target_;
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager_test.cc b/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
index 925a18f..9dc7f4d 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
+++ b/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/input/pointer_event_manager.h"
 
+#include <limits>
+
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
@@ -100,13 +102,55 @@
   WebMouseEvent CreateTestMouseEvent(WebInputEvent::Type type,
                                      const WebFloatPoint& coordinates) {
     WebMouseEvent event(type, coordinates, coordinates,
-                        WebPointerProperties::Button::kLeft, 0, 0,
+                        WebPointerProperties::Button::kLeft, 0,
+                        WebInputEvent::kLeftButtonDown,
                         WebInputEvent::GetStaticTimeStampForTests());
     event.SetFrameScale(1);
     return event;
   }
 };
 
+TEST_F(PointerEventManagerTest, HasPointerCapture) {
+  WebView().MainFrameWidget()->Resize(WebSize(400, 400));
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(
+      "<body style='padding: 0px; width: 400px; height: 400px;'>"
+      "</body>");
+  ASSERT_FALSE(GetDocument().body()->hasPointerCapture(4));
+  ASSERT_FALSE(GetDocument().body()->hasPointerCapture(
+      std::numeric_limits<PointerId>::max()));
+  ASSERT_FALSE(GetDocument().body()->hasPointerCapture(0));
+  ASSERT_FALSE(GetDocument().body()->hasPointerCapture(-1));
+  ASSERT_FALSE(
+      GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId));
+
+  ExceptionState exception(nullptr, ExceptionState::kExecutionContext, "", "");
+
+  GetEventHandler().HandleMousePressEvent(
+      CreateTestMouseEvent(WebInputEvent::kMouseDown, WebFloatPoint(100, 100)));
+
+  ASSERT_FALSE(
+      GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId));
+
+  GetDocument().body()->setPointerCapture(PointerEventFactory::kMouseId,
+                                          exception);
+  ASSERT_TRUE(
+      GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId));
+
+  GetEventHandler().HandleMouseMoveEvent(
+      CreateTestMouseEvent(WebInputEvent::kMouseMove, WebFloatPoint(200, 200)),
+      Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
+
+  ASSERT_TRUE(
+      GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId));
+
+  GetDocument().body()->releasePointerCapture(PointerEventFactory::kMouseId,
+                                              exception);
+  ASSERT_FALSE(
+      GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId));
+}
+
 TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
   WebView().MainFrameWidget()->Resize(WebSize(400, 400));
   SimRequest request("https://example.com/test.html", "text/html");
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
index d42f29e..cab7cdd 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
+++ b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
@@ -96,7 +96,6 @@
               .GetMainFrameResizesAreOrientationChanges()),
       touch_event_emulation_enabled_(false),
       double_tap_to_zoom_enabled_(false),
-      original_device_supports_touch_(false),
       original_max_touch_points_(0),
       embedder_script_enabled_(
           web_view->GetPage()->GetSettings().GetScriptEnabled()),
@@ -477,8 +476,6 @@
 void DevToolsEmulator::SetTouchEventEmulationEnabled(bool enabled,
                                                      int max_touch_points) {
   if (!touch_event_emulation_enabled_) {
-    original_device_supports_touch_ =
-        web_view_->GetPage()->GetSettings().GetDeviceSupportsTouch();
     original_max_touch_points_ =
         web_view_->GetPage()->GetSettings().GetMaxTouchPoints();
   }
@@ -486,8 +483,6 @@
   web_view_->GetPage()
       ->GetSettings()
       .SetForceTouchEventFeatureDetectionForInspector(enabled);
-  web_view_->GetPage()->GetSettings().SetDeviceSupportsTouch(
-      enabled ? true : original_device_supports_touch_);
   web_view_->GetPage()->GetSettings().SetMaxTouchPoints(
       enabled ? max_touch_points : original_max_touch_points_);
   web_view_->GetPage()->GetSettings().SetAvailablePointerTypes(
@@ -499,7 +494,7 @@
   web_view_->GetPage()->GetSettings().SetPrimaryHoverType(
       enabled ? kHoverTypeNone : embedder_primary_hover_type_);
   WebLocalFrameImpl* frame = web_view_->MainFrameImpl();
-  if (!original_device_supports_touch_ && enabled && frame)
+  if (enabled && frame)
     frame->GetFrame()->GetEventHandler().ClearMouseEventManager();
 }
 
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_emulator.h b/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
index b9680b1..3bffc2d 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
+++ b/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
@@ -113,7 +113,6 @@
 
   bool touch_event_emulation_enabled_;
   bool double_tap_to_zoom_enabled_;
-  bool original_device_supports_touch_;
   int original_max_touch_points_;
 
   bool embedder_script_enabled_;
diff --git a/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc b/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc
index 83fbd77..32f723a 100644
--- a/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc
@@ -38,7 +38,8 @@
 InspectorPerformanceAgent::InspectorPerformanceAgent(
     InspectedFrames* inspected_frames)
     : inspected_frames_(inspected_frames),
-      enabled_(&agent_state_, /*default_value=*/false) {}
+      enabled_(&agent_state_, /*default_value=*/false),
+      use_thread_ticks_(&agent_state_, /*default_value=*/false) {}
 
 InspectorPerformanceAgent::~InspectorPerformanceAgent() = default;
 
@@ -55,6 +56,7 @@
   task_start_ticks_ = TimeTicks();
   script_start_ticks_ = TimeTicks();
   v8compile_start_ticks_ = TimeTicks();
+  thread_time_origin_ = GetThreadTimeNow();
 }
 
 protocol::Response InspectorPerformanceAgent::enable() {
@@ -95,13 +97,13 @@
   using namespace protocol::Performance::SetTimeDomain;
 
   if (time_domain == TimeDomainEnum::TimeTicks) {
-    use_thread_ticks_ = false;
+    use_thread_ticks_.Clear();
   } else if (time_domain == TimeDomainEnum::ThreadTicks) {
     if (!base::ThreadTicks::IsSupported()) {
       return Response::Error("Thread time is not supported on this platform.");
     }
     base::ThreadTicks::WaitUntilInitialized();
-    use_thread_ticks_ = true;
+    use_thread_ticks_.Set(true);
   } else {
     return Response::Error("Invalid time domain specification.");
   }
@@ -110,11 +112,14 @@
 }
 
 TimeTicks InspectorPerformanceAgent::GetTimeTicksNow() {
-  return use_thread_ticks_
-             ? base::TimeTicks() +
-                   base::TimeDelta::FromMicroseconds(
-                       base::ThreadTicks::Now().since_origin().InMicroseconds())
-             : base::subtle::TimeTicksNowIgnoringOverride();
+  return use_thread_ticks_.Get() ? GetThreadTimeNow()
+                                 : base::subtle::TimeTicksNowIgnoringOverride();
+}
+
+TimeTicks InspectorPerformanceAgent::GetThreadTimeNow() {
+  return base::TimeTicks() +
+         base::TimeDelta::FromMicroseconds(
+             base::ThreadTicks::Now().since_origin().InMicroseconds());
 }
 
 Response InspectorPerformanceAgent::getMetrics(
@@ -170,6 +175,9 @@
   AppendMetric(result.get(), "TaskOtherDuration",
                other_tasks_duration.InSecondsF());
 
+  TimeDelta thread_time = GetThreadTimeNow() - thread_time_origin_;
+  AppendMetric(result.get(), "ThreadTime", thread_time.InSecondsF());
+
   v8::HeapStatistics heap_statistics;
   V8PerIsolateData::MainThreadIsolate()->GetHeapStatistics(&heap_statistics);
   AppendMetric(result.get(), "JSHeapUsedSize",
diff --git a/third_party/blink/renderer/core/inspector/inspector_performance_agent.h b/third_party/blink/renderer/core/inspector/inspector_performance_agent.h
index 57a34dbf..9bc6a2b 100644
--- a/third_party/blink/renderer/core/inspector/inspector_performance_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_performance_agent.h
@@ -72,6 +72,7 @@
   void ScriptEnds();
   void InnerEnable();
   TimeTicks GetTimeTicksNow();
+  TimeTicks GetThreadTimeNow();
 
   Member<InspectedFrames> inspected_frames_;
   TimeDelta layout_duration_;
@@ -84,12 +85,13 @@
   TimeTicks task_start_ticks_;
   TimeDelta v8compile_duration_;
   TimeTicks v8compile_start_ticks_;
+  TimeTicks thread_time_origin_;
   unsigned long long layout_count_ = 0;
   unsigned long long recalc_style_count_ = 0;
   int script_call_depth_ = 0;
   int layout_depth_ = 0;
-  bool use_thread_ticks_ = false;
   InspectorAgentState::Boolean enabled_;
+  InspectorAgentState::Boolean use_thread_ticks_;
   DISALLOW_COPY_AND_ASSIGN(InspectorPerformanceAgent);
 };
 
diff --git a/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc b/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
index 223e720..9390b052 100644
--- a/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
+++ b/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
@@ -5,13 +5,17 @@
 #include "third_party/blink/renderer/core/layout/custom/css_layout_definition.h"
 
 #include <memory>
+
 #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_fragment_result_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_layout_callback.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_layout_fragment_request.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_no_argument_constructor.h"
 #include "third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -45,55 +49,46 @@
 
 CSSLayoutDefinition::CSSLayoutDefinition(
     ScriptState* script_state,
-    v8::Local<v8::Function> constructor,
-    v8::Local<v8::Function> intrinsic_sizes,
-    v8::Local<v8::Function> layout,
+    V8NoArgumentConstructor* constructor,
+    V8Function* intrinsic_sizes,
+    V8LayoutCallback* layout,
     const Vector<CSSPropertyID>& native_invalidation_properties,
     const Vector<AtomicString>& custom_invalidation_properties,
     const Vector<CSSPropertyID>& child_native_invalidation_properties,
     const Vector<AtomicString>& child_custom_invalidation_properties)
     : script_state_(script_state),
-      constructor_(script_state->GetIsolate(), constructor),
-      intrinsic_sizes_(script_state->GetIsolate(), intrinsic_sizes),
-      layout_(script_state->GetIsolate(), layout),
-      constructor_has_failed_(false) {
-  native_invalidation_properties_ = native_invalidation_properties;
-  custom_invalidation_properties_ = custom_invalidation_properties;
-  child_native_invalidation_properties_ = child_native_invalidation_properties;
-  child_custom_invalidation_properties_ = child_custom_invalidation_properties;
-}
+      constructor_(constructor),
+      unused_intrinsic_sizes_(intrinsic_sizes),
+      layout_(layout),
+      native_invalidation_properties_(native_invalidation_properties),
+      custom_invalidation_properties_(custom_invalidation_properties),
+      child_native_invalidation_properties_(
+          child_native_invalidation_properties),
+      child_custom_invalidation_properties_(
+          child_custom_invalidation_properties) {}
 
 CSSLayoutDefinition::~CSSLayoutDefinition() = default;
 
 CSSLayoutDefinition::Instance::Instance(CSSLayoutDefinition* definition,
                                         v8::Local<v8::Value> instance)
     : definition_(definition),
-      instance_(definition->script_state_->GetIsolate(), instance) {}
+      instance_(definition->GetScriptState()->GetIsolate(), instance) {}
 
 bool CSSLayoutDefinition::Instance::Layout(
     const LayoutCustom& layout_custom,
     FragmentResultOptions* fragment_result_options,
     scoped_refptr<SerializedScriptValue>* fragment_result_data) {
   ScriptState* script_state = definition_->GetScriptState();
-  ExecutionContext* execution_context = ExecutionContext::From(script_state);
+  v8::Isolate* isolate = script_state->GetIsolate();
 
-  if (!script_state->ContextIsValid()) {
+  if (!script_state->ContextIsValid())
     return false;
-  }
 
   ScriptState::Scope scope(script_state);
 
-  v8::Isolate* isolate = script_state->GetIsolate();
-  v8::Local<v8::Value> instance = instance_.NewLocal(isolate);
-  v8::Local<v8::Context> context = script_state->GetContext();
-
-  v8::Local<v8::Function> layout = definition_->layout_.NewLocal(isolate);
-
   // TODO(ikilpatrick): Determine if knowing the size of the array ahead of
   // time improves performance in any noticable way.
-  v8::Local<v8::Array> children = v8::Array::New(isolate, 0);
-  uint32_t index = 0;
-
+  HeapVector<Member<CustomLayoutChild>> children;
   for (LayoutBox* child = layout_custom.FirstChildBox(); child;
        child = child->NextSiblingBox()) {
     if (child->IsOutOfFlowPositioned())
@@ -101,17 +96,12 @@
 
     CustomLayoutChild* layout_child = child->GetCustomLayoutChild();
     DCHECK(layout_child);
-
-    bool success;
-    if (!children
-             ->CreateDataProperty(
-                 context, index++,
-                 ToV8(layout_child, context->Global(), isolate))
-             .To(&success) &&
-        success)
-      return false;
+    children.push_back(layout_child);
   }
 
+  // TODO(ikilpatrick): Fill in layout edges.
+  ScriptValue edges(script_state, v8::Undefined(isolate));
+
   LayoutUnit fixed_block_size(-1);
   if (IsLogicalHeightDefinite(layout_custom)) {
     LayoutBox::LogicalExtentComputedValues computed_values;
@@ -120,6 +110,7 @@
     fixed_block_size = computed_values.extent_;
   }
 
+  // TODO(ikilpatrick): Fill in layout constraints.
   CustomLayoutConstraints* constraints =
       MakeGarbageCollected<CustomLayoutConstraints>(
           layout_custom.LogicalWidth(), fixed_block_size,
@@ -133,28 +124,21 @@
           layout_custom.GetNode(), definition_->native_invalidation_properties_,
           definition_->custom_invalidation_properties_);
 
-  // TODO(ikilpatrick): Fill in layout constraints, and edges.
-  Vector<v8::Local<v8::Value>> argv = {
-      children,
-      v8::Undefined(isolate),  // edges
-      ToV8(constraints, context->Global(), isolate),
-      ToV8(style_map, context->Global(), isolate),
-  };
-
-  v8::Local<v8::Value> generator_value;
-  if (!V8ScriptRunner::CallFunction(layout, execution_context, instance,
-                                    argv.size(), argv.data(), isolate)
-           .ToLocal(&generator_value))
+  ScriptValue return_value;
+  if (!definition_->layout_
+           ->Invoke(instance_.NewLocal(isolate), children, edges, constraints,
+                    style_map)
+           .To(&return_value)) {
     return false;
+  }
 
-  DCHECK(generator_value->IsGeneratorObject());
-  v8::Local<v8::Object> generator =
-      v8::Local<v8::Object>::Cast(generator_value);
-
-  ScriptIterator iterator(generator, isolate);
+  DCHECK(return_value.V8Value()->IsGeneratorObject());
+  ScriptIterator iterator(return_value.V8Value().As<v8::Object>(), isolate);
   v8::Local<v8::Value> next_value;
 
   // We run the generator until it's exhausted.
+  v8::Local<v8::Context> context = script_state->GetContext();
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
   ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
                                  "CSSLayoutAPI", "Layout");
   while (iterator.Next(execution_context, exception_state, next_value)) {
@@ -299,28 +283,18 @@
     return nullptr;
 
   // Ensure that we don't create an instance on a detached context.
-  if (!GetScriptState()->ContextIsValid()) {
+  if (!GetScriptState()->ContextIsValid())
     return nullptr;
-  }
-
-  Instance* instance = nullptr;
 
   ScriptState::Scope scope(GetScriptState());
 
-  v8::Isolate* isolate = script_state_->GetIsolate();
-  v8::Local<v8::Function> constructor = constructor_.NewLocal(isolate);
-  DCHECK(!IsUndefinedOrNull(constructor));
-
-  v8::Local<v8::Value> layout_instance;
-  if (V8ScriptRunner::CallAsConstructor(
-          isolate, constructor, ExecutionContext::From(script_state_), 0, {})
-          .ToLocal(&layout_instance)) {
-    instance = MakeGarbageCollected<Instance>(this, layout_instance);
-  } else {
+  ScriptValue instance;
+  if (!constructor_->Construct().To(&instance)) {
     constructor_has_failed_ = true;
+    return nullptr;
   }
 
-  return instance;
+  return MakeGarbageCollected<Instance>(this, instance.V8Value());
 }
 
 void CSSLayoutDefinition::Instance::Trace(blink::Visitor* visitor) {
@@ -329,7 +303,7 @@
 
 void CSSLayoutDefinition::Trace(Visitor* visitor) {
   visitor->Trace(constructor_);
-  visitor->Trace(intrinsic_sizes_);
+  visitor->Trace(unused_intrinsic_sizes_);
   visitor->Trace(layout_);
   visitor->Trace(script_state_);
 }
diff --git a/third_party/blink/renderer/core/layout/custom/css_layout_definition.h b/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
index 7364c99..2142c302 100644
--- a/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
+++ b/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
@@ -20,6 +20,9 @@
 class LayoutCustom;
 class ScriptState;
 class SerializedScriptValue;
+class V8Function;
+class V8LayoutCallback;
+class V8NoArgumentConstructor;
 
 // Represents a javascript class registered on the LayoutWorkletGlobalScope by
 // the author.
@@ -30,9 +33,9 @@
  public:
   CSSLayoutDefinition(
       ScriptState*,
-      v8::Local<v8::Function> constructor,
-      v8::Local<v8::Function> intrinsic_sizes,
-      v8::Local<v8::Function> layout,
+      V8NoArgumentConstructor* constructor,
+      V8Function* intrinsic_sizes,
+      V8LayoutCallback* layout,
       const Vector<CSSPropertyID>& native_invalidation_properties,
       const Vector<AtomicString>& custom_invalidation_properties,
       const Vector<CSSPropertyID>& child_native_invalidation_properties,
@@ -80,10 +83,6 @@
 
   ScriptState* GetScriptState() const { return script_state_; }
 
-  v8::Local<v8::Function> LayoutFunctionForTesting(v8::Isolate* isolate) {
-    return layout_.NewLocal(isolate);
-  }
-
   virtual void Trace(blink::Visitor* visitor);
 
   const char* NameInHeapSnapshot() const override {
@@ -96,13 +95,13 @@
   // This object keeps the class instances, constructor function, intrinsic
   // sizes function, and layout function alive. It participates in wrapper
   // tracing as it holds onto V8 wrappers.
-  TraceWrapperV8Reference<v8::Function> constructor_;
-  TraceWrapperV8Reference<v8::Function> intrinsic_sizes_;
-  TraceWrapperV8Reference<v8::Function> layout_;
+  TraceWrapperMember<V8NoArgumentConstructor> constructor_;
+  TraceWrapperMember<V8Function> unused_intrinsic_sizes_;
+  TraceWrapperMember<V8LayoutCallback> layout_;
 
   // If a constructor call ever fails, we'll refuse to create any more
   // instances of the web developer provided class.
-  bool constructor_has_failed_;
+  bool constructor_has_failed_ = false;
 
   Vector<CSSPropertyID> native_invalidation_properties_;
   Vector<AtomicString> custom_invalidation_properties_;
diff --git a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
index 207c5aa..e3d1c4af 100644
--- a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
@@ -4,6 +4,9 @@
 
 #include "third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h"
 
+#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_layout_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_no_argument_constructor.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_parser.h"
 #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
@@ -16,6 +19,7 @@
 #include "third_party/blink/renderer/core/layout/custom/layout_worklet.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
+#include "third_party/blink/renderer/platform/bindings/callback_method_retriever.h"
 
 namespace blink {
 
@@ -59,7 +63,7 @@
 // https://drafts.css-houdini.org/css-layout-api/#dom-layoutworkletglobalscope-registerlayout
 void LayoutWorkletGlobalScope::registerLayout(
     const AtomicString& name,
-    const ScriptValue& constructor_value,
+    V8NoArgumentConstructor* layout_ctor,
     ExceptionState& exception_state) {
   if (name.IsEmpty()) {
     exception_state.ThrowTypeError("The empty string is not a valid name.");
@@ -73,17 +77,14 @@
     return;
   }
 
-  v8::Local<v8::Context> context = ScriptController()->GetContext();
-
-  DCHECK(constructor_value.V8Value()->IsFunction());
-  v8::Local<v8::Function> constructor =
-      v8::Local<v8::Function>::Cast(constructor_value.V8Value());
+  v8::Local<v8::Context> current_context =
+      layout_ctor->GetIsolate()->GetCurrentContext();
 
   Vector<CSSPropertyID> native_invalidation_properties;
   Vector<AtomicString> custom_invalidation_properties;
 
   if (!V8ObjectParser::ParseCSSPropertyList(
-          context, constructor, "inputProperties",
+          current_context, layout_ctor->CallbackObject(), "inputProperties",
           &native_invalidation_properties, &custom_invalidation_properties,
           &exception_state))
     return;
@@ -92,29 +93,47 @@
   Vector<AtomicString> child_custom_invalidation_properties;
 
   if (!V8ObjectParser::ParseCSSPropertyList(
-          context, constructor, "childInputProperties",
-          &child_native_invalidation_properties,
+          current_context, layout_ctor->CallbackObject(),
+          "childInputProperties", &child_native_invalidation_properties,
           &child_custom_invalidation_properties, &exception_state))
     return;
 
-  v8::Local<v8::Object> prototype;
-  if (!V8ObjectParser::ParsePrototype(context, constructor, &prototype,
-                                      &exception_state))
+  CallbackMethodRetriever retriever(layout_ctor);
+  retriever.GetPrototypeObject(exception_state);
+  if (exception_state.HadException())
     return;
 
-  v8::Local<v8::Function> intrinsic_sizes;
-  if (!V8ObjectParser::ParseGeneratorFunction(
-          context, prototype, "intrinsicSizes", &intrinsic_sizes,
-          &exception_state))
+  v8::Local<v8::Function> v8_intrinsic_sizes =
+      retriever.GetMethodOrThrow("intrinsicSizes", exception_state);
+  if (exception_state.HadException())
     return;
+  // TODO(ikilpatrick): Make it clear if we really need to check the function
+  // is a generator function or not.  Non generator function can return an
+  // iterator.
+  if (!v8_intrinsic_sizes->IsGeneratorFunction()) {
+    exception_state.ThrowTypeError(
+        "The 'intrinsicSizes' property on the prototype is not a generator "
+        "function.");
+    return;
+  }
+  V8Function* intrinsic_sizes = V8Function::Create(v8_intrinsic_sizes);
 
-  v8::Local<v8::Function> layout;
-  if (!V8ObjectParser::ParseGeneratorFunction(context, prototype, "layout",
-                                              &layout, &exception_state))
+  v8::Local<v8::Function> v8_layout =
+      retriever.GetMethodOrThrow("layout", exception_state);
+  if (exception_state.HadException())
     return;
+  // TODO(ikilpatrick): Make it clear if we really need to check the function
+  // is a generator function or not.  Non generator function can return an
+  // iterator.
+  if (!v8_layout->IsGeneratorFunction()) {
+    exception_state.ThrowTypeError(
+        "The 'layout' property on the prototype is not a generator function.");
+    return;
+  }
+  V8LayoutCallback* layout = V8LayoutCallback::Create(v8_layout);
 
   CSSLayoutDefinition* definition = MakeGarbageCollected<CSSLayoutDefinition>(
-      ScriptController()->GetScriptState(), constructor, intrinsic_sizes,
+      ScriptController()->GetScriptState(), layout_ctor, intrinsic_sizes,
       layout, native_invalidation_properties, custom_invalidation_properties,
       child_native_invalidation_properties,
       child_custom_invalidation_properties);
diff --git a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
index 69c2f99..c05408c 100644
--- a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
+++ b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
@@ -5,17 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_CUSTOM_LAYOUT_WORKLET_GLOBAL_SCOPE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_CUSTOM_LAYOUT_WORKLET_GLOBAL_SCOPE_H_
 
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/layout/custom/pending_layout_registry.h"
 #include "third_party/blink/renderer/core/workers/worklet_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
 class CSSLayoutDefinition;
+class V8NoArgumentConstructor;
 class WorkerReportingProxy;
 
 class CORE_EXPORT LayoutWorkletGlobalScope final : public WorkletGlobalScope {
@@ -41,7 +40,7 @@
 
   // Implements LayoutWorkletGlobalScope.idl
   void registerLayout(const AtomicString& name,
-                      const ScriptValue& constructor_value,
+                      V8NoArgumentConstructor* layout_ctor,
                       ExceptionState&);
 
   CSSLayoutDefinition* FindDefinition(const AtomicString& name);
diff --git a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.idl b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.idl
index 0ed4c1e..3c618a74 100644
--- a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.idl
+++ b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.idl
@@ -9,7 +9,9 @@
     Global=(Worklet,LayoutWorklet),
     RuntimeEnabled=CSSLayoutAPI
 ] interface LayoutWorkletGlobalScope : WorkletGlobalScope {
-    // TODO(yukishiino): |layoutCtor| should be of callback function type
-    // (should be: callback T = any ()).
-    [RaisesException] void registerLayout(DOMString name, CallbackFunctionTreatedAsScriptValue layoutCtor);
+    [RaisesException] void registerLayout(DOMString name, NoArgumentConstructor layoutCtor);
 };
+
+// Blink-specific type for layout function
+// https://drafts.css-houdini.org/css-layout-api/#layout-definition-layout-function
+callback LayoutCallback = any (sequence<LayoutChild> children, any edges, LayoutConstraints constraints, StylePropertyMapReadOnly styleMap);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index d1b08d3..c6483ba 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -674,6 +674,11 @@
     TextDirection direction = start_item.Direction();
     unsigned end_index = index + 1;
     unsigned end_offset = start_item.EndOffset();
+
+    // Scan forward until an item is encountered that should trigger a shaping
+    // break. This ensures that adjacent text items are shaped together whenever
+    // possible as this is required for accurate cross-element shaping.
+    unsigned num_text_items = 1;
     for (; end_index < items->size(); end_index++) {
       const NGInlineItem& item = (*items)[end_index];
 
@@ -693,6 +698,7 @@
             !item.EqualsRunSegment(start_item))
           break;
         end_offset = item.EndOffset();
+        num_text_items++;
       } else if (item.Type() == NGInlineItem::kOpenTag ||
                  item.Type() == NGInlineItem::kCloseTag) {
         // These items are opaque to shaping.
@@ -770,7 +776,10 @@
 
     // If the text is from multiple items, split the ShapeResult to
     // corresponding items.
-    unsigned opaque_context = 0;
+    DCHECK_GT(num_text_items, 0u);
+    std::unique_ptr<ShapeResult::ShapeRange[]> text_item_ranges =
+        std::make_unique<ShapeResult::ShapeRange[]>(num_text_items);
+    unsigned range_index = 0;
     for (; index < end_index; index++) {
       NGInlineItem& item = (*items)[index];
       if (item.Type() != NGInlineItem::kText)
@@ -782,12 +791,14 @@
       //
       // When multiple code units shape to one glyph, such as ligatures, the
       // item that has its first code unit keeps the glyph.
-      item.shape_result_ = shape_result->SubRange(
-          item.StartOffset(), item.EndOffset(), &opaque_context);
-      DCHECK(item.TextShapeResult());
-      DCHECK_EQ(item.TextShapeResult()->StartIndex(), item.StartOffset());
-      DCHECK_EQ(item.TextShapeResult()->EndIndex(), item.EndOffset());
+      scoped_refptr<ShapeResult> item_result =
+          ShapeResult::CreateEmpty(*shape_result.get());
+      item.shape_result_ = item_result;
+      text_item_ranges[range_index++] = {item.StartOffset(), item.EndOffset(),
+                                         item_result.get()};
     }
+    DCHECK_EQ(range_index, num_text_items);
+    shape_result->CopyRanges(&text_item_ranges[0], num_text_items);
   }
 
 #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index c7c8bfe..2f91900 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -112,18 +112,18 @@
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(30), LayoutUnit(40)),
             result->PhysicalFragment()->Size());
 
-  // Test pointer-equal constraint space
+  // Test pointer-equal constraint space.
   result = block_flow->CachedLayoutResult(space, nullptr);
   EXPECT_NE(result.get(), nullptr);
 
-  // Test identical, but not pointer-equal, constraint space
+  // Test identical, but not pointer-equal, constraint space.
   space = ConstructBlockLayoutTestConstraintSpace(
       WritingMode::kHorizontalTb, TextDirection::kLtr,
       NGLogicalSize(LayoutUnit(100), LayoutUnit(100)));
   result = block_flow->CachedLayoutResult(space, nullptr);
   EXPECT_NE(result.get(), nullptr);
 
-  // Test different constraint space
+  // Test different constraint space.
   space = ConstructBlockLayoutTestConstraintSpace(
       WritingMode::kHorizontalTb, TextDirection::kLtr,
       NGLogicalSize(LayoutUnit(200), LayoutUnit(100)));
@@ -144,6 +144,52 @@
   EXPECT_EQ(result.get(), nullptr);
 }
 
+TEST_F(NGBlockLayoutAlgorithmTest, MinInlineSizeCaching) {
+  ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
+
+  SetBodyInnerHTML(R"HTML(
+    <div id="box" style="min-width:30%; width: 10px; height:40px;"></div>
+  )HTML");
+
+  NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+      WritingMode::kHorizontalTb, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(100), LayoutUnit(100)));
+
+  LayoutBlockFlow* block_flow =
+      ToLayoutBlockFlow(GetLayoutObjectByElementId("box"));
+  NGBlockNode node(block_flow);
+
+  scoped_refptr<NGLayoutResult> result(node.Layout(space, nullptr));
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(30), LayoutUnit(40)),
+            result->PhysicalFragment()->Size());
+
+  // Test pointer-equal constraint space.
+  result = block_flow->CachedLayoutResult(space, nullptr);
+  EXPECT_NE(result.get(), nullptr);
+
+  // Test identical, but not pointer-equal, constraint space.
+  space = ConstructBlockLayoutTestConstraintSpace(
+      WritingMode::kHorizontalTb, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(100), LayoutUnit(100)));
+  result = block_flow->CachedLayoutResult(space, nullptr);
+  EXPECT_NE(result.get(), nullptr);
+
+  // Test different constraint space.
+  space = ConstructBlockLayoutTestConstraintSpace(
+      WritingMode::kHorizontalTb, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(100), LayoutUnit(200)));
+  result = block_flow->CachedLayoutResult(space, nullptr);
+  EXPECT_NE(result.get(), nullptr);
+
+  // Test a different constraint space that will actually result in a different
+  // size.
+  space = ConstructBlockLayoutTestConstraintSpace(
+      WritingMode::kHorizontalTb, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(200), LayoutUnit(100)));
+  result = block_flow->CachedLayoutResult(space, nullptr);
+  EXPECT_EQ(result.get(), nullptr);
+}
+
 // Verifies that two children are laid out with the correct size and position.
 TEST_F(NGBlockLayoutAlgorithmTest, LayoutBlockChildren) {
   SetBodyInnerHTML(R"HTML(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index e0f2907..aef56874 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -53,13 +53,15 @@
 }
 
 inline bool InlineLengthMayChange(const Length& length,
+                                  LengthResolveType type,
                                   const NGConstraintSpace& new_space,
                                   const NGConstraintSpace& old_space) {
   // Percentage inline margins will affect the size if the size is unspecified
   // (auto and similar). So we need to check both available size and the
   // percentage resolution size in that case.
   bool is_unspecified =
-      length.IsAuto() || length.IsFitContent() || length.IsFillAvailable();
+      (length.IsAuto() && type != LengthResolveType::kMinSize) ||
+      length.IsFitContent() || length.IsFillAvailable();
   if (is_unspecified) {
     if (new_space.AvailableSize().inline_size !=
         old_space.AvailableSize().inline_size)
@@ -770,9 +772,15 @@
         old_space.AvailableSize().inline_size)
       return true;
   } else {
-    if (InlineLengthMayChange(style.LogicalWidth(), new_space, old_space) ||
-        InlineLengthMayChange(style.LogicalMaxWidth(), new_space, old_space) ||
-        InlineLengthMayChange(style.LogicalMaxWidth(), new_space, old_space))
+    if (InlineLengthMayChange(style.LogicalWidth(),
+                              LengthResolveType::kContentSize, new_space,
+                              old_space) ||
+        InlineLengthMayChange(style.LogicalMinWidth(),
+                              LengthResolveType::kMinSize, new_space,
+                              old_space) ||
+        InlineLengthMayChange(style.LogicalMaxWidth(),
+                              LengthResolveType::kMaxSize, new_space,
+                              old_space))
       return true;
   }
 
diff --git a/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc b/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc
index 982852a2..a371603 100644
--- a/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc
+++ b/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc
@@ -100,7 +100,7 @@
   // Once PlzNavigate removes ResourceFetcher usage in navigations, we
   // might be able to remove this FetchClientSettingsObject at all.
   return *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
-      KURL(),
+      KURL(), KURL(),
 
       // SecurityOrigin. This is actually used via
       // FetchContext::GetSecurityOrigin().
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
index 3286d9e..6ac05a4 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
@@ -298,7 +298,7 @@
   FetchDescendants(module_script);
 }
 
-void ModuleTreeLinker::FetchDescendants(ModuleScript* module_script) {
+void ModuleTreeLinker::FetchDescendants(const ModuleScript* module_script) {
   DCHECK(module_script);
 
   // [nospec] Abort the steps if the browsing context is discarded.
@@ -446,7 +446,7 @@
   // thus skip FindFirstParseError() call.
   if (!found_parse_error_) {
 #if DCHECK_IS_ON()
-    HeapHashSet<Member<ModuleScript>> discovered_set;
+    HeapHashSet<Member<const ModuleScript>> discovered_set;
     DCHECK(FindFirstParseError(result_, &discovered_set).IsEmpty());
 #endif
 
@@ -465,7 +465,7 @@
     // [FDaI] Step 7. Otherwise ...
 
     // [FFPE] Step 2. If discoveredSet was not given, let it be an empty set.
-    HeapHashSet<Member<ModuleScript>> discovered_set;
+    HeapHashSet<Member<const ModuleScript>> discovered_set;
 
     // [FDaI] Step 5. Let parse error be the result of finding the first parse
     // error given result.
@@ -484,8 +484,8 @@
 //
 // This returns non-empty ScriptValue iff a parse error is found.
 ScriptValue ModuleTreeLinker::FindFirstParseError(
-    ModuleScript* module_script,
-    HeapHashSet<Member<ModuleScript>>* discovered_set) const {
+    const ModuleScript* module_script,
+    HeapHashSet<Member<const ModuleScript>>* discovered_set) const {
   // FindFirstParseError() is called only when there is no fetch errors, i.e.
   // all module scripts in the graph are non-null.
   DCHECK(module_script);
@@ -528,7 +528,8 @@
     // value in moduleMap whose key is given by an item of childURLs.
     //
     // [FFPE] Step 8. For each childModule of childModules:
-    ModuleScript* child_module = modulator_->GetFetchedModuleScript(child_url);
+    const ModuleScript* child_module =
+        modulator_->GetFetchedModuleScript(child_url);
 
     // [FFPE] Step 8.1. Assert: childModule is a module script (i.e., it is not
     // "fetching" or null)
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
index c1cc15b..ababbe0 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
@@ -101,7 +101,7 @@
   // Steps 3--7 of [IMSGF], and [FD]/[FDaI] called from [IMSGF].
   // TODO(hiroshige): Currently
   void NotifyModuleLoadFinished(ModuleScript*) override;
-  void FetchDescendants(ModuleScript*);
+  void FetchDescendants(const ModuleScript*);
 
   // Completion of [FD].
   void FinalizeFetchDescendantsForOneModuleScript();
@@ -110,8 +110,9 @@
   void Instantiate();
 
   // [FFPE]
-  ScriptValue FindFirstParseError(ModuleScript*,
-                                  HeapHashSet<Member<ModuleScript>>*) const;
+  ScriptValue FindFirstParseError(
+      const ModuleScript*,
+      HeapHashSet<Member<const ModuleScript>>*) const;
 
   const Member<ResourceFetcher> fetch_client_settings_object_fetcher_;
 
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index fced0462..4165c50 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -82,11 +82,6 @@
           frame->GetSettings()->GetSpatialNavigationEnabled());
 }
 
-bool SpatialNavigationIgnoresEventHandlers(const LocalFrame* frame) {
-  return (frame && frame->GetSettings() &&
-          frame->GetSettings()->GetDeviceSupportsTouch());
-}
-
 static bool RectsIntersectOnOrthogonalAxis(SpatialNavigationDirection direction,
                                            const LayoutRect& a,
                                            const LayoutRect& b) {
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h
index 22aefc98..9e40a81 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.h
+++ b/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -45,7 +45,6 @@
 }
 
 CORE_EXPORT bool IsSpatialNavigationEnabled(const LocalFrame*);
-bool SpatialNavigationIgnoresEventHandlers(const LocalFrame*);
 
 struct FocusCandidate {
   STACK_ALLOCATED();
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index acd6aea..92a62d7 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -3020,12 +3020,13 @@
 }
 
 void CompositedLayerMapping::SetNeedsCheckRasterInvalidation() {
-  ApplyToGraphicsLayers(this,
-                        [](GraphicsLayer* graphics_layer) {
-                          if (graphics_layer->DrawsContent())
-                            graphics_layer->SetNeedsCheckRasterInvalidation();
-                        },
-                        kApplyToAllGraphicsLayers);
+  ApplyToGraphicsLayers(
+      this,
+      [](GraphicsLayer* graphics_layer) {
+        if (graphics_layer->DrawsContent())
+          graphics_layer->SetNeedsCheckRasterInvalidation();
+      },
+      kApplyToAllGraphicsLayers);
 }
 
 const GraphicsLayerPaintInfo* CompositedLayerMapping::ContainingSquashedLayer(
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 913c060..4ee6114 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -28,9 +28,8 @@
         .RecomputeInterestRect(graphics_layer);
   }
 
-  IntRect ComputeInterestRect(
-      GraphicsLayer* graphics_layer,
-      IntRect previous_interest_rect) {
+  IntRect ComputeInterestRect(GraphicsLayer* graphics_layer,
+                              IntRect previous_interest_rect) {
     return static_cast<CompositedLayerMapping&>(graphics_layer->Client())
         .ComputeInterestRect(graphics_layer, previous_interest_rect);
   }
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index 12aa542..8d8c9be 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -74,7 +74,6 @@
 };
 
 class CompositingRequirementsUpdater::OverlapMap {
-
  public:
   OverlapMap() {
     // Begin by assuming the root layer will be composited so that there
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
index 6aac400..50ab350 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
@@ -236,14 +236,6 @@
 }
 
 Vector<NGPaintFragmentWithContainerOffset>
-NGPaintFragmentTraversal::DescendantsOf(const NGPaintFragment& container) {
-  Vector<NGPaintFragmentWithContainerOffset> result;
-  NotSelfPaintingFilter filter;
-  CollectPaintFragments(container, NGPhysicalOffset(), filter, &result);
-  return result;
-}
-
-Vector<NGPaintFragmentWithContainerOffset>
 NGPaintFragmentTraversal::InlineDescendantsOf(
     const NGPaintFragment& container) {
   Vector<NGPaintFragmentWithContainerOffset> result;
@@ -252,15 +244,6 @@
   return result;
 }
 
-Vector<NGPaintFragmentWithContainerOffset>
-NGPaintFragmentTraversal::SelfFragmentsOf(const NGPaintFragment& container,
-                                          const LayoutObject* target) {
-  Vector<NGPaintFragmentWithContainerOffset> result;
-  LayoutObjectFilter filter(target);
-  CollectPaintFragments(container, NGPhysicalOffset(), filter, &result);
-  return result;
-}
-
 NGPaintFragment* NGPaintFragmentTraversal::PreviousLineOf(
     const NGPaintFragment& line) {
   DCHECK(line.PhysicalFragment().IsLineBox());
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
index 4923bc0..f78b27b 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
@@ -11,7 +11,6 @@
 
 namespace blink {
 
-class LayoutObject;
 class NGPaintFragment;
 
 // Used for return value of traversing fragment tree.
@@ -147,19 +146,10 @@
   // Returns inclusive ancestors.
   static AncestorRange InclusiveAncestorsOf(const NGPaintFragment&);
 
-  // Returns descendants without paint layer in preorder.
-  static Vector<NGPaintFragmentWithContainerOffset> DescendantsOf(
-      const NGPaintFragment&);
-
   // Returns inline descendants in preorder.
   static Vector<NGPaintFragmentWithContainerOffset> InlineDescendantsOf(
       const NGPaintFragment&);
 
-  // Deprecated. Use NGPaintFragment::InlineFragmentsFor() instead.
-  static Vector<NGPaintFragmentWithContainerOffset> SelfFragmentsOf(
-      const NGPaintFragment&,
-      const LayoutObject* target);
-
   // Returns the line box paint fragment of |line|. |line| itself must be the
   // paint fragment of a line box.
   static NGPaintFragment* PreviousLineOf(const NGPaintFragment& line);
diff --git a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
index 29488d2..9461ae39 100644
--- a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
+++ b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
@@ -15,7 +15,12 @@
   DCHECK(execution_context_->IsContextThread());
 }
 
-const KURL& FetchClientSettingsObjectImpl::BaseURL() const {
+const KURL& FetchClientSettingsObjectImpl::GlobalObjectUrl() const {
+  DCHECK(execution_context_->IsContextThread());
+  return execution_context_->Url();
+}
+
+const KURL& FetchClientSettingsObjectImpl::BaseUrl() const {
   DCHECK(execution_context_->IsContextThread());
   return execution_context_->BaseURL();
 }
diff --git a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
index 13b3a5e7..db59eda 100644
--- a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
+++ b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
@@ -31,7 +31,8 @@
   explicit FetchClientSettingsObjectImpl(ExecutionContext&);
   ~FetchClientSettingsObjectImpl() override = default;
 
-  const KURL& BaseURL() const override;
+  const KURL& GlobalObjectUrl() const override;
+  const KURL& BaseUrl() const override;
   const SecurityOrigin* GetSecurityOrigin() const override;
   network::mojom::ReferrerPolicy GetReferrerPolicy() const override;
   const String GetOutgoingReferrer() const override;
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.cc b/third_party/blink/renderer/core/script/modulator_impl_base.cc
index b49b7a9..fd31ab3f 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -224,7 +224,8 @@
 ModuleImportMeta ModulatorImplBase::HostGetImportMetaProperties(
     ScriptModule record) const {
   // <spec step="1">Let module script be moduleRecord.[[HostDefined]].</spec>
-  ModuleScript* module_script = script_module_resolver_->GetHostDefined(record);
+  const ModuleScript* module_script =
+      script_module_resolver_->GetHostDefined(record);
   DCHECK(module_script);
 
   // <spec step="2">Let urlString be module script's base URL,
diff --git a/third_party/blink/renderer/core/script/module_map_test.cc b/third_party/blink/renderer/core/script/module_map_test.cc
index 9311745..2f456c9 100644
--- a/third_party/blink/renderer/core/script/module_map_test.cc
+++ b/third_party/blink/renderer/core/script/module_map_test.cc
@@ -56,15 +56,15 @@
     return register_module_script_call_count_;
   }
 
-  void RegisterModuleScript(ModuleScript*) override {
+  void RegisterModuleScript(const ModuleScript*) override {
     register_module_script_call_count_++;
   }
 
-  void UnregisterModuleScript(ModuleScript*) override {
+  void UnregisterModuleScript(const ModuleScript*) override {
     FAIL() << "UnregisterModuleScript shouldn't be called in ModuleMapTest";
   }
 
-  ModuleScript* GetHostDefined(const ScriptModule&) const override {
+  const ModuleScript* GetHostDefined(const ScriptModule&) const override {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/script/module_script.cc b/third_party/blink/renderer/core/script/module_script.cc
index da03e43..7502d49 100644
--- a/third_party/blink/renderer/core/script/module_script.cc
+++ b/third_party/blink/renderer/core/script/module_script.cc
@@ -204,7 +204,7 @@
 }
 
 KURL ModuleScript::ResolveModuleSpecifier(const String& module_request,
-                                          String* failure_reason) {
+                                          String* failure_reason) const {
   auto found = specifier_to_url_cache_.find(module_request);
   if (found != specifier_to_url_cache_.end())
     return found->value;
diff --git a/third_party/blink/renderer/core/script/module_script.h b/third_party/blink/renderer/core/script/module_script.h
index 473de68aa..382def8 100644
--- a/third_party/blink/renderer/core/script/module_script.h
+++ b/third_party/blink/renderer/core/script/module_script.h
@@ -72,7 +72,7 @@
 
   // Resolves a module specifier with the module script's base URL.
   KURL ResolveModuleSpecifier(const String& module_request,
-                              String* failure_reason = nullptr);
+                              String* failure_reason = nullptr) const;
 
   void Trace(blink::Visitor*) override;
   const char* NameInHeapSnapshot() const override { return "ModuleScript"; }
@@ -148,7 +148,7 @@
   const ParkableString source_text_;
 
   const TextPosition start_position_;
-  HashMap<String, KURL> specifier_to_url_cache_;
+  mutable HashMap<String, KURL> specifier_to_url_cache_;
   KURL source_url_;
 };
 
diff --git a/third_party/blink/renderer/core/script/script_module_resolver.h b/third_party/blink/renderer/core/script/script_module_resolver.h
index 56c83bfc..ddc63864 100644
--- a/third_party/blink/renderer/core/script/script_module_resolver.h
+++ b/third_party/blink/renderer/core/script/script_module_resolver.h
@@ -31,13 +31,13 @@
   // Notifies the ScriptModuleResolver that a ModuleScript exists.
   // This hook gives a chance for the resolver impl to populate module record
   // identifier -> ModuleScript mapping entry.
-  virtual void RegisterModuleScript(ModuleScript*) = 0;
+  virtual void RegisterModuleScript(const ModuleScript*) = 0;
 
   // Notifies the ScriptModuleResolver to clear its ModuleScript mapping.
-  virtual void UnregisterModuleScript(ModuleScript*) = 0;
+  virtual void UnregisterModuleScript(const ModuleScript*) = 0;
 
   // Corresponds to the spec concept "[[HostDefined]]".
-  virtual ModuleScript* GetHostDefined(const ScriptModule&) const = 0;
+  virtual const ModuleScript* GetHostDefined(const ScriptModule&) const = 0;
 
   // Implements "Runtime Semantics: HostResolveImportedModule"
   // https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule
diff --git a/third_party/blink/renderer/core/script/script_module_resolver_impl.cc b/third_party/blink/renderer/core/script/script_module_resolver_impl.cc
index 3a94588..a31ef938 100644
--- a/third_party/blink/renderer/core/script/script_module_resolver_impl.cc
+++ b/third_party/blink/renderer/core/script/script_module_resolver_impl.cc
@@ -11,7 +11,7 @@
 namespace blink {
 
 void ScriptModuleResolverImpl::RegisterModuleScript(
-    ModuleScript* module_script) {
+    const ModuleScript* module_script) {
   DCHECK(module_script);
   if (module_script->Record().IsNull())
     return;
@@ -27,7 +27,7 @@
 }
 
 void ScriptModuleResolverImpl::UnregisterModuleScript(
-    ModuleScript* module_script) {
+    const ModuleScript* module_script) {
   DCHECK(module_script);
   if (module_script->Record().IsNull())
     return;
@@ -40,7 +40,7 @@
   record_to_module_script_map_.erase(module_script->Record());
 }
 
-ModuleScript* ScriptModuleResolverImpl::GetHostDefined(
+const ModuleScript* ScriptModuleResolverImpl::GetHostDefined(
     const ScriptModule& record) const {
   const auto it = record_to_module_script_map_.find(record);
   CHECK_NE(it, record_to_module_script_map_.end())
@@ -61,7 +61,7 @@
 
   // <spec step="1">Let referencing script be
   // referencingScriptOrModule.[[HostDefined]].</spec>
-  ModuleScript* referrer_module = GetHostDefined(referrer);
+  const ModuleScript* referrer_module = GetHostDefined(referrer);
 
   // <spec step="2">Let moduleMap be referencing script's settings object's
   // module map.</spec>
diff --git a/third_party/blink/renderer/core/script/script_module_resolver_impl.h b/third_party/blink/renderer/core/script/script_module_resolver_impl.h
index e4fa735..6a22cd6 100644
--- a/third_party/blink/renderer/core/script/script_module_resolver_impl.h
+++ b/third_party/blink/renderer/core/script/script_module_resolver_impl.h
@@ -42,9 +42,9 @@
  private:
   // Implements ScriptModuleResolver:
 
-  void RegisterModuleScript(ModuleScript*) final;
-  void UnregisterModuleScript(ModuleScript*) final;
-  ModuleScript* GetHostDefined(const ScriptModule&) const final;
+  void RegisterModuleScript(const ModuleScript*) final;
+  void UnregisterModuleScript(const ModuleScript*) final;
+  const ModuleScript* GetHostDefined(const ScriptModule&) const final;
 
   // Implements "Runtime Semantics: HostResolveImportedModule" per HTML spec.
   // https://html.spec.whatwg.org/C/#hostresolveimportedmodule(referencingscriptormodule,-specifier))
@@ -60,7 +60,8 @@
   // should not use ScriptModule as the map key. We currently rely on Detach()
   // to clear the refs, but we should implement a key type which keeps a
   // weak-ref to v8::Module.
-  HeapHashMap<ScriptModule, Member<ModuleScript>> record_to_module_script_map_;
+  HeapHashMap<ScriptModule, Member<const ModuleScript>>
+      record_to_module_script_map_;
   Member<Modulator> modulator_;
 };
 
diff --git a/third_party/blink/renderer/core/script/worklet_modulator_impl.cc b/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
index 90ca676..e24441f4 100644
--- a/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
+++ b/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
@@ -31,7 +31,8 @@
 }
 
 V8CacheOptions WorkletModulatorImpl::GetV8CacheOptions() const {
-  return kV8CacheOptionsDefault;
+  auto* scope = To<WorkletGlobalScope>(GetExecutionContext());
+  return scope->GetV8CacheOptions();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.cc b/third_party/blink/renderer/core/testing/dummy_modulator.cc
index ce5f4e84..ac66f19 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.cc
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -17,10 +17,10 @@
 
   // We ignore {Unr,R}egisterModuleScript() calls caused by
   // ModuleScript::CreateForTest().
-  void RegisterModuleScript(ModuleScript*) override {}
-  void UnregisterModuleScript(ModuleScript*) override {}
+  void RegisterModuleScript(const ModuleScript*) override {}
+  void UnregisterModuleScript(const ModuleScript*) override {}
 
-  ModuleScript* GetHostDefined(const ScriptModule&) const override {
+  const ModuleScript* GetHostDefined(const ScriptModule&) const override {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 78a4ad76..926ed473 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -234,7 +234,7 @@
     ScriptController()->Evaluate(
         ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
                          handler, response_url),
-        sanitize_script_errors, &error_event, v8_cache_options_);
+        sanitize_script_errors, &error_event, GetV8CacheOptions());
     if (error_event) {
       ScriptController()->RethrowExceptionFromImportedScript(error_event,
                                                              exception_state);
@@ -487,7 +487,7 @@
   bool success = ScriptController()->Evaluate(
       ScriptSourceCode(source_code, handler, script_url),
       SanitizeScriptErrors::kDoNotSanitize, nullptr /* error_event */,
-      v8_cache_options_);
+      GetV8CacheOptions());
   ReportingProxy().DidEvaluateClassicScript(success);
 }
 
@@ -497,6 +497,7 @@
     base::TimeTicks time_origin)
     : WorkerOrWorkletGlobalScope(
           thread->GetIsolate(),
+          creation_params->v8_cache_options,
           creation_params->worker_clients,
           std::move(creation_params->web_worker_fetch_context),
           thread->GetWorkerReportingProxy()),
@@ -504,7 +505,6 @@
       script_type_(creation_params->script_type),
       user_agent_(creation_params->user_agent),
       parent_devtools_token_(creation_params->parent_devtools_token),
-      v8_cache_options_(creation_params->v8_cache_options),
       thread_(thread),
       timers_(GetTaskRunner(TaskType::kJavascriptTimer)),
       time_origin_(time_origin),
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h
index def09af..192a99e 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -33,7 +33,6 @@
 #include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
 #include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -180,8 +179,6 @@
 
   TrustedTypePolicyFactory* trustedTypes();
 
-  V8CacheOptions GetV8CacheOptions() const { return v8_cache_options_; }
-
  protected:
   WorkerGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
                     WorkerThread*,
@@ -246,7 +243,6 @@
   const mojom::ScriptType script_type_;
   const String user_agent_;
   const base::UnguessableToken parent_devtools_token_;
-  const V8CacheOptions v8_cache_options_;
   std::unique_ptr<WorkerSettings> worker_settings_;
 
   mutable Member<WorkerLocation> location_;
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 055824a5..8d5eec51 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -30,6 +30,7 @@
 
 WorkerOrWorkletGlobalScope::WorkerOrWorkletGlobalScope(
     v8::Isolate* isolate,
+    V8CacheOptions v8_cache_options,
     WorkerClients* worker_clients,
     scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context,
     WorkerReportingProxy& reporting_proxy)
@@ -38,6 +39,7 @@
       web_worker_fetch_context_(std::move(web_worker_fetch_context)),
       script_controller_(
           WorkerOrWorkletScriptController::Create(this, isolate)),
+      v8_cache_options_(v8_cache_options),
       reporting_proxy_(reporting_proxy),
       used_features_(static_cast<int>(WebFeature::kNumberOfFeatures)) {
   if (worker_clients_)
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
index bf91bba..8765c8e 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -43,6 +43,7 @@
   using SecurityContext::GetContentSecurityPolicy;
 
   WorkerOrWorkletGlobalScope(v8::Isolate*,
+                             V8CacheOptions,
                              WorkerClients*,
                              scoped_refptr<WebWorkerFetchContext>,
                              WorkerReportingProxy&);
@@ -115,6 +116,7 @@
   WorkerOrWorkletScriptController* ScriptController() {
     return script_controller_.Get();
   }
+  V8CacheOptions GetV8CacheOptions() const { return v8_cache_options_; }
 
   WorkerReportingProxy& ReportingProxy() { return reporting_proxy_; }
 
@@ -170,6 +172,7 @@
   Member<SubresourceFilter> subresource_filter_;
 
   Member<WorkerOrWorkletScriptController> script_controller_;
+  const V8CacheOptions v8_cache_options_;
 
   WorkerReportingProxy& reporting_proxy_;
 
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
index 3e30703..548bd87 100644
--- a/third_party/blink/renderer/core/workers/worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -63,6 +63,7 @@
     WorkerThread* worker_thread)
     : WorkerOrWorkletGlobalScope(
           isolate,
+          creation_params->v8_cache_options,
           creation_params->worker_clients,
           std::move(creation_params->web_worker_fetch_context),
           reporting_proxy),
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
index b3b9ad2..4474f22 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
@@ -985,6 +985,8 @@
   }
 
   QualifiedName q_name(prefix, local_name, adjusted_uri);
+  if (!prefix.IsEmpty() && adjusted_uri.IsEmpty())
+    q_name = QualifiedName(g_null_atom, prefix + ":" + local_name, g_null_atom);
   Element* new_element = current_node_->GetDocument().CreateElement(
       q_name,
       parsing_fragment_ ? CreateElementFlags::ByFragmentParser()
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc
new file mode 100644
index 0000000..f84b7fa
--- /dev/null
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc
@@ -0,0 +1,27 @@
+// 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/xml/parser/xml_document_parser.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+
+namespace blink {
+
+// crbug.com/932380
+TEST(XMLDocumentParserTest, NodeNamespaceWithParseError) {
+  auto& doc = *Document::CreateForTest();
+  doc.SetContent(
+      "<html xmlns='http://www.w3.org/1999/xhtml'>"
+      "<body><d:foo/></body></html>");
+
+  // The first child of <html> is <parseerror>, not <body>.
+  Element* foo = ToElement(doc.documentElement()->lastChild()->firstChild());
+  EXPECT_TRUE(foo->namespaceURI().IsNull()) << foo->namespaceURI();
+  EXPECT_TRUE(foo->prefix().IsNull()) << foo->prefix();
+  EXPECT_EQ(foo->localName(), "d:foo");
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index e0f82de..c5a68b2 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -322,7 +322,6 @@
     "peerconnection/rtc_quic_stream_test.cc",
     "peerconnection/rtc_quic_transport_test.cc",
     "peerconnection/rtc_quic_transport_test.h",
-    "picture_in_picture/html_video_element_picture_in_picture_test.cc",
     "picture_in_picture/picture_in_picture_controller_test.cc",
     "presentation/mock_presentation_service.h",
     "presentation/presentation_availability_state_test.cc",
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.h b/third_party/blink/renderer/modules/imagecapture/image_capture.h
index b2b9016..ea0caa46 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture.h
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture.h
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/modules/mediastream/media_track_constraint_set.h"
 #include "third_party/blink/renderer/modules/mediastream/media_track_settings.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/media_controls/BUILD.gn b/third_party/blink/renderer/modules/media_controls/BUILD.gn
index e7f5c2c..680021e 100644
--- a/third_party/blink/renderer/modules/media_controls/BUILD.gn
+++ b/third_party/blink/renderer/modules/media_controls/BUILD.gn
@@ -88,8 +88,6 @@
     "media_controls_resource_loader.h",
     "media_controls_rotate_to_fullscreen_delegate.cc",
     "media_controls_rotate_to_fullscreen_delegate.h",
-    "media_download_in_product_help_manager.cc",
-    "media_download_in_product_help_manager.h",
   ]
 
   deps = [
diff --git a/third_party/blink/renderer/modules/media_controls/DEPS b/third_party/blink/renderer/modules/media_controls/DEPS
index 6f2a859..8538c99 100644
--- a/third_party/blink/renderer/modules/media_controls/DEPS
+++ b/third_party/blink/renderer/modules/media_controls/DEPS
@@ -2,7 +2,6 @@
   "+mojo/public/cpp/bindings",
   "+services/device/public/mojom/constants.mojom-blink.h",
   "+services/device/public/mojom/screen_orientation.mojom-blink.h",
-  "+services/service_manager/public/cpp",
   "-third_party/blink/renderer/modules",
   "+third_party/blink/renderer/modules/device_orientation",
   "+third_party/blink/renderer/modules/media_controls",
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
index 91850219..1b91c6c 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
-#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
 #include "third_party/blink/renderer/platform/text/platform_locale.h"
 
 namespace blink {
@@ -64,16 +63,6 @@
   return IsOverflowElement() ? "DownloadOverflowButton" : "DownloadButton";
 }
 
-void MediaControlDownloadButtonElement::UpdateShownState() {
-  MediaControlInputElement::UpdateShownState();
-
-  if (!MediaControlsImpl::IsModern() &&
-      GetMediaControls().DownloadInProductHelp()) {
-    GetMediaControls().DownloadInProductHelp()->SetDownloadButtonVisibility(
-        IsWanted() && DoesFit());
-  }
-}
-
 void MediaControlDownloadButtonElement::DefaultEventHandler(Event& event) {
   const KURL& url = MediaElement().currentSrc();
   if ((event.type() == event_type_names::kClick ||
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h
index 991b212..0db13dea 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h
@@ -6,14 +6,13 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_DOWNLOAD_BUTTON_ELEMENT_H_
 
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
 
 namespace blink {
 
 class Event;
 class MediaControlsImpl;
 
-class MODULES_EXPORT MediaControlDownloadButtonElement final
+class MediaControlDownloadButtonElement final
     : public MediaControlInputElement {
  public:
   explicit MediaControlDownloadButtonElement(MediaControlsImpl&);
@@ -31,7 +30,6 @@
 
  protected:
   const char* GetNameForHistograms() const final;
-  void UpdateShownState() final;
 
  private:
   // This is used for UMA histogram (Media.Controls.Download). New values should
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h
index d3e5c257..5079d9d 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h
@@ -58,7 +58,7 @@
   void DefaultEventHandler(Event&) override;
 
   // Implements MediaControlElementBase.
-  void UpdateShownState() override;
+  void UpdateShownState() final;
 
   // Updates the value of the Text string shown in the overflow menu.
   void UpdateOverflowString();
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
index 7b08f01..882d66a 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
@@ -7,9 +7,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
-#include "third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h"
 #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
-#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
 
 namespace blink {
 
@@ -30,17 +28,6 @@
   return "OverflowButton";
 }
 
-void MediaControlOverflowMenuButtonElement::UpdateShownState() {
-  MediaControlInputElement::UpdateShownState();
-
-  if (MediaControlsImpl::IsModern() &&
-      GetMediaControls().DownloadInProductHelp()) {
-    GetMediaControls().DownloadInProductHelp()->SetDownloadButtonVisibility(
-        IsWanted() && DoesFit() &&
-        GetMediaControls().DownloadButton().ShouldDisplayDownloadButton());
-  }
-}
-
 void MediaControlOverflowMenuButtonElement::DefaultEventHandler(Event& event) {
   // Only respond to a click event if we are not disabled.
   if (!hasAttribute(html_names::kDisabledAttr) &&
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h
index bf65cb6..73aac4e 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h
@@ -24,7 +24,6 @@
 
  protected:
   const char* GetNameForHistograms() const override;
-  void UpdateShownState() final;
 
  private:
   void DefaultEventHandler(Event&) override;
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index fe64853..b8394904 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -86,7 +86,6 @@
 #include "third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h"
 #include "third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h"
 #include "third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h"
-#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
 #include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -454,16 +453,6 @@
             ToHTMLVideoElement(media_element));
   }
 
-  // Initialize download in-product-help for video elements if enabled.
-  if (media_element.GetDocument().GetSettings() &&
-      media_element.GetDocument()
-          .GetSettings()
-          ->GetMediaDownloadInProductHelpEnabled() &&
-      media_element.IsHTMLVideoElement()) {
-    controls->download_iph_manager_ =
-        MakeGarbageCollected<MediaDownloadInProductHelpManager>(*controls);
-  }
-
   MediaControlsResourceLoader::InjectMediaControlsUAStyleSheet();
 
   shadow_root.ParserAppendChild(controls);
@@ -1017,8 +1006,6 @@
   // Only make the controls visible if they won't get hidden by OnTimeUpdate.
   if (MediaElement().paused() || !ShouldHideMediaControls())
     MakeOpaque();
-  if (download_iph_manager_)
-    download_iph_manager_->SetControlsVisibility(true);
   if (loading_panel_)
     loading_panel_->OnControlsShown();
 
@@ -1037,8 +1024,6 @@
 
   if (overlay_play_button_)
     overlay_play_button_->SetIsWanted(false);
-  if (download_iph_manager_)
-    download_iph_manager_->SetControlsVisibility(false);
   if (loading_panel_)
     loading_panel_->OnControlsHidden();
 
@@ -1135,10 +1120,6 @@
   if (text_track_list_->IsWanted() || overflow_list_->IsWanted())
     return false;
 
-  // Don't hide the media controls while the in product help is showing.
-  if (download_iph_manager_ && download_iph_manager_->IsShowingInProductHelp())
-    return false;
-
   // Don't hide if we have accessiblity focus.
   if (panel_->KeepDisplayedForAccessibility())
     return false;
@@ -1460,9 +1441,6 @@
 
   MaybeRecordElementsDisplayed();
 
-  if (download_iph_manager_)
-    download_iph_manager_->UpdateInProductHelp();
-
   UpdateOverflowAndTrackListCSSClassForPip();
   UpdateOverflowMenuItemCSSClass();
 }
@@ -1641,7 +1619,8 @@
       is_mouse_over_controls_ = true;
       if (!MediaElement().paused()) {
         MakeOpaqueFromPointerEvent();
-        StartHideMediaControlsIfNecessary();
+        if (ShouldHideMediaControls())
+          StartHideMediaControlsTimer();
       }
     }
   } else if (event->type() == event_type_names::kPointerout) {
@@ -1909,9 +1888,6 @@
 
   if (IsVisible() && ShouldHideMediaControls())
     MakeTransparent();
-
-  if (download_iph_manager_)
-    download_iph_manager_->UpdateInProductHelp();
 }
 
 void MediaControlsImpl::OnDurationChange() {
@@ -1950,8 +1926,6 @@
 
 void MediaControlsImpl::OnPlaying() {
   timeline_->OnPlaying();
-  if (download_iph_manager_)
-    download_iph_manager_->SetIsPlaying(true);
 
   StartHideMediaControlsTimer();
   UpdateCSSClassFromState();
@@ -1965,9 +1939,6 @@
 
   StopHideMediaControlsTimer();
 
-  if (download_iph_manager_)
-    download_iph_manager_->SetIsPlaying(false);
-
   UpdateCSSClassFromState();
 }
 
@@ -2185,9 +2156,6 @@
     overlay_play_button_->SetDoesFit(does_fit);
   }
 
-  if (download_iph_manager_)
-    download_iph_manager_->UpdateInProductHelp();
-
   MaybeRecordElementsDisplayed();
 }
 
@@ -2318,11 +2286,6 @@
     ToggleTextTrackList();
 }
 
-void MediaControlsImpl::StartHideMediaControlsIfNecessary() {
-  if (ShouldHideMediaControls())
-    StartHideMediaControlsTimer();
-}
-
 void MediaControlsImpl::VolumeSliderWantedTimerFired(TimerBase*) {
   volume_slider_->OpenSlider();
   volume_control_container_->OpenContainer();
@@ -2368,11 +2331,6 @@
            volume_slider_->IsFocused() || mute_button_->IsFocused());
 }
 
-const MediaControlDownloadButtonElement& MediaControlsImpl::DownloadButton()
-    const {
-  return *download_button_;
-}
-
 const MediaControlOverflowMenuButtonElement& MediaControlsImpl::OverflowButton()
     const {
   return *overflow_menu_;
@@ -2382,14 +2340,6 @@
   return *overflow_menu_;
 }
 
-void MediaControlsImpl::DidDismissDownloadInProductHelp() {
-  StartHideMediaControlsIfNecessary();
-}
-
-MediaDownloadInProductHelpManager* MediaControlsImpl::DownloadInProductHelp() {
-  return download_iph_manager_;
-}
-
 void MediaControlsImpl::OnWaiting() {
   UpdateCSSClassFromState();
 }
@@ -2431,7 +2381,6 @@
   visitor->Trace(orientation_lock_delegate_);
   visitor->Trace(rotate_to_fullscreen_delegate_);
   visitor->Trace(display_cutout_delegate_);
-  visitor->Trace(download_iph_manager_);
   visitor->Trace(media_button_panel_);
   visitor->Trace(loading_panel_);
   visitor->Trace(display_cutout_fullscreen_button_);
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
index 6f7a7f35..8698db62 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -66,7 +66,6 @@
 class MediaControlToggleClosedCaptionsButtonElement;
 class MediaControlVolumeControlContainerElement;
 class MediaControlVolumeSliderElement;
-class MediaDownloadInProductHelpManager;
 class ShadowRoot;
 class TextTrack;
 
@@ -158,11 +157,8 @@
   void UpdateCurrentTimeDisplay();
 
   // Methods used for Download In-product help.
-  const MediaControlDownloadButtonElement& DownloadButton() const;
   const MediaControlOverflowMenuButtonElement& OverflowButton() const;
   MediaControlOverflowMenuButtonElement& OverflowButton();
-  void DidDismissDownloadInProductHelp();
-  MediaDownloadInProductHelpManager* DownloadInProductHelp();
 
   // Accessors for UI elements.
   const MediaControlCurrentTimeDisplayElement& CurrentTimeDisplay() const;
@@ -411,8 +407,6 @@
 
   bool keep_showing_until_timer_fires_ : 1;
 
-  Member<MediaDownloadInProductHelpManager> download_iph_manager_;
-
   bool is_acting_as_audio_controls_ = false;
 
   // Our best guess on whether the user is interacting with the controls via
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 0f6800d..0b92a45 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
@@ -40,7 +40,6 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h"
-#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
 #include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
@@ -89,22 +88,11 @@
  public:
   MockLayoutObject(Node* node) : LayoutObject(node) {}
 
-  void SetVisible(bool visible) { visible_ = visible; }
-
   const char* GetName() const override { return "MockLayoutObject"; }
   void UpdateLayout() override {}
   FloatRect LocalBoundingBoxRectForAccessibility() const override {
     return FloatRect();
   }
-  void AbsoluteQuads(Vector<FloatQuad>& quads,
-                     MapCoordinatesFlags mode) const override {
-    if (!visible_)
-      return;
-    quads.push_back(FloatQuad(FloatRect(0.f, 0.f, 10.f, 10.f)));
-  }
-
- private:
-  bool visible_ = false;
 };
 
 class StubLocalFrameClientForImpl : public EmptyLocalFrameClient {
@@ -136,13 +124,6 @@
   return nullptr;
 }
 
-MediaControlDownloadButtonElement& GetDownloadButton(
-    MediaControlsImpl& controls) {
-  Element* element = GetElementByShadowPseudoId(
-      controls, "-internal-media-controls-download-button");
-  return static_cast<MediaControlDownloadButtonElement&>(*element);
-}
-
 bool IsElementVisible(Element& element) {
   const CSSPropertyValueSet* inline_style = element.InlineStyle();
 
@@ -213,8 +194,6 @@
     FillWithEmptyClients(clients);
     clients.chrome_client = MakeGarbageCollected<MockChromeClientForImpl>();
     SetupPageWithClients(&clients, StubLocalFrameClientForImpl::Create());
-    GetDocument().GetSettings()->SetMediaDownloadInProductHelpEnabled(
-        EnableDownloadInProductHelp());
 
     GetDocument().write("<video controls>");
     HTMLVideoElement& video =
@@ -306,8 +285,6 @@
     return !remote_playback.availability_callbacks_.IsEmpty();
   }
 
-  virtual bool EnableDownloadInProductHelp() { return false; }
-
   const String GetDisplayedTime(MediaControlTimeDisplayElement* display) {
     return ToText(display->firstChild())->data();
   }
@@ -611,167 +588,6 @@
   EXPECT_FALSE(IsElementVisible(*download_button));
 }
 
-TEST_F(MediaControlsImplTest, DownloadButtonInProductHelpDisabled) {
-  EXPECT_FALSE(MediaControls().DownloadInProductHelp());
-}
-
-class MediaControlsImplPictureInPictureTest : public MediaControlsImplTest {
- public:
-  void SetUp() override {
-    RuntimeEnabledFeatures::SetPictureInPictureEnabled(true);
-    MediaControlsImplTest::SetUp();
-  }
-};
-
-TEST_F(MediaControlsImplPictureInPictureTest, PictureInPictureButtonVisible) {
-  EnsureSizing();
-
-  Element* picture_in_picture_button = GetElementByShadowPseudoId(
-      MediaControls(), "-internal-media-controls-picture-in-picture-button");
-  ASSERT_NE(nullptr, picture_in_picture_button);
-  ASSERT_FALSE(IsElementVisible(*picture_in_picture_button));
-
-  MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4");
-  test::RunPendingTasks();
-  SetReady();
-  test::RunPendingTasks();
-  SimulateLoadedMetadata();
-  ASSERT_TRUE(IsElementVisible(*picture_in_picture_button));
-
-  MediaControls().MediaElement().SetSrc("");
-  test::RunPendingTasks();
-  SimulateLoadedMetadata();
-  ASSERT_FALSE(IsElementVisible(*picture_in_picture_button));
-
-  MediaControls().MediaElement().SetBooleanAttribute(
-      html_names::kDisablepictureinpictureAttr, true);
-  MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4");
-  test::RunPendingTasks();
-  SetReady();
-  test::RunPendingTasks();
-  SimulateLoadedMetadata();
-  ASSERT_FALSE(IsElementVisible(*picture_in_picture_button));
-
-  MediaControls().MediaElement().SetBooleanAttribute(
-      html_names::kDisablepictureinpictureAttr, false);
-  test::RunPendingTasks();
-  ASSERT_TRUE(IsElementVisible(*picture_in_picture_button));
-}
-
-class MediaControlsImplInProductHelpTest : public MediaControlsImplTest {
- public:
-  void SetUp() override {
-    MediaControlsImplTest::SetUp();
-    ASSERT_TRUE(MediaControls().DownloadInProductHelp());
-  }
-
-  MediaDownloadInProductHelpManager& Manager() {
-    return *MediaControls().DownloadInProductHelp();
-  }
-
-  void Play() { MediaControls().OnPlaying(); }
-  void OnTimeUpdate() { MediaControls().OnTimeUpdate(); }
-
-  bool EnableDownloadInProductHelp() override { return true; }
-};
-
-TEST_F(MediaControlsImplInProductHelpTest, DownloadButtonInProductHelp_Button) {
-  EnsureSizing();
-
-  // Inject the LayoutObject for the button to override the rect returned in
-  // visual viewport.
-  MediaControlDownloadButtonElement& button =
-      GetDownloadButton(MediaControls());
-  MockLayoutObject layout_object(&button);
-  layout_object.SetVisible(true);
-  button.SetLayoutObject(&layout_object);
-
-  MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4");
-  test::RunPendingTasks();
-  SimulateLoadedMetadata();
-  Play();
-
-  // Load above should have made the button wanted, which should trigger showing
-  // in-product help.
-  EXPECT_TRUE(Manager().IsShowingInProductHelp());
-
-  // Disable the download button, which dismisses the in-product-help.
-  button.SetIsWanted(false);
-  EXPECT_FALSE(Manager().IsShowingInProductHelp());
-
-  // Toggle again. In-product help is shown only once.
-  button.SetIsWanted(true);
-  EXPECT_FALSE(Manager().IsShowingInProductHelp());
-
-  button.SetLayoutObject(nullptr);
-}
-
-TEST_F(MediaControlsImplInProductHelpTest,
-       DownloadButtonInProductHelp_ControlsVisibility) {
-  EnsureSizing();
-
-  // Inject the LayoutObject for the button to override the rect returned in
-  // visual viewport.
-  MediaControlDownloadButtonElement& button =
-      GetDownloadButton(MediaControls());
-  MockLayoutObject layout_object(&button);
-  layout_object.SetVisible(true);
-  button.SetLayoutObject(&layout_object);
-
-  // The in-product-help should not be shown while the controls are hidden.
-  MediaControls().Hide();
-  MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4");
-  test::RunPendingTasks();
-  SimulateLoadedMetadata();
-  Play();
-
-  ASSERT_TRUE(button.IsWanted());
-  EXPECT_FALSE(Manager().IsShowingInProductHelp());
-
-  // Showing the controls initiates showing in-product-help.
-  MediaControls().MaybeShow();
-  EXPECT_TRUE(Manager().IsShowingInProductHelp());
-
-  OnTimeUpdate();
-  EXPECT_TRUE(Manager().IsShowingInProductHelp());
-
-  // Hiding the controls dismissed in-product-help.
-  MediaControls().Hide();
-  EXPECT_FALSE(Manager().IsShowingInProductHelp());
-
-  button.SetLayoutObject(nullptr);
-}
-
-TEST_F(MediaControlsImplInProductHelpTest,
-       DownloadButtonInProductHelp_ButtonVisibility) {
-  EnsureSizing();
-
-  // Inject the LayoutObject for the button to override the rect returned in
-  // visual viewport.
-  MediaControlDownloadButtonElement& button =
-      GetDownloadButton(MediaControls());
-  MockLayoutObject layout_object(&button);
-  button.SetLayoutObject(&layout_object);
-
-  // The in-product-help should not be shown while the button is hidden.
-  layout_object.SetVisible(false);
-  MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4");
-  test::RunPendingTasks();
-  SimulateLoadedMetadata();
-  Play();
-
-  ASSERT_TRUE(button.IsWanted());
-  EXPECT_FALSE(Manager().IsShowingInProductHelp());
-
-  // Make the button visible to show in-product-help.
-  layout_object.SetVisible(true);
-  button.SetIsWanted(false);
-  button.SetIsWanted(true);
-  EXPECT_TRUE(Manager().IsShowingInProductHelp());
-
-  button.SetLayoutObject(nullptr);
-}
-
 TEST_F(MediaControlsImplTest, TimelineSeekToRoundedEnd) {
   EnsureSizing();
 
diff --git a/third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.cc b/third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.cc
deleted file mode 100644
index 4ee08861..0000000
--- a/third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
-
-#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
-#include "third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h"
-#include "third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h"
-#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
-
-namespace blink {
-
-MediaDownloadInProductHelpManager::MediaDownloadInProductHelpManager(
-    MediaControlsImpl& controls)
-    : controls_(controls) {}
-
-MediaDownloadInProductHelpManager::~MediaDownloadInProductHelpManager() =
-    default;
-
-void MediaDownloadInProductHelpManager::SetControlsVisibility(bool can_show) {
-  if (controls_can_show_ == can_show)
-    return;
-
-  controls_can_show_ = can_show;
-  StateUpdated();
-}
-
-void MediaDownloadInProductHelpManager::SetDownloadButtonVisibility(
-    bool can_show) {
-  if (button_can_show_ == can_show)
-    return;
-
-  button_can_show_ = can_show;
-  StateUpdated();
-}
-
-void MediaDownloadInProductHelpManager::SetIsPlaying(bool is_playing) {
-  if (is_playing_ == is_playing)
-    return;
-
-  is_playing_ = is_playing;
-  StateUpdated();
-}
-
-bool MediaDownloadInProductHelpManager::IsShowingInProductHelp() const {
-  return media_in_product_help_.is_bound();
-}
-
-void MediaDownloadInProductHelpManager::UpdateInProductHelp() {
-  if (!IsShowingInProductHelp() || !CanShowInProductHelp())
-    return;
-
-  MaybeDispatchDownloadInProductHelpTrigger(false);
-}
-
-void MediaDownloadInProductHelpManager::
-    MaybeDispatchDownloadInProductHelpTrigger(bool create) {
-  // Only show in-product-help once for an element.
-  if (create && media_download_in_product_trigger_observed_)
-    return;
-
-  auto* frame = controls_->GetDocument().GetFrame();
-  if (!frame)
-    return;
-
-  // If the button is not in the viewport, don't show the in-product-help.
-  IntRect button_rect =
-      controls_->IsModern()
-          ? controls_->OverflowButton().VisibleBoundsInVisualViewport()
-          : controls_->DownloadButton().VisibleBoundsInVisualViewport();
-  if (button_rect.IsEmpty())
-    return;
-
-  if (download_button_rect_ == button_rect && media_in_product_help_.is_bound())
-    return;
-
-  download_button_rect_ = button_rect;
-  media_download_in_product_trigger_observed_ = true;
-  if (!media_in_product_help_.is_bound()) {
-    frame->Client()->GetInterfaceProvider()->GetInterface(
-        mojo::MakeRequest(&media_in_product_help_));
-    media_in_product_help_.set_connection_error_handler(
-        WTF::Bind(&MediaDownloadInProductHelpManager::DismissInProductHelp,
-                  WrapWeakPersistent(this)));
-    DCHECK(media_in_product_help_.is_bound());
-  }
-
-  // MaybeShow should always make the controls visible since we early out if
-  // CanShow is false for the controls.
-  controls_->MaybeShow();
-  media_in_product_help_->ShowInProductHelpWidget(button_rect);
-}
-
-void MediaDownloadInProductHelpManager::StateUpdated() {
-  if (CanShowInProductHelp())
-    MaybeDispatchDownloadInProductHelpTrigger(true);
-  else
-    DismissInProductHelp();
-}
-
-bool MediaDownloadInProductHelpManager::CanShowInProductHelp() const {
-  // In-product help should only be shown if the controls can be made visible,
-  // the download button is wanted and the video is not paused.
-  return controls_can_show_ && button_can_show_ && is_playing_;
-}
-
-void MediaDownloadInProductHelpManager::DismissInProductHelp() {
-  download_button_rect_ = IntRect();
-  if (!media_in_product_help_.is_bound())
-    return;
-
-  media_in_product_help_.reset();
-  controls_->DidDismissDownloadInProductHelp();
-}
-
-void MediaDownloadInProductHelpManager::Trace(blink::Visitor* visitor) {
-  visitor->Trace(controls_);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h b/third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h
deleted file mode 100644
index ac8463b2..0000000
--- a/third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_DOWNLOAD_IN_PRODUCT_HELP_MANAGER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_DOWNLOAD_IN_PRODUCT_HELP_MANAGER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "third_party/blink/public/platform/media_download_in_product_help.mojom-blink.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-
-namespace blink {
-class MediaControlsImpl;
-
-class MODULES_EXPORT MediaDownloadInProductHelpManager final
-    : public GarbageCollectedFinalized<MediaDownloadInProductHelpManager> {
- public:
-  explicit MediaDownloadInProductHelpManager(MediaControlsImpl&);
-  virtual ~MediaDownloadInProductHelpManager();
-
-  void SetControlsVisibility(bool can_show);
-  void SetDownloadButtonVisibility(bool can_show);
-  void SetIsPlaying(bool is_playing);
-  bool IsShowingInProductHelp() const;
-  void UpdateInProductHelp();
-
-  virtual void Trace(blink::Visitor*);
-
- private:
-  void StateUpdated();
-  bool CanShowInProductHelp() const;
-  void MaybeDispatchDownloadInProductHelpTrigger(bool create);
-  void DismissInProductHelp();
-
-  Member<MediaControlsImpl> controls_;
-
-  bool controls_can_show_ = false;
-  bool button_can_show_ = false;
-  bool is_playing_ = false;
-  bool media_download_in_product_trigger_observed_ = false;
-  IntRect download_button_rect_;
-
-  mojom::blink::MediaDownloadInProductHelpPtr media_in_product_help_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaDownloadInProductHelpManager);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_DOWNLOAD_IN_PRODUCT_HELP_MANAGER_H_
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 0feebbf..d83eba2 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -674,7 +674,6 @@
           "permissions/permission_descriptor.idl",
           "permissions/push_permission_descriptor.idl",
           "picture_in_picture/enter_picture_in_picture_event_init.idl",
-          "picture_in_picture/picture_in_picture_control.idl",
           "presentation/presentation_connection_available_event_init.idl",
           "presentation/presentation_connection_close_event_init.idl",
           "push_messaging/push_event_init.idl",
diff --git a/third_party/blink/renderer/modules/notifications/notification.cc b/third_party/blink/renderer/modules/notifications/notification.cc
index 0b29ba52..8a8e0dc 100644
--- a/third_party/blink/renderer/modules/notifications/notification.cc
+++ b/third_party/blink/renderer/modules/notifications/notification.cc
@@ -155,21 +155,21 @@
       type_(type),
       state_(State::kLoading),
       data_(std::move(data)),
+      prepare_show_method_runner_(
+          context->GetTaskRunner(TaskType::kMiscPlatformAPI),
+          this,
+          &Notification::PrepareShow),
       listener_binding_(this) {}
 
 Notification::~Notification() = default;
 
 void Notification::SchedulePrepareShow() {
   DCHECK_EQ(state_, State::kLoading);
-  DCHECK(!prepare_show_method_runner_);
 
-  prepare_show_method_runner_ = AsyncMethodRunner<Notification>::Create(
-      this, &Notification::PrepareShow,
-      GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
-  prepare_show_method_runner_->RunAsync();
+  prepare_show_method_runner_.StartOneShot(TimeDelta(), FROM_HERE);
 }
 
-void Notification::PrepareShow() {
+void Notification::PrepareShow(TimerBase*) {
   DCHECK_EQ(state_, State::kLoading);
   if (!GetExecutionContext()->IsSecureContext()) {
     DispatchErrorEvent();
@@ -470,8 +470,8 @@
 
   state_ = State::kClosed;
 
-  if (prepare_show_method_runner_)
-    prepare_show_method_runner_->Stop();
+  if (prepare_show_method_runner_.IsActive())
+    prepare_show_method_runner_.Stop();
 
   if (loader_)
     loader_->Stop();
@@ -487,7 +487,6 @@
 }
 
 void Notification::Trace(blink::Visitor* visitor) {
-  visitor->Trace(prepare_show_method_runner_);
   visitor->Trace(loader_);
   EventTargetWithInlineData::Trace(visitor);
   ContextLifecycleObserver::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/notifications/notification.h b/third_party/blink/renderer/modules/notifications/notification.h
index 843b1933..469747101 100644
--- a/third_party/blink/renderer/modules/notifications/notification.h
+++ b/third_party/blink/renderer/modules/notifications/notification.h
@@ -44,8 +44,8 @@
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/vibration/navigator_vibration.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
 namespace blink {
@@ -168,7 +168,7 @@
 
   // Verifies that permission has been granted, then asynchronously starts
   // loading the resources associated with this notification.
-  void PrepareShow();
+  void PrepareShow(TimerBase* timer);
 
   // Shows the notification through the embedder using the loaded resources.
   void DidLoadResources(NotificationResourcesLoader* loader);
@@ -184,7 +184,7 @@
 
   String token_;
 
-  Member<AsyncMethodRunner<Notification>> prepare_show_method_runner_;
+  TaskRunnerTimer<Notification> prepare_show_method_runner_;
 
   Member<NotificationResourcesLoader> loader_;
 
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
index cac49b52..5144aa0 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
@@ -4,14 +4,11 @@
 
 #include "third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.h"
 
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
-#include "third_party/blink/public/platform/web_icon_sizes_parser.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
-#include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_control.h"
 #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h"
 #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_window.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -99,18 +96,6 @@
   return promise;
 }
 
-void HTMLVideoElementPictureInPicture::setPictureInPictureControls(
-    HTMLVideoElement& element,
-    const HeapVector<Member<PictureInPictureControl>>& controls) {
-  Document& document = element.GetDocument();
-
-  PictureInPictureControllerImpl& controller =
-      PictureInPictureControllerImpl::From(document);
-
-  controller.SetPictureInPictureCustomControls(
-      &element, ToPictureInPictureControlInfoVector(controls));
-}
-
 // static
 bool HTMLVideoElementPictureInPicture::FastHasAttribute(
     const QualifiedName& name,
@@ -140,37 +125,4 @@
   }
 }
 
-// static
-std::vector<PictureInPictureControlInfo>
-HTMLVideoElementPictureInPicture::ToPictureInPictureControlInfoVector(
-    const HeapVector<Member<PictureInPictureControl>>& controls) {
-  std::vector<PictureInPictureControlInfo> converted_controls;
-  for (const PictureInPictureControl* control : controls) {
-    PictureInPictureControlInfo current_converted_control;
-    HeapVector<Member<MediaImage>> current_icons = control->icons();
-
-    // Only two icons are supported, so cap the loop at running that many times
-    // to avoid potential problems.
-    for (wtf_size_t j = 0; j < current_icons.size() && j < 2; ++j) {
-      PictureInPictureControlInfo::Icon current_icon;
-      current_icon.src = KURL(WebString(current_icons[j]->src()));
-
-      WebVector<WebSize> sizes = WebIconSizesParser::ParseIconSizes(
-          WebString(current_icons[j]->sizes()));
-      std::vector<gfx::Size> converted_sizes;
-      for (size_t i = 0; i < sizes.size(); ++i)
-        converted_sizes.push_back(static_cast<gfx::Size>(sizes[i]));
-
-      current_icon.sizes = converted_sizes;
-      current_icon.type = WebString(current_icons[j]->type()).Utf8();
-      current_converted_control.icons.push_back(current_icon);
-    }
-
-    current_converted_control.id = WebString(control->id()).Utf8();
-    current_converted_control.label = WebString(control->label()).Utf8();
-    converted_controls.push_back(current_converted_control);
-  }
-  return converted_controls;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.h b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.h
index 13981d8..53a8a02 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.h
+++ b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.h
@@ -7,26 +7,19 @@
 
 #include "third_party/blink/renderer/core/dom/qualified_name.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
 
 class HTMLVideoElement;
 class ScriptPromise;
 class ScriptState;
-class PictureInPictureControl;
-struct PictureInPictureControlInfo;
 
-class MODULES_EXPORT HTMLVideoElementPictureInPicture {
+class HTMLVideoElementPictureInPicture {
   STATIC_ONLY(HTMLVideoElementPictureInPicture);
 
  public:
   static ScriptPromise requestPictureInPicture(ScriptState*, HTMLVideoElement&);
 
-  static void setPictureInPictureControls(
-      HTMLVideoElement&,
-      const HeapVector<Member<PictureInPictureControl>>&);
-
   static bool FastHasAttribute(const QualifiedName&, const HTMLVideoElement&);
 
   static void SetBooleanAttribute(const QualifiedName&,
@@ -37,12 +30,6 @@
                                          kEnterpictureinpicture)
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(leavepictureinpicture,
                                          kLeavepictureinpicture)
-  DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pictureinpicturecontrolclick,
-                                         kPictureinpicturecontrolclick)
-
-  static std::vector<PictureInPictureControlInfo>
-  ToPictureInPictureControlInfoVector(
-      const HeapVector<Member<PictureInPictureControl>>&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
index 18f4a01..a64f0f3d 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
+++ b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
@@ -8,11 +8,9 @@
 ]
 partial interface HTMLVideoElement {
     [RuntimeEnabled=PictureInPictureAPI, CallWith=ScriptState, Measure, NewObject] Promise<PictureInPictureWindow> requestPictureInPicture();
-    [RuntimeEnabled=PictureInPictureControl] void setPictureInPictureControls(sequence<PictureInPictureControl> pipControls);
 
     [RuntimeEnabled=PictureInPictureAPI] attribute EventHandler onenterpictureinpicture;
     [RuntimeEnabled=PictureInPictureAPI] attribute EventHandler onleavepictureinpicture;
-    [RuntimeEnabled=PictureInPictureControl] attribute EventHandler onpictureinpicturecontrolclick;
 
     [OriginTrialEnabled=AutoPictureInPicture, CEReactions, Measure, Reflect] attribute boolean autoPictureInPicture;
     [RuntimeEnabled=PictureInPictureAPI, CEReactions, Measure, Reflect] attribute boolean disablePictureInPicture;
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture_test.cc b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture_test.cc
deleted file mode 100644
index 4871569..0000000
--- a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture_test.cc
+++ /dev/null
@@ -1,113 +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.
-
-#include "third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
-#include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_control.h"
-
-namespace blink {
-
-TEST(HTMLVideoElementPictureInPictureTest,
-     ToPictureInPictureControlInfoVector_Basic) {
-  MediaImage* image = MediaImage::Create();
-  image->setSrc("https://dummyimage.com/144x144/7d727d/fafafa.gif");
-  image->setSizes("144x144");
-  image->setType("image/gif");
-  HeapVector<Member<MediaImage>> images;
-  images.push_back(image);
-
-  PictureInPictureControl* control = PictureInPictureControl::Create();
-  control->setId(WTF::String("Test id"));
-  control->setLabel(WTF::String("Test label"));
-  control->setIcons(images);
-
-  HeapVector<Member<PictureInPictureControl>> controls;
-  controls.push_back(control);
-
-  std::vector<PictureInPictureControlInfo> converted_controls =
-      HTMLVideoElementPictureInPicture::ToPictureInPictureControlInfoVector(
-          controls);
-
-  ASSERT_EQ(1U, converted_controls.size());
-  EXPECT_EQ(144, converted_controls[0].icons[0].sizes[0].width());
-  EXPECT_EQ(144, converted_controls[0].icons[0].sizes[0].height());
-}
-
-TEST(HTMLVideoElementPictureInPictureTest,
-     ToPictureInPictureControlInfoVector_MultipleImages) {
-  MediaImage* image = MediaImage::Create();
-  image->setSrc("https://dummyimage.com/144x144/7d727d/fafafa.gif");
-  image->setSizes("144x144");
-  image->setType("image/gif");
-
-  MediaImage* image2 = MediaImage::Create();
-  image2->setSrc("https://dummyimage.com/96x96/7d727d/fafafa.gif");
-  image2->setSizes("96x96");
-  image2->setType("image/gif");
-
-  HeapVector<Member<MediaImage>> images;
-  images.push_back(image);
-  images.push_back(image2);
-
-  PictureInPictureControl* control = PictureInPictureControl::Create();
-  control->setId(WTF::String("Test id"));
-  control->setLabel(WTF::String("Test label"));
-  control->setIcons(images);
-
-  HeapVector<Member<PictureInPictureControl>> controls;
-  controls.push_back(control);
-
-  std::vector<PictureInPictureControlInfo> converted_controls =
-      HTMLVideoElementPictureInPicture::ToPictureInPictureControlInfoVector(
-          controls);
-
-  ASSERT_EQ(1U, converted_controls.size());
-  EXPECT_EQ(144, converted_controls[0].icons[0].sizes[0].width());
-  EXPECT_EQ(144, converted_controls[0].icons[0].sizes[0].height());
-  EXPECT_EQ(96, converted_controls[0].icons[1].sizes[0].width());
-  EXPECT_EQ(96, converted_controls[0].icons[1].sizes[0].height());
-}
-
-TEST(HTMLVideoElementPictureInPictureTest,
-     ToPictureInPictureControlInfoVector_InvalidSize) {
-  MediaImage* image = MediaImage::Create();
-  image->setSrc("https://dummyimage.com/144x144/7d727d/fafafa.gif");
-  image->setSizes("144");
-  image->setType("image/gif");
-  HeapVector<Member<MediaImage>> images;
-  images.push_back(image);
-
-  PictureInPictureControl* control = PictureInPictureControl::Create();
-  control->setId(WTF::String("Test id"));
-  control->setLabel(WTF::String("Test label"));
-  control->setIcons(images);
-
-  HeapVector<Member<PictureInPictureControl>> controls;
-  controls.push_back(control);
-
-  std::vector<PictureInPictureControlInfo> converted_controls =
-      HTMLVideoElementPictureInPicture::ToPictureInPictureControlInfoVector(
-          controls);
-
-  ASSERT_EQ(1U, converted_controls.size());
-
-  ASSERT_EQ(1U, converted_controls[0].icons.size());
-
-  EXPECT_EQ(0U, converted_controls[0].icons[0].sizes.size());
-}
-
-TEST(HTMLVideoElementPictureInPictureTest,
-     ToPictureInPictureControlInfoVector_Empty) {
-  HeapVector<Member<PictureInPictureControl>> controls;
-
-  std::vector<PictureInPictureControlInfo> converted_controls =
-      HTMLVideoElementPictureInPicture::ToPictureInPictureControlInfoVector(
-          controls);
-
-  EXPECT_EQ(0U, converted_controls.size());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_control.idl b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_control.idl
deleted file mode 100644
index 964c0cdb..0000000
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_control.idl
+++ /dev/null
@@ -1,9 +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.
-
-dictionary PictureInPictureControl {
-    DOMString id = "";
-    DOMString label = "";
-    sequence<MediaImage> icons = [];
-};
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index 4da05d4..1d1aa48 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/events/picture_in_picture_control_event.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
@@ -125,10 +124,6 @@
       WTF::Bind(&PictureInPictureControllerImpl::OnEnteredPictureInPicture,
                 WrapPersistent(this), WrapPersistent(element),
                 WrapPersistent(resolver)));
-
-  // If the media element has already been given custom controls, this will
-  // ensure that they get set. Otherwise, this will do nothing.
-  element->SendCustomControlsToPipWindow();
 }
 
 void PictureInPictureControllerImpl::OnEnteredPictureInPicture(
@@ -186,14 +181,6 @@
   delegate_binding_.Close();
 }
 
-void PictureInPictureControllerImpl::SetPictureInPictureCustomControls(
-    HTMLVideoElement* element,
-    const std::vector<PictureInPictureControlInfo>& controls) {
-  element->SetPictureInPictureCustomControls(controls);
-  if (IsPictureInPictureElement(element))
-    element->SendCustomControlsToPipWindow();
-}
-
 void PictureInPictureControllerImpl::OnExitedPictureInPicture(
     ScriptPromiseResolver* resolver) {
   DCHECK(GetSupplementable());
@@ -218,22 +205,6 @@
     resolver->Resolve();
 }
 
-void PictureInPictureControllerImpl::OnPictureInPictureControlClicked(
-    const WebString& control_id) {
-  DCHECK(GetSupplementable());
-
-  // Bail out if document is not active.
-  if (!GetSupplementable()->IsActive())
-    return;
-
-  if (RuntimeEnabledFeatures::PictureInPictureControlEnabled() &&
-      picture_in_picture_element_) {
-    picture_in_picture_element_->DispatchEvent(
-        *PictureInPictureControlEvent::Create(
-            event_type_names::kPictureinpicturecontrolclick, control_id));
-  }
-}
-
 Element* PictureInPictureControllerImpl::PictureInPictureElement() const {
   return picture_in_picture_element_;
 }
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
index f0e16f1f..ae99a72 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
@@ -68,9 +68,6 @@
   void ExitPictureInPicture(HTMLVideoElement*, ScriptPromiseResolver*) override;
   void AddToAutoPictureInPictureElementsList(HTMLVideoElement*) override;
   void RemoveFromAutoPictureInPictureElementsList(HTMLVideoElement*) override;
-  void SetPictureInPictureCustomControls(
-      HTMLVideoElement*,
-      const std::vector<PictureInPictureControlInfo>&) override;
   Status IsElementAllowed(const HTMLVideoElement&) const override;
   bool IsPictureInPictureElement(const Element*) const override;
   void OnPictureInPictureStateChange() override;
@@ -96,7 +93,6 @@
                                  ScriptPromiseResolver*,
                                  const WebSize& picture_in_picture_window_size);
   void OnExitedPictureInPicture(ScriptPromiseResolver*) override;
-  void OnPictureInPictureControlClicked(const WebString& control_id) override;
 
   // Makes sure the `picture_in_picture_service_` is set. Returns whether it was
   // initialized successfully.
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index a7c6a23..bc380ad 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1561,16 +1561,33 @@
   GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
   if (!CopyRenderingResultsFromDrawingBuffer(Host()->ResourceProvider(),
                                              source_buffer)) {
-    // Currently, copyRenderingResultsFromDrawingBuffer is expected to always
+    // Currently, CopyRenderingResultsFromDrawingBuffer is expected to always
     // succeed because cases where canvas()-buffer() is not accelerated are
-    // handle before reaching this point.  If that assumption ever stops holding
-    // true, we may need to implement a fallback right here.
+    // handled before reaching this point.  If that assumption ever stops
+    // holding true, we may need to implement a fallback right here.
     NOTREACHED();
     return false;
   }
   return true;
 }
 
+void WebGLRenderingContextBase::ProvideBackBufferToResourceProvider() const {
+  if (isContextLost())
+    return;
+
+  DCHECK(Host()->ResourceProvider());
+  if (Host()->ResourceProvider()->Size() != GetDrawingBuffer()->Size())
+    Host()->DiscardResourceProvider();
+
+  CanvasResourceProvider* resource_provider =
+      Host()->GetOrCreateCanvasResourceProvider(kPreferAcceleration);
+  if (!resource_provider || !resource_provider->IsAccelerated())
+    return;
+
+  resource_provider->ImportResource(
+      GetDrawingBuffer()->AsCanvasResource(resource_provider->CreateWeakPtr()));
+}
+
 bool WebGLRenderingContextBase::ContextCreatedOnXRCompatibleAdapter() {
   // TODO(http://crbug.com/876140) Determine if device is compatible with
   // current context.
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 5f6bc49..9d08f0c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -565,6 +565,7 @@
 
   scoped_refptr<Uint8Array> PaintRenderingResultsToDataArray(
       SourceDrawingBuffer) override;
+  void ProvideBackBufferToResourceProvider() const override;
 
   unsigned MaxVertexAttribs() const { return max_vertex_attribs_; }
 
diff --git a/third_party/blink/renderer/modules/webmidi/midi_access.cc b/third_party/blink/renderer/modules/webmidi/midi_access.cc
index ece5db01..88c991b 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_access.cc
+++ b/third_party/blink/renderer/modules/webmidi/midi_access.cc
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/modules/webmidi/midi_output.h"
 #include "third_party/blink/renderer/modules/webmidi/midi_output_map.h"
 #include "third_party/blink/renderer/modules/webmidi/midi_port.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 5e7c5535..e477fbe5 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -455,7 +455,7 @@
         GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
     if (!binding_.is_bound()) {
       device::mojom::blink::VRServiceClientPtr client;
-      binding_.Bind(mojo::MakeRequest(&client, task_runner));
+      binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
       service_->SetClient(std::move(client));
     }
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index bc84c2a8..ae2ac6f5 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -305,7 +305,6 @@
     "animation/timing_function.cc",
     "animation/timing_function.h",
     "async_file_system_callbacks.h",
-    "async_method_runner.h",
     "audio/android/fft_frame_open_maxdl_android.cc",
     "audio/audio_array.h",
     "audio/audio_bus.cc",
@@ -1703,6 +1702,7 @@
     "fonts/shaping/harfbuzz_shaper_test.cc",
     "fonts/shaping/run_segmenter_test.cc",
     "fonts/shaping/shape_result_bloberizer_test.cc",
+    "fonts/shaping/shape_result_test.cc",
     "fonts/shaping/shape_result_view_test.cc",
     "fonts/shaping/shaping_line_breaker_test.cc",
     "fonts/small_caps_iterator_test.cc",
diff --git a/third_party/blink/renderer/platform/animation/DEPS b/third_party/blink/renderer/platform/animation/DEPS
index 7ec486a..432493e 100644
--- a/third_party/blink/renderer/platform/animation/DEPS
+++ b/third_party/blink/renderer/platform/animation/DEPS
@@ -2,6 +2,10 @@
     # Don't depend on platform/.
     "-third_party/blink/renderer/platform",
 
+    # We are moving from WTF_MAKE_NONCOPYABLE to DISALLOW_COPY_AND_ASSIGN.
+    # Stop new dependencies on WTF_MAKE_NONCOPYABLE.
+    "-third_party/blink/renderer/platform/wtf/noncopyable.h",
+
     # Module.
     "+third_party/blink/renderer/platform/animation",
 
diff --git a/third_party/blink/renderer/platform/animation/compositor_animation.h b/third_party/blink/renderer/platform/animation/compositor_animation.h
index 0d233ea..0f533b472c 100644
--- a/third_party/blink/renderer/platform/animation/compositor_animation.h
+++ b/third_party/blink/renderer/platform/animation/compositor_animation.h
@@ -6,6 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_ANIMATION_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
 #include "cc/animation/animation_delegate.h"
@@ -14,7 +16,6 @@
 #include "cc/animation/worklet_animation.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace cc {
@@ -30,8 +31,6 @@
 
 // A compositor representation for Animation.
 class PLATFORM_EXPORT CompositorAnimation : public cc::AnimationDelegate {
-  WTF_MAKE_NONCOPYABLE(CompositorAnimation);
-
  public:
   static std::unique_ptr<CompositorAnimation> Create();
   static std::unique_ptr<CompositorAnimation> CreateWorkletAnimation(
@@ -85,6 +84,8 @@
 
   scoped_refptr<cc::SingleKeyframeEffectAnimation> animation_;
   CompositorAnimationDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorAnimation);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_animation_timeline.h b/third_party/blink/renderer/platform/animation/compositor_animation_timeline.h
index 1d0ab86..96169b8 100644
--- a/third_party/blink/renderer/platform/animation/compositor_animation_timeline.h
+++ b/third_party/blink/renderer/platform/animation/compositor_animation_timeline.h
@@ -7,11 +7,11 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "cc/animation/animation_timeline.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -19,8 +19,6 @@
 
 // A compositor representation for cc::AnimationTimeline.
 class PLATFORM_EXPORT CompositorAnimationTimeline {
-  WTF_MAKE_NONCOPYABLE(CompositorAnimationTimeline);
-
  public:
   static std::unique_ptr<CompositorAnimationTimeline> Create() {
     return base::WrapUnique(new CompositorAnimationTimeline());
@@ -37,6 +35,8 @@
   CompositorAnimationTimeline();
 
   scoped_refptr<cc::AnimationTimeline> animation_timeline_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorAnimationTimeline);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h b/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h
index d7769ad..ac2d4d2f 100644
--- a/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h
+++ b/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h
@@ -7,12 +7,12 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h"
 #include "third_party/blink/renderer/platform/animation/timing_function.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace cc {
 class KeyframedFilterAnimationCurve;
@@ -27,8 +27,6 @@
 // A keyframed filter animation curve.
 class PLATFORM_EXPORT CompositorFilterAnimationCurve
     : public CompositorAnimationCurve {
-  WTF_MAKE_NONCOPYABLE(CompositorFilterAnimationCurve);
-
  public:
   static std::unique_ptr<CompositorFilterAnimationCurve> Create() {
     return base::WrapUnique(new CompositorFilterAnimationCurve());
@@ -46,6 +44,8 @@
   CompositorFilterAnimationCurve();
 
   std::unique_ptr<cc::KeyframedFilterAnimationCurve> curve_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorFilterAnimationCurve);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h b/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h
index fca7bbbd..a1597ae 100644
--- a/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h
+++ b/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h
@@ -5,19 +5,17 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_FILTER_KEYFRAME_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_FILTER_KEYFRAME_H_
 
+#include "base/macros.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class TimingFunction;
 
 class PLATFORM_EXPORT CompositorFilterKeyframe : public CompositorKeyframe {
-  WTF_MAKE_NONCOPYABLE(CompositorFilterKeyframe);
-
  public:
   CompositorFilterKeyframe(double time,
                            CompositorFilterOperations value,
@@ -32,6 +30,8 @@
 
  private:
   std::unique_ptr<cc::FilterKeyframe> filter_keyframe_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorFilterKeyframe);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h b/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h
index 97bb9d5..050b078 100644
--- a/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h
+++ b/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h
@@ -7,13 +7,13 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_float_keyframe.h"
 #include "third_party/blink/renderer/platform/animation/timing_function.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace cc {
@@ -29,8 +29,6 @@
 // A keyframed float animation curve.
 class PLATFORM_EXPORT CompositorFloatAnimationCurve
     : public CompositorAnimationCurve {
-  WTF_MAKE_NONCOPYABLE(CompositorFloatAnimationCurve);
-
  public:
   static std::unique_ptr<CompositorFloatAnimationCurve> Create() {
     return base::WrapUnique(new CompositorFloatAnimationCurve());
@@ -60,6 +58,8 @@
       std::unique_ptr<cc::KeyframedFloatAnimationCurve>);
 
   std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorFloatAnimationCurve);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h b/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h
index e874084..2d38e036 100644
--- a/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h
+++ b/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h
@@ -5,18 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_FLOAT_KEYFRAME_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_FLOAT_KEYFRAME_H_
 
+#include "base/macros.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class TimingFunction;
 
 class PLATFORM_EXPORT CompositorFloatKeyframe : public CompositorKeyframe {
-  WTF_MAKE_NONCOPYABLE(CompositorFloatKeyframe);
-
  public:
   CompositorFloatKeyframe(double time, float value, const TimingFunction&);
   CompositorFloatKeyframe(std::unique_ptr<cc::FloatKeyframe>);
@@ -31,6 +29,8 @@
 
  private:
   std::unique_ptr<cc::FloatKeyframe> float_keyframe_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorFloatKeyframe);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h b/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
index b9a0db9..7bb2214 100644
--- a/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
+++ b/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
@@ -7,12 +7,12 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "cc/animation/keyframe_model.h"
 #include "third_party/blink/renderer/platform/animation/compositor_target_property.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace cc {
 class KeyframeModel;
@@ -25,8 +25,6 @@
 
 // A compositor driven animation.
 class PLATFORM_EXPORT CompositorKeyframeModel {
-  WTF_MAKE_NONCOPYABLE(CompositorKeyframeModel);
-
  public:
   using Direction = cc::KeyframeModel::Direction;
   using FillMode = cc::KeyframeModel::FillMode;
@@ -85,6 +83,8 @@
                           int group_id);
 
   std::unique_ptr<cc::KeyframeModel> keyframe_model_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorKeyframeModel);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
index 7b2dec4d..f1a8031 100644
--- a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
+++ b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
@@ -7,11 +7,11 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_curve.h"
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace cc {
@@ -22,8 +22,6 @@
 
 class PLATFORM_EXPORT CompositorScrollOffsetAnimationCurve
     : public CompositorAnimationCurve {
-  WTF_MAKE_NONCOPYABLE(CompositorScrollOffsetAnimationCurve);
-
  public:
   enum ScrollDurationBehavior {
     kScrollDurationDeltaBased = 0,
@@ -60,6 +58,8 @@
   CompositorScrollOffsetAnimationCurve(cc::ScrollOffsetAnimationCurve*);
 
   std::unique_ptr<cc::ScrollOffsetAnimationCurve> curve_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorScrollOffsetAnimationCurve);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h b/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h
index 5b93457..4e6d616b 100644
--- a/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h
+++ b/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h
@@ -7,12 +7,12 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h"
 #include "third_party/blink/renderer/platform/animation/timing_function.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace cc {
 class KeyframedTransformAnimationCurve;
@@ -27,8 +27,6 @@
 // A keyframed transform animation curve.
 class PLATFORM_EXPORT CompositorTransformAnimationCurve
     : public CompositorAnimationCurve {
-  WTF_MAKE_NONCOPYABLE(CompositorTransformAnimationCurve);
-
  public:
   static std::unique_ptr<CompositorTransformAnimationCurve> Create() {
     return base::WrapUnique(new CompositorTransformAnimationCurve());
@@ -47,6 +45,8 @@
   CompositorTransformAnimationCurve();
 
   std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorTransformAnimationCurve);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h b/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h
index 26a6c29..48fc188 100644
--- a/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h
+++ b/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h
@@ -5,18 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_KEYFRAME_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_KEYFRAME_H_
 
+#include "base/macros.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
 #include "third_party/blink/renderer/platform/animation/compositor_transform_operations.h"
 #include "third_party/blink/renderer/platform/animation/timing_function.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT CompositorTransformKeyframe : public CompositorKeyframe {
-  WTF_MAKE_NONCOPYABLE(CompositorTransformKeyframe);
-
  public:
   CompositorTransformKeyframe(double time,
                               CompositorTransformOperations value,
@@ -31,6 +29,8 @@
 
  private:
   std::unique_ptr<cc::TransformKeyframe> transform_keyframe_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorTransformKeyframe);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/async_method_runner.h b/third_party/blink/renderer/platform/async_method_runner.h
deleted file mode 100644
index e083ccc..0000000
--- a/third_party/blink/renderer/platform/async_method_runner.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_ASYNC_METHOD_RUNNER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ASYNC_METHOD_RUNNER_H_
-
-#include "base/single_thread_task_runner.h"
-#include "third_party/blink/renderer/platform/timer.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
-
-namespace blink {
-
-template <typename TargetClass>
-class AsyncMethodRunner final
-    : public GarbageCollectedFinalized<AsyncMethodRunner<TargetClass>> {
-  WTF_MAKE_NONCOPYABLE(AsyncMethodRunner);
-
- public:
-  typedef void (TargetClass::*TargetMethod)();
-
-  static AsyncMethodRunner* Create(
-      TargetClass* object,
-      TargetMethod method,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-    return MakeGarbageCollected<AsyncMethodRunner>(object, method,
-                                                   std::move(task_runner));
-  }
-
-  AsyncMethodRunner(TargetClass* object,
-                    TargetMethod method,
-                    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-      : timer_(std::move(task_runner),
-               this,
-               &AsyncMethodRunner<TargetClass>::Fired),
-        object_(object),
-        method_(method),
-        paused_(false),
-        run_when_unpaused_(false) {}
-  ~AsyncMethodRunner() = default;
-
-  // Schedules to run the method asynchronously. Do nothing if it's already
-  // scheduled. If it's suspended, remember to schedule to run the method when
-  // Unpause() is called.
-  void RunAsync() {
-    if (paused_) {
-      DCHECK(!timer_.IsActive());
-      run_when_unpaused_ = true;
-      return;
-    }
-
-    // FIXME: runAsync should take a TraceLocation and pass it to timer here.
-    if (!timer_.IsActive())
-      timer_.StartOneShot(TimeDelta(), FROM_HERE);
-  }
-
-  // If it's scheduled to run the method, cancel it and remember to schedule
-  // it again when resume() is called. Mainly for implementing
-  // PausableObject::Pause().
-  void Pause() {
-    if (paused_)
-      return;
-    paused_ = true;
-
-    if (!timer_.IsActive())
-      return;
-
-    timer_.Stop();
-    run_when_unpaused_ = true;
-  }
-
-  // Resumes pending method run.
-  void Unpause() {
-    if (!paused_)
-      return;
-    paused_ = false;
-
-    if (!run_when_unpaused_)
-      return;
-
-    run_when_unpaused_ = false;
-    // FIXME: resume should take a TraceLocation and pass it to timer here.
-    timer_.StartOneShot(TimeDelta(), FROM_HERE);
-  }
-
-  void Stop() {
-    if (paused_) {
-      DCHECK(!timer_.IsActive());
-      run_when_unpaused_ = false;
-      paused_ = false;
-      return;
-    }
-
-    DCHECK(!run_when_unpaused_);
-    timer_.Stop();
-  }
-
-  bool IsActive() const { return timer_.IsActive(); }
-
-  void Trace(blink::Visitor* visitor) { visitor->Trace(object_); }
-
- private:
-  void Fired(TimerBase*) { (object_->*method_)(); }
-
-  TaskRunnerTimer<AsyncMethodRunner<TargetClass>> timer_;
-
-  Member<TargetClass> object_;
-  TargetMethod method_;
-
-  bool paused_;
-  bool run_when_unpaused_;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/renderer/platform/audio/DEPS b/third_party/blink/renderer/platform/audio/DEPS
index e7d214c5..c03fe22 100644
--- a/third_party/blink/renderer/platform/audio/DEPS
+++ b/third_party/blink/renderer/platform/audio/DEPS
@@ -2,6 +2,10 @@
     # Don't depend on platform.
     "-third_party/blink/renderer/platform",
 
+    # We are moving from WTF_MAKE_NONCOPYABLE to DISALLOW_COPY_AND_ASSIGN.
+    # Stop new dependencies on WTF_MAKE_NONCOPYABLE.
+    "-third_party/blink/renderer/platform/wtf/noncopyable.h",
+
     # Module.
     "+third_party/blink/renderer/platform/audio",
 
diff --git a/third_party/blink/renderer/platform/audio/audio_array.h b/third_party/blink/renderer/platform/audio/audio_array.h
index 674aa69..971dede5 100644
--- a/third_party/blink/renderer/platform/audio/audio_array.h
+++ b/third_party/blink/renderer/platform/audio/audio_array.h
@@ -30,18 +30,18 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_AUDIO_ARRAY_H_
 
 #include <string.h>
+
+#include "base/macros.h"
 #include "base/numerics/checked_math.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 template <typename T>
 class AudioArray {
   USING_FAST_MALLOC(AudioArray);
-  WTF_MAKE_NONCOPYABLE(AudioArray);
 
  public:
   AudioArray() : allocation_(nullptr), aligned_data_(nullptr), size_(0) {}
@@ -149,6 +149,8 @@
   T* allocation_;
   T* aligned_data_;
   uint32_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioArray);
 };
 
 typedef AudioArray<float> AudioFloatArray;
diff --git a/third_party/blink/renderer/platform/audio/audio_bus.h b/third_party/blink/renderer/platform/audio/audio_bus.h
index c0c8c24..3c6cbff 100644
--- a/third_party/blink/renderer/platform/audio/audio_bus.h
+++ b/third_party/blink/renderer/platform/audio/audio_bus.h
@@ -30,8 +30,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_AUDIO_BUS_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_channel.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -41,8 +42,6 @@
 // The data layout is "planar" as opposed to "interleaved".  An AudioBus with
 // one channel is mono, an AudioBus with two channels is stereo, etc.
 class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
-  WTF_MAKE_NONCOPYABLE(AudioBus);
-
  public:
   enum {
     kChannelLeft = 0,
@@ -182,6 +181,9 @@
   Vector<std::unique_ptr<AudioChannel>> channels_;
   int layout_;
   float sample_rate_;  // 0.0 if unknown or N/A
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AudioBus);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/audio_channel.h b/third_party/blink/renderer/platform/audio/audio_channel.h
index 57a9376..5ac656d 100644
--- a/third_party/blink/renderer/platform/audio/audio_channel.h
+++ b/third_party/blink/renderer/platform/audio/audio_channel.h
@@ -30,6 +30,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_AUDIO_CHANNEL_H_
 
 #include <memory>
+
 #include "base/numerics/checked_math.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -42,7 +43,6 @@
 // The PCM samples are normally assumed to be in a nominal range -1.0 -> +1.0
 class PLATFORM_EXPORT AudioChannel {
   USING_FAST_MALLOC(AudioChannel);
-  WTF_MAKE_NONCOPYABLE(AudioChannel);
 
  public:
   // Memory can be externally referenced, or can be internally allocated with an
@@ -130,6 +130,8 @@
   float* raw_pointer_;
   std::unique_ptr<AudioFloatArray> mem_buffer_;
   bool silent_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioChannel);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/audio_destination.h b/third_party/blink/renderer/platform/audio/audio_destination.h
index 5709fadb..2abf9aa 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination.h
+++ b/third_party/blink/renderer/platform/audio/audio_destination.h
@@ -30,6 +30,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_AUDIO_DESTINATION_H_
 
 #include <memory>
+
 #include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
 #include "third_party/blink/public/platform/web_audio_device.h"
@@ -59,7 +60,6 @@
     : public ThreadSafeRefCounted<AudioDestination>,
       public WebAudioDevice::RenderCallback {
   USING_FAST_MALLOC(AudioDestination);
-  WTF_MAKE_NONCOPYABLE(AudioDestination);
 
  public:
   AudioDestination(AudioIOCallback&,
@@ -154,6 +154,8 @@
 
   // Accessed by rendering thread.
   size_t frames_elapsed_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioDestination);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/audio_resampler.h b/third_party/blink/renderer/platform/audio/audio_resampler.h
index 17ea917..103698c 100644
--- a/third_party/blink/renderer/platform/audio/audio_resampler.h
+++ b/third_party/blink/renderer/platform/audio/audio_resampler.h
@@ -27,11 +27,12 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_AUDIO_RESAMPLER_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
 #include "third_party/blink/renderer/platform/audio/audio_resampler_kernel.h"
 #include "third_party/blink/renderer/platform/audio/audio_source_provider.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -42,7 +43,6 @@
 
 class PLATFORM_EXPORT AudioResampler {
   DISALLOW_NEW();
-  WTF_MAKE_NONCOPYABLE(AudioResampler);
 
  public:
   AudioResampler();
@@ -70,6 +70,8 @@
   double rate_;
   Vector<std::unique_ptr<AudioResamplerKernel>> kernels_;
   scoped_refptr<AudioBus> source_bus_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioResampler);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/audio_resampler_kernel.h b/third_party/blink/renderer/platform/audio/audio_resampler_kernel.h
index d47fcdd6..a0d333a 100644
--- a/third_party/blink/renderer/platform/audio/audio_resampler_kernel.h
+++ b/third_party/blink/renderer/platform/audio/audio_resampler_kernel.h
@@ -39,7 +39,6 @@
 
 class PLATFORM_EXPORT AudioResamplerKernel {
   USING_FAST_MALLOC(AudioResamplerKernel);
-  WTF_MAKE_NONCOPYABLE(AudioResamplerKernel);
 
  public:
   AudioResamplerKernel(AudioResampler*);
@@ -80,6 +79,8 @@
   // there will be no buffered samples.
   float last_values_[2];
   unsigned fill_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioResamplerKernel);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/direct_convolver.h b/third_party/blink/renderer/platform/audio/direct_convolver.h
index f2f6f98..965a7ee6 100644
--- a/third_party/blink/renderer/platform/audio/direct_convolver.h
+++ b/third_party/blink/renderer/platform/audio/direct_convolver.h
@@ -31,16 +31,15 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT DirectConvolver {
   USING_FAST_MALLOC(DirectConvolver);
-  WTF_MAKE_NONCOPYABLE(DirectConvolver);
 
  public:
   DirectConvolver(size_t input_block_size,
@@ -60,6 +59,8 @@
   AudioFloatArray buffer_;
   std::unique_ptr<AudioFloatArray> convolution_kernel_;
   AudioFloatArray prepared_convolution_kernel_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirectConvolver);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/down_sampler.h b/third_party/blink/renderer/platform/audio/down_sampler.h
index 7f1f174..5587a70d 100644
--- a/third_party/blink/renderer/platform/audio/down_sampler.h
+++ b/third_party/blink/renderer/platform/audio/down_sampler.h
@@ -31,10 +31,10 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DOWN_SAMPLER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DOWN_SAMPLER_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/simple_fft_convolver.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -42,7 +42,6 @@
 
 class PLATFORM_EXPORT DownSampler {
   USING_FAST_MALLOC(DownSampler);
-  WTF_MAKE_NONCOPYABLE(DownSampler);
 
  public:
   explicit DownSampler(size_t input_block_size);
@@ -70,6 +69,8 @@
   // Used as delay-line (FIR filter history) for the input samples to account
   // for the 0.5 term right in the middle of the kernel.
   AudioFloatArray input_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownSampler);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/dynamics_compressor.h b/third_party/blink/renderer/platform/audio/dynamics_compressor.h
index aa99c54..ff5245a 100644
--- a/third_party/blink/renderer/platform/audio/dynamics_compressor.h
+++ b/third_party/blink/renderer/platform/audio/dynamics_compressor.h
@@ -30,10 +30,11 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DYNAMICS_COMPRESSOR_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -46,7 +47,6 @@
 
 class PLATFORM_EXPORT DynamicsCompressor {
   USING_FAST_MALLOC(DynamicsCompressor);
-  WTF_MAKE_NONCOPYABLE(DynamicsCompressor);
 
  public:
   enum {
@@ -111,6 +111,9 @@
 
   // The core compressor.
   DynamicsCompressorKernel compressor_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DynamicsCompressor);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h b/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h
index fa93846..7ebf0129 100644
--- a/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h
+++ b/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h
@@ -30,17 +30,16 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DYNAMICS_COMPRESSOR_KERNEL_H_
 
 #include <memory>
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT DynamicsCompressorKernel {
   DISALLOW_NEW();
-  WTF_MAKE_NONCOPYABLE(DynamicsCompressorKernel);
 
  public:
   DynamicsCompressorKernel(float sample_rate, unsigned number_of_channels);
@@ -135,6 +134,9 @@
 
   // Internal parameter for the knee portion of the curve.
   float knee_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DynamicsCompressorKernel);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/fft_convolver.h b/third_party/blink/renderer/platform/audio/fft_convolver.h
index af6c5681..f384df7 100644
--- a/third_party/blink/renderer/platform/audio/fft_convolver.h
+++ b/third_party/blink/renderer/platform/audio/fft_convolver.h
@@ -29,16 +29,15 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_FFT_CONVOLVER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_FFT_CONVOLVER_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/fft_frame.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT FFTConvolver {
   USING_FAST_MALLOC(FFTConvolver);
-  WTF_MAKE_NONCOPYABLE(FFTConvolver);
 
  public:
   // fftSize must be a power of two
@@ -75,6 +74,8 @@
   // Saves the 2nd half of the FFT buffer, so we can do an overlap-add with the
   // 1st half of the next one
   AudioFloatArray last_overlap_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(FFTConvolver);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/hrtf_database.h b/third_party/blink/renderer/platform/audio/hrtf_database.h
index 72761b0..708fab1 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_database.h
+++ b/third_party/blink/renderer/platform/audio/hrtf_database.h
@@ -30,11 +30,12 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_HRTF_DATABASE_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/audio/hrtf_elevation.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -43,7 +44,6 @@
 
 class PLATFORM_EXPORT HRTFDatabase {
   USING_FAST_MALLOC(HRTFDatabase);
-  WTF_MAKE_NONCOPYABLE(HRTFDatabase);
 
  public:
   static std::unique_ptr<HRTFDatabase> Create(float sample_rate);
@@ -94,6 +94,8 @@
 
   Vector<std::unique_ptr<HRTFElevation>> elevations_;
   float sample_rate_;
+
+  DISALLOW_COPY_AND_ASSIGN(HRTFDatabase);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/hrtf_elevation.h b/third_party/blink/renderer/platform/audio/hrtf_elevation.h
index c29ba2ca..cc4a7a9 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_elevation.h
+++ b/third_party/blink/renderer/platform/audio/hrtf_elevation.h
@@ -30,10 +30,11 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_HRTF_ELEVATION_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/audio/hrtf_kernel.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
@@ -44,7 +45,6 @@
 
 class PLATFORM_EXPORT HRTFElevation {
   USING_FAST_MALLOC(HRTFElevation);
-  WTF_MAKE_NONCOPYABLE(HRTFElevation);
 
  public:
   // Loads and returns an HRTFElevation with the given HRTF database subject
@@ -125,6 +125,8 @@
   std::unique_ptr<HRTFKernelList> kernel_list_r_;
   double elevation_angle_;
   float sample_rate_;
+
+  DISALLOW_COPY_AND_ASSIGN(HRTFElevation);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/hrtf_kernel.h b/third_party/blink/renderer/platform/audio/hrtf_kernel.h
index 6758b9a15..b9b9bf4 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_kernel.h
+++ b/third_party/blink/renderer/platform/audio/hrtf_kernel.h
@@ -32,10 +32,10 @@
 #include <memory>
 #include <utility>
 
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/audio/fft_frame.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -53,7 +53,6 @@
 //      m_frameDelay is the leading delay of the original impulse response.
 class PLATFORM_EXPORT HRTFKernel {
   USING_FAST_MALLOC(HRTFKernel);
-  WTF_MAKE_NONCOPYABLE(HRTFKernel);
 
  public:
   // Note: this is destructive on the passed in AudioChannel.
@@ -101,6 +100,8 @@
   std::unique_ptr<FFTFrame> fft_frame_;
   float frame_delay_;
   float sample_rate_;
+
+  DISALLOW_COPY_AND_ASSIGN(HRTFKernel);
 };
 
 typedef Vector<std::unique_ptr<HRTFKernel>> HRTFKernelList;
diff --git a/third_party/blink/renderer/platform/audio/multi_channel_resampler.h b/third_party/blink/renderer/platform/audio/multi_channel_resampler.h
index 64949504..26645bc4 100644
--- a/third_party/blink/renderer/platform/audio/multi_channel_resampler.h
+++ b/third_party/blink/renderer/platform/audio/multi_channel_resampler.h
@@ -30,9 +30,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_MULTI_CHANNEL_RESAMPLER_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/sinc_resampler.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -41,7 +42,6 @@
 
 class PLATFORM_EXPORT MultiChannelResampler {
   USING_FAST_MALLOC(MultiChannelResampler);
-  WTF_MAKE_NONCOPYABLE(MultiChannelResampler);
 
  public:
   MultiChannelResampler(double scale_factor, unsigned number_of_channels);
@@ -61,6 +61,8 @@
   Vector<std::unique_ptr<SincResampler>> kernels_;
 
   unsigned number_of_channels_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultiChannelResampler);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/panner.h b/third_party/blink/renderer/platform/audio/panner.h
index 93a0eb9..655250c 100644
--- a/third_party/blink/renderer/platform/audio/panner.h
+++ b/third_party/blink/renderer/platform/audio/panner.h
@@ -30,10 +30,11 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_PANNER_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -43,7 +44,6 @@
 
 class PLATFORM_EXPORT Panner {
   USING_FAST_MALLOC(Panner);
-  WTF_MAKE_NONCOPYABLE(Panner);
 
  public:
   // This values are used in histograms and should not be renumbered or deleted.
@@ -80,6 +80,9 @@
   Panner(PanningModel model) : panning_model_(model) {}
 
   PanningModel panning_model_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Panner);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/push_pull_fifo.h b/third_party/blink/renderer/platform/audio/push_pull_fifo.h
index 3e6335ed..0d44e29 100644
--- a/third_party/blink/renderer/platform/audio/push_pull_fifo.h
+++ b/third_party/blink/renderer/platform/audio/push_pull_fifo.h
@@ -39,7 +39,6 @@
 // TODO(hongchan): add a unit test for multi-thread access.
 class BLINK_PLATFORM_EXPORT PushPullFIFO {
   USING_FAST_MALLOC(PushPullFIFO);
-  WTF_MAKE_NONCOPYABLE(PushPullFIFO);
 
  public:
   // Maximum FIFO length. (512 render quanta)
@@ -94,6 +93,8 @@
   size_t index_read_ = 0;
   size_t index_write_ = 0;
   scoped_refptr<AudioBus> fifo_bus_;
+
+  DISALLOW_COPY_AND_ASSIGN(PushPullFIFO);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/reverb.h b/third_party/blink/renderer/platform/audio/reverb.h
index 03ce81f..f23f2ed 100644
--- a/third_party/blink/renderer/platform/audio/reverb.h
+++ b/third_party/blink/renderer/platform/audio/reverb.h
@@ -30,9 +30,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_REVERB_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/reverb_convolver.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -44,7 +45,6 @@
 
 class PLATFORM_EXPORT Reverb {
   USING_FAST_MALLOC(Reverb);
-  WTF_MAKE_NONCOPYABLE(Reverb);
 
  public:
   enum { kMaxFrameSize = 256 };
@@ -80,6 +80,8 @@
 
   // For "True" stereo processing
   scoped_refptr<AudioBus> temp_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(Reverb);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.h b/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.h
index 9b2389134..270af89 100644
--- a/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.h
+++ b/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.h
@@ -29,10 +29,10 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_REVERB_ACCUMULATION_BUFFER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_REVERB_ACCUMULATION_BUFFER_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -43,7 +43,6 @@
 // time around.
 class PLATFORM_EXPORT ReverbAccumulationBuffer {
   DISALLOW_NEW();
-  WTF_MAKE_NONCOPYABLE(ReverbAccumulationBuffer);
 
  public:
   ReverbAccumulationBuffer(size_t length);
@@ -73,6 +72,8 @@
   AudioFloatArray buffer_;
   size_t read_index_;
   size_t read_time_frame_;  // for debugging (frame on continuous timeline)
+
+  DISALLOW_COPY_AND_ASSIGN(ReverbAccumulationBuffer);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/reverb_convolver.h b/third_party/blink/renderer/platform/audio/reverb_convolver.h
index 40c53798..ebdcf7eb 100644
--- a/third_party/blink/renderer/platform/audio/reverb_convolver.h
+++ b/third_party/blink/renderer/platform/audio/reverb_convolver.h
@@ -30,6 +30,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_REVERB_CONVOLVER_H_
 
 #include <memory>
+
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/direct_convolver.h"
 #include "third_party/blink/renderer/platform/audio/fft_convolver.h"
@@ -46,7 +47,6 @@
 
 class PLATFORM_EXPORT ReverbConvolver {
   USING_FAST_MALLOC(ReverbConvolver);
-  WTF_MAKE_NONCOPYABLE(ReverbConvolver);
 
  public:
   // maxFFTSize can be adjusted (from say 2048 to 32768) depending on how much
@@ -94,6 +94,8 @@
 
   // Background thread and synchronization
   std::unique_ptr<Thread> background_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReverbConvolver);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/reverb_convolver_stage.h b/third_party/blink/renderer/platform/audio/reverb_convolver_stage.h
index 39f00a9..faecb2a6e5 100644
--- a/third_party/blink/renderer/platform/audio/reverb_convolver_stage.h
+++ b/third_party/blink/renderer/platform/audio/reverb_convolver_stage.h
@@ -31,10 +31,10 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/fft_frame.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -49,7 +49,6 @@
 // response.
 class PLATFORM_EXPORT ReverbConvolverStage {
   USING_FAST_MALLOC(ReverbConvolverStage);
-  WTF_MAKE_NONCOPYABLE(ReverbConvolverStage);
 
  public:
   // renderPhase is useful to know so that we can manipulate the pre versus post
@@ -97,6 +96,8 @@
 
   bool direct_mode_;
   std::unique_ptr<DirectConvolver> direct_convolver_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReverbConvolverStage);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/reverb_input_buffer.h b/third_party/blink/renderer/platform/audio/reverb_input_buffer.h
index b08aad19..df147a03 100644
--- a/third_party/blink/renderer/platform/audio/reverb_input_buffer.h
+++ b/third_party/blink/renderer/platform/audio/reverb_input_buffer.h
@@ -30,10 +30,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_REVERB_INPUT_BUFFER_H_
 
 #include <atomic>
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -41,7 +41,6 @@
 // the background threads.
 class PLATFORM_EXPORT ReverbInputBuffer {
   DISALLOW_NEW();
-  WTF_MAKE_NONCOPYABLE(ReverbInputBuffer);
 
  public:
   ReverbInputBuffer(size_t length);
@@ -78,6 +77,8 @@
   // the getter and setter to access it atomically.  Don't access
   // directly!
   std::atomic_size_t write_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReverbInputBuffer);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/simple_fft_convolver.h b/third_party/blink/renderer/platform/audio/simple_fft_convolver.h
index 8e2093d..6b7220fb 100644
--- a/third_party/blink/renderer/platform/audio/simple_fft_convolver.h
+++ b/third_party/blink/renderer/platform/audio/simple_fft_convolver.h
@@ -7,10 +7,10 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/fft_frame.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -22,7 +22,6 @@
 // smaller than that of the FFTConvolver.
 class PLATFORM_EXPORT SimpleFFTConvolver {
   USING_FAST_MALLOC(SimpleFFTConvolver);
-  WTF_MAKE_NONCOPYABLE(SimpleFFTConvolver);
 
  public:
   SimpleFFTConvolver(
@@ -53,6 +52,8 @@
   // Saves the 2nd half of the FFT buffer, so we can do an overlap-add with the
   // 1st half of the next one
   AudioFloatArray last_overlap_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleFFTConvolver);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/sinc_resampler.h b/third_party/blink/renderer/platform/audio/sinc_resampler.h
index df888571..484e654 100644
--- a/third_party/blink/renderer/platform/audio/sinc_resampler.h
+++ b/third_party/blink/renderer/platform/audio/sinc_resampler.h
@@ -29,11 +29,11 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_SINC_RESAMPLER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_SINC_RESAMPLER_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/audio_source_provider.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -41,7 +41,6 @@
 
 class PLATFORM_EXPORT SincResampler {
   USING_FAST_MALLOC(SincResampler);
-  WTF_MAKE_NONCOPYABLE(SincResampler);
 
  public:
   // scaleFactor == sourceSampleRate / destinationSampleRate
@@ -96,6 +95,9 @@
 
   // The buffer is primed once at the very beginning of processing.
   bool is_buffer_primed_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SincResampler);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/stereo_panner.h b/third_party/blink/renderer/platform/audio/stereo_panner.h
index 91f8d0c..96affa9 100644
--- a/third_party/blink/renderer/platform/audio/stereo_panner.h
+++ b/third_party/blink/renderer/platform/audio/stereo_panner.h
@@ -5,9 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_STEREO_PANNER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_STEREO_PANNER_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -18,7 +18,6 @@
 
 class PLATFORM_EXPORT StereoPanner {
   USING_FAST_MALLOC(StereoPanner);
-  WTF_MAKE_NONCOPYABLE(StereoPanner);
 
  public:
   static std::unique_ptr<StereoPanner> Create(float sample_rate);
@@ -35,6 +34,8 @@
 
  private:
   explicit StereoPanner(float sample_rate);
+
+  DISALLOW_COPY_AND_ASSIGN(StereoPanner);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/up_sampler.h b/third_party/blink/renderer/platform/audio/up_sampler.h
index e76a8d84..399852bb 100644
--- a/third_party/blink/renderer/platform/audio/up_sampler.h
+++ b/third_party/blink/renderer/platform/audio/up_sampler.h
@@ -33,11 +33,11 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/audio/audio_array.h"
 #include "third_party/blink/renderer/platform/audio/direct_convolver.h"
 #include "third_party/blink/renderer/platform/audio/simple_fft_convolver.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -45,7 +45,6 @@
 
 class PLATFORM_EXPORT UpSampler {
   USING_FAST_MALLOC(UpSampler);
-  WTF_MAKE_NONCOPYABLE(UpSampler);
 
  public:
   explicit UpSampler(size_t input_block_size);
@@ -76,6 +75,8 @@
   // the FIR filter (convolution) used to generate the odd sample-frames of the
   // output.
   AudioFloatArray input_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpSampler);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 79cd453..9d0ee8c 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -636,6 +636,7 @@
 
 void WebRuntimeFeatures::EnableHTMLImports(bool enable) {
   RuntimeEnabledFeatures::SetHTMLImportsEnabled(enable);
+  RuntimeEnabledFeatures::SetHTMLImportsOnlyChromeEnabled(enable);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/DEPS b/third_party/blink/renderer/platform/fonts/DEPS
index d859ec6..4b1d7e06 100644
--- a/third_party/blink/renderer/platform/fonts/DEPS
+++ b/third_party/blink/renderer/platform/fonts/DEPS
@@ -2,6 +2,10 @@
     # Don't depend on platform/.
     "-third_party/blink/renderer/platform",
 
+    # We are moving from WTF_MAKE_NONCOPYABLE to DISALLOW_COPY_AND_ASSIGN.
+    # Stop new dependencies on WTF_MAKE_NONCOPYABLE.
+    "-third_party/blink/renderer/platform/wtf/noncopyable.h",
+
     # Module.
     "+third_party/blink/renderer/platform/fonts",
 
diff --git a/third_party/blink/renderer/platform/fonts/font_cache.h b/third_party/blink/renderer/platform/fonts/font_cache.h
index 589e0ba..f580e5fc 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/font_cache.h
@@ -31,7 +31,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CACHE_H_
 
 #include <limits.h>
-
 #include <memory>
 
 #include "base/memory/scoped_refptr.h"
@@ -99,7 +98,6 @@
 class PLATFORM_EXPORT FontCache {
   friend class FontCachePurgePreventer;
 
-  WTF_MAKE_NONCOPYABLE(FontCache);
   USING_FAST_MALLOC(FontCache);
 
  public:
@@ -346,15 +344,19 @@
 
   friend class SimpleFontData;  // For fontDataFromFontPlatformData
   friend class FontFallbackList;
+
+  DISALLOW_COPY_AND_ASSIGN(FontCache);
 };
 
 class PLATFORM_EXPORT FontCachePurgePreventer {
   USING_FAST_MALLOC(FontCachePurgePreventer);
-  WTF_MAKE_NONCOPYABLE(FontCachePurgePreventer);
 
  public:
   FontCachePurgePreventer() { FontCache::GetFontCache()->DisablePurging(); }
   ~FontCachePurgePreventer() { FontCache::GetFontCache()->EnablePurging(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FontCachePurgePreventer);
 };
 
 AtomicString ToAtomicString(const SkString&);
diff --git a/third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h b/third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h
index 12896385..abac740 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h
+++ b/third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h
@@ -5,11 +5,11 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CACHE_MEMORY_DUMP_PROVIDER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CACHE_MEMORY_DUMP_PROVIDER_H_
 
+#include "base/macros.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -28,7 +28,7 @@
  private:
   FontCacheMemoryDumpProvider() = default;
 
-  WTF_MAKE_NONCOPYABLE(FontCacheMemoryDumpProvider);
+  DISALLOW_COPY_AND_ASSIGN(FontCacheMemoryDumpProvider);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.h b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.h
index 82625802..6a1806a 100644
--- a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.h
+++ b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.h
@@ -32,12 +32,12 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CUSTOM_PLATFORM_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CUSTOM_PLATFORM_DATA_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/fonts/font_orientation.h"
 #include "third_party/blink/renderer/platform/fonts/font_selection_types.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
@@ -54,7 +54,6 @@
 class PLATFORM_EXPORT FontCustomPlatformData
     : public RefCounted<FontCustomPlatformData> {
   USING_FAST_MALLOC(FontCustomPlatformData);
-  WTF_MAKE_NONCOPYABLE(FontCustomPlatformData);
 
  public:
   static scoped_refptr<FontCustomPlatformData> Create(SharedBuffer*,
@@ -79,6 +78,8 @@
   FontCustomPlatformData(sk_sp<SkTypeface>, size_t data_size);
   sk_sp<SkTypeface> base_typeface_;
   size_t data_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(FontCustomPlatformData);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_data.h b/third_party/blink/renderer/platform/fonts/font_data.h
index 2b770f6..f6544d37 100644
--- a/third_party/blink/renderer/platform/fonts/font_data.h
+++ b/third_party/blink/renderer/platform/fonts/font_data.h
@@ -26,11 +26,11 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_DATA_H_
 
+#include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
 
@@ -39,8 +39,6 @@
 class SimpleFontData;
 
 class PLATFORM_EXPORT FontData : public RefCounted<FontData> {
-  WTF_MAKE_NONCOPYABLE(FontData);
-
  public:
   FontData() = default;
 
@@ -54,6 +52,9 @@
   virtual bool IsLoadingFallback() const = 0;
   virtual bool IsSegmented() const = 0;
   virtual bool ShouldSkipDrawing() const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FontData);
 };
 
 #define DEFINE_FONT_DATA_TYPE_CASTS(thisType, predicate)     \
diff --git a/third_party/blink/renderer/platform/fonts/font_data_cache.h b/third_party/blink/renderer/platform/fonts/font_data_cache.h
index 685a269..0fc60f3 100644
--- a/third_party/blink/renderer/platform/fonts/font_data_cache.h
+++ b/third_party/blink/renderer/platform/fonts/font_data_cache.h
@@ -69,7 +69,6 @@
 
 class FontDataCache {
   USING_FAST_MALLOC(FontDataCache);
-  WTF_MAKE_NONCOPYABLE(FontDataCache);
 
  public:
   FontDataCache() = default;
@@ -93,6 +92,8 @@
       Cache;
   Cache cache_;
   LinkedHashSet<scoped_refptr<SimpleFontData>> inactive_font_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(FontDataCache);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
index 19ffa28..646d5f0b 100644
--- a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
@@ -20,8 +20,6 @@
 class SimpleFontData;
 
 class FontFallbackIterator : public RefCounted<FontFallbackIterator> {
-  WTF_MAKE_NONCOPYABLE(FontFallbackIterator);
-
  public:
   static scoped_refptr<FontFallbackIterator> Create(const FontDescription&,
                                              scoped_refptr<FontFallbackList>,
@@ -82,6 +80,8 @@
   HashSet<uint32_t> unique_font_data_for_range_sets_returned_;
   Vector<scoped_refptr<FontDataForRangeSet>> tracked_loading_range_sets_;
   FontFallbackPriority font_fallback_priority_;
+
+  DISALLOW_COPY_AND_ASSIGN(FontFallbackIterator);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_list.h b/third_party/blink/renderer/platform/fonts/font_fallback_list.h
index 30fc8b04..6d800c7 100644
--- a/third_party/blink/renderer/platform/fonts/font_fallback_list.h
+++ b/third_party/blink/renderer/platform/fonts/font_fallback_list.h
@@ -39,8 +39,6 @@
 const int kCAllFamiliesScanned = -1;
 
 class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> {
-  WTF_MAKE_NONCOPYABLE(FontFallbackList);
-
  public:
   static scoped_refptr<FontFallbackList> Create() {
     return base::AdoptRef(new FontFallbackList());
@@ -101,6 +99,8 @@
   unsigned short generation_;
   mutable bool has_loading_fallback_ : 1;
   mutable base::WeakPtr<ShapeCache> shape_cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(FontFallbackList);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_global_context.h b/third_party/blink/renderer/platform/fonts/font_global_context.h
index d3308f5..6419225 100644
--- a/third_party/blink/renderer/platform/fonts/font_global_context.h
+++ b/third_party/blink/renderer/platform/fonts/font_global_context.h
@@ -22,8 +22,6 @@
 // FontGlobalContext contains non-thread-safe, thread-specific data used for
 // font formatting.
 class PLATFORM_EXPORT FontGlobalContext {
-  WTF_MAKE_NONCOPYABLE(FontGlobalContext);
-
  public:
   static FontGlobalContext* Get(CreateIfNeeded = kCreate);
 
@@ -56,6 +54,8 @@
   HarfBuzzFontCache harfbuzz_font_cache_;
   hb_font_funcs_t* harfbuzz_font_funcs_;
   std::unique_ptr<FontUniqueNameLookup> font_unique_name_lookup_;
+
+  DISALLOW_COPY_AND_ASSIGN(FontGlobalContext);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/glyph_metrics_map.h b/third_party/blink/renderer/platform/fonts/glyph_metrics_map.h
index cb98f109..9386930 100644
--- a/third_party/blink/renderer/platform/fonts/glyph_metrics_map.h
+++ b/third_party/blink/renderer/platform/fonts/glyph_metrics_map.h
@@ -46,7 +46,6 @@
 template <class T>
 class GlyphMetricsMap {
   USING_FAST_MALLOC(GlyphMetricsMap);
-  WTF_MAKE_NONCOPYABLE(GlyphMetricsMap);
 
  public:
   GlyphMetricsMap() : filled_primary_page_(false) {}
@@ -62,7 +61,7 @@
  private:
   class GlyphMetricsPage {
     USING_FAST_MALLOC(GlyphMetricsPage);
-    WTF_MAKE_NONCOPYABLE(GlyphMetricsPage);
+    DISALLOW_COPY_AND_ASSIGN(GlyphMetricsPage);
 
    public:
     static const size_t kSize =
@@ -96,6 +95,8 @@
   // We optimize for the page that contains glyph indices 0-255.
   GlyphMetricsPage primary_page_;
   std::unique_ptr<HashMap<int, std::unique_ptr<GlyphMetricsPage>>> pages_;
+
+  DISALLOW_COPY_AND_ASSIGN(GlyphMetricsMap);
 };
 
 template <>
diff --git a/third_party/blink/renderer/platform/fonts/orientation_iterator.h b/third_party/blink/renderer/platform/fonts/orientation_iterator.h
index 4ec912c..724ebca8 100644
--- a/third_party/blink/renderer/platform/fonts/orientation_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/orientation_iterator.h
@@ -6,17 +6,17 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_ORIENTATION_ITERATOR_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/fonts/font_orientation.h"
 #include "third_party/blink/renderer/platform/fonts/script_run_iterator.h"
 #include "third_party/blink/renderer/platform/fonts/utf16_text_iterator.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT OrientationIterator {
   USING_FAST_MALLOC(OrientationIterator);
-  WTF_MAKE_NONCOPYABLE(OrientationIterator);
 
  public:
   enum RenderOrientation {
@@ -35,6 +35,8 @@
   std::unique_ptr<UTF16TextIterator> utf16_iterator_;
   unsigned buffer_size_;
   bool at_end_;
+
+  DISALLOW_COPY_AND_ASSIGN(OrientationIterator);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/script_run_iterator.h b/third_party/blink/renderer/platform/fonts/script_run_iterator.h
index 39d23e3..c5f535c 100644
--- a/third_party/blink/renderer/platform/fonts/script_run_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/script_run_iterator.h
@@ -5,11 +5,11 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SCRIPT_RUN_ITERATOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SCRIPT_RUN_ITERATOR_H_
 
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/dtoa/utils.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 #include <unicode/uchar.h>
@@ -21,7 +21,6 @@
 
 class PLATFORM_EXPORT ScriptRunIterator {
   USING_FAST_MALLOC(ScriptRunIterator);
-  WTF_MAKE_NONCOPYABLE(ScriptRunIterator);
 
  public:
   ScriptRunIterator(const UChar* text, wtf_size_t length);
@@ -72,6 +71,8 @@
   UScriptCode common_preferred_;
 
   const ScriptData* script_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptRunIterator);
 };
 
 // ScriptData is a wrapper which returns a set of scripts for a particular
@@ -81,7 +82,6 @@
 // method to work correctly.
 class PLATFORM_EXPORT ScriptData {
   USING_FAST_MALLOC(ScriptData);
-  WTF_MAKE_NONCOPYABLE(ScriptData);
 
  protected:
   ScriptData() = default;
@@ -104,6 +104,9 @@
   virtual UChar32 GetPairedBracket(UChar32) const = 0;
 
   virtual PairedBracketType GetPairedBracketType(UChar32) const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScriptData);
 };
 
 class PLATFORM_EXPORT ICUScriptData : public ScriptData {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.h b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.h
index 2f9cd060..7a0a862 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.h
@@ -38,7 +38,6 @@
 
 class PLATFORM_EXPORT CachingWordShapeIterator final {
   STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(CachingWordShapeIterator);
 
  public:
   CachingWordShapeIterator(ShapeCache* cache,
@@ -211,6 +210,8 @@
   float width_so_far_;  // Used only when allowTabs()
   unsigned start_index_ : 31;
   unsigned shape_by_word_ : 1;
+
+  DISALLOW_COPY_AND_ASSIGN(CachingWordShapeIterator);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h
index 7565968..33f4ea8 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h
@@ -44,7 +44,6 @@
 
 class PLATFORM_EXPORT CachingWordShaper final {
   STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(CachingWordShaper);
 
  public:
   explicit CachingWordShaper(const Font& font) : font_(font) {}
@@ -71,6 +70,8 @@
   ShapeCache* GetShapeCache() const;
 
   const Font& font_;
+
+  DISALLOW_COPY_AND_ASSIGN(CachingWordShaper);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h
index a234385..fa031387 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h
@@ -31,12 +31,12 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FACE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FACE_H_
 
+#include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/fonts/typesetting_features.h"
 #include "third_party/blink/renderer/platform/fonts/unicode_range_set.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 
@@ -48,8 +48,6 @@
 struct HarfBuzzFontData;
 
 class HarfBuzzFace : public RefCounted<HarfBuzzFace> {
-  WTF_MAKE_NONCOPYABLE(HarfBuzzFace);
-
  public:
   static scoped_refptr<HarfBuzzFace> Create(FontPlatformData* platform_data,
                                             uint64_t unique_id) {
@@ -80,6 +78,8 @@
   uint64_t unique_id_;
   hb_font_t* unscaled_font_;
   HarfBuzzFontData* harfbuzz_font_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(HarfBuzzFace);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
index c0d7905..4ecf1f2 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FONT_CACHE_H_
 
 #include <memory>
+
 #include "third_party/blink/renderer/platform/fonts/font_metrics.h"
 #include "third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h"
@@ -36,7 +37,6 @@
 // particular size.
 struct HarfBuzzFontData {
   USING_FAST_MALLOC(HarfBuzzFontData);
-  WTF_MAKE_NONCOPYABLE(HarfBuzzFontData);
 
  public:
   HarfBuzzFontData()
@@ -120,6 +120,9 @@
 
   scoped_refptr<OpenTypeVerticalData> vertical_data_;
   scoped_refptr<UnicodeRangeSet> range_set_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HarfBuzzFontData);
 };
 
 // Though we have FontCache class, which provides the cache mechanism for
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index fa99bda..e370c5f 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -126,7 +126,6 @@
 template <typename T>
 class HarfBuzzScopedPtr {
   STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(HarfBuzzScopedPtr);
 
  public:
   typedef void (*DestroyFunction)(T*);
@@ -146,6 +145,8 @@
  private:
   T* ptr_;
   DestroyFunction destroy_;
+
+  DISALLOW_COPY_AND_ASSIGN(HarfBuzzScopedPtr);
 };
 
 using FeaturesVector = Vector<hb_feature_t, 6>;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
index 2b6132e..02253633 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -1269,11 +1269,9 @@
   HarfBuzzShaper shaper(mixed_string);
   scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
 
-  // Copy multiple times using |context| from multiple runs
-  unsigned context = 0;
-  scoped_refptr<ShapeResult> sub2to4 = result->SubRange(2, 4, &context);
+  scoped_refptr<ShapeResult> sub2to4 = result->SubRange(2, 4);
   EXPECT_EQ(2u, sub2to4->NumCharacters());
-  scoped_refptr<ShapeResult> sub5to9 = result->SubRange(5, 9, &context);
+  scoped_refptr<ShapeResult> sub5to9 = result->SubRange(5, 9);
   EXPECT_EQ(4u, sub5to9->NumCharacters());
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
index 84647ca..93227df 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
@@ -7,6 +7,7 @@
 
 #include <unicode/uscript.h>
 #include <memory>
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/fonts/font_orientation.h"
 #include "third_party/blink/renderer/platform/fonts/orientation_iterator.h"
 #include "third_party/blink/renderer/platform/fonts/script_run_iterator.h"
@@ -14,7 +15,6 @@
 #include "third_party/blink/renderer/platform/fonts/symbols_iterator.h"
 #include "third_party/blink/renderer/platform/fonts/utf16_text_iterator.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
@@ -23,7 +23,6 @@
 // font-variant of the text run.
 class PLATFORM_EXPORT RunSegmenter {
   STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(RunSegmenter);
 
  public:
   // Indices into the UTF-16 buffer that is passed in
@@ -63,6 +62,8 @@
   unsigned orientation_iterator_position_;
   unsigned symbols_iterator_position_;
   bool at_end_;
+
+  DISALLOW_COPY_AND_ASSIGN(RunSegmenter);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
index 0445650..d3e9b50d 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
@@ -45,7 +45,6 @@
 
 class ShapeCache {
   USING_FAST_MALLOC(ShapeCache);
-  WTF_MAKE_NONCOPYABLE(ShapeCache);
   // Used to optimize small strings as hash table keys. Avoids malloc'ing an
   // out-of-line StringImpl.
   class SmallStringKey {
@@ -238,6 +237,8 @@
   SmallStringMap short_string_map_;
   unsigned version_ = 0;
   base::WeakPtrFactory<ShapeCache> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShapeCache);
 };
 
 inline bool operator==(const ShapeCache::SmallStringKey& a,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index bab5820..f6970907 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -1320,11 +1320,53 @@
 
 void ShapeResult::CopyRange(unsigned start_offset,
                             unsigned end_offset,
-                            ShapeResult* target,
-                            unsigned* start_run_index) const {
+                            ShapeResult* target) const {
+  unsigned run_index = 0;
+  CopyRangeInternal(run_index, start_offset, end_offset, target);
+}
+
+void ShapeResult::CopyRanges(const ShapeRange* ranges,
+                             unsigned num_ranges) const {
+  DCHECK_GT(num_ranges, 0u);
   if (!runs_.size())
     return;
 
+  // Ranges are in logical order so for RTL the ranges are proccessed back to
+  // front to ensure that they're in a sequential visual order with regards to
+  // the runs.
+  if (Rtl()) {
+    unsigned run_index = 0;
+    unsigned last_range = num_ranges - 1;
+    for (unsigned i = 0; i < num_ranges; i++) {
+      const ShapeRange& range = ranges[last_range - i];
+#if DCHECK_IS_ON()
+      DCHECK_GE(range.end, range.start);
+      if (i != last_range)
+        DCHECK_GE(range.start, ranges[last_range - (i + 1)].end);
+#endif
+      run_index =
+          CopyRangeInternal(run_index, range.start, range.end, range.target);
+    }
+    return;
+  }
+
+  unsigned run_index = 0;
+  for (unsigned i = 0; i < num_ranges; i++) {
+    const ShapeRange& range = ranges[i];
+#if DCHECK_IS_ON()
+    DCHECK_GE(range.end, range.start);
+    if (i)
+      DCHECK_GE(range.start, ranges[i - 1].end);
+#endif
+    run_index =
+        CopyRangeInternal(run_index, range.start, range.end, range.target);
+  }
+}
+
+unsigned ShapeResult::CopyRangeInternal(unsigned run_index,
+                                        unsigned start_offset,
+                                        unsigned end_offset,
+                                        ShapeResult* target) const {
 #if DCHECK_IS_ON()
   unsigned target_num_characters_before = target->num_characters_;
 #endif
@@ -1337,7 +1379,7 @@
           : target->EndIndex() - std::max(start_offset, StartIndex());
   unsigned target_run_size_before = target->runs_.size();
   float total_width = 0;
-  unsigned run_index = start_run_index ? *start_run_index : 0;
+  //run_index = 0;
   for (; run_index < runs_.size(); run_index++) {
     const auto& run = runs_[run_index];
     unsigned run_start = run->start_index_;
@@ -1357,11 +1399,7 @@
 
       // No need to process runs after the end of the range.
       if ((!Rtl() && end_offset <= run_end) ||
-          (Rtl() && start_offset > run_start)) {
-        // RTL cannot use |start_run_index| because runs are in the descending
-        // order.
-        if (!Rtl() && start_run_index)
-          *start_run_index = run_index;
+          (Rtl() && start_offset >= run_start)) {
         break;
       }
     }
@@ -1369,7 +1407,7 @@
 
   if (!target->num_glyphs_) {
     target->UpdateStartIndex();
-    return;
+    return run_index;
   }
 
   // Runs in RTL result are in visual order, and that new runs should be
@@ -1406,18 +1444,17 @@
   DCHECK_EQ(
       target->num_characters_ - target_num_characters_before,
       std::min(end_offset, EndIndex()) - std::max(start_offset, StartIndex()));
-
   target->CheckConsistency();
 #endif
+
+  return run_index;
 }
 
-scoped_refptr<ShapeResult> ShapeResult::SubRange(
-    unsigned start_offset,
-    unsigned end_offset,
-    unsigned* start_run_index) const {
+scoped_refptr<ShapeResult> ShapeResult::SubRange(unsigned start_offset,
+                                                 unsigned end_offset) const {
   scoped_refptr<ShapeResult> sub_range =
       Create(primary_font_.get(), 0, Direction());
-  CopyRange(start_offset, end_offset, sub_range.get(), start_run_index);
+  CopyRange(start_offset, end_offset, sub_range.get());
   return sub_range;
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 0f32f46..90861cb 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -113,6 +112,10 @@
                                     TextDirection direction) {
     return base::AdoptRef(new ShapeResult(font, num_characters, direction));
   }
+  static scoped_refptr<ShapeResult> CreateEmpty(const ShapeResult& other) {
+    return base::AdoptRef(
+        new ShapeResult(other.primary_font_, 0, other.Direction()));
+  }
   static scoped_refptr<ShapeResult> Create(const ShapeResult& other) {
     return base::AdoptRef(new ShapeResult(other));
   }
@@ -246,26 +249,25 @@
 
   // Append a copy of a range within an existing result to another result.
   //
-  // For sequential copies the opaque_context in/out parameter can be used to
-  // improve performance by avoding a linear scan to find the first run for the
-  // range. It should be set to zero for the first call and the resulting out
-  // value for one call is the appropiate input value for the next.
-  // NOTE: opaque_context assumes non-overlapping ranges.
-  void CopyRange(unsigned start,
-                 unsigned end,
-                 ShapeResult*,
-                 unsigned* opaque_context = nullptr) const;
+  // For sequential copies the vector version below is prefered as it avoid a
+  // linear scan to find the first run for the range.
+  void CopyRange(unsigned start, unsigned end, ShapeResult*) const;
+
+  struct ShapeRange {
+    // ShapeRange(unsigned start, unsigned end, ShapeResult* target)
+    //    : start(start), end(end), target(target){};
+    unsigned start;
+    unsigned end;
+    ShapeResult* target;
+  };
+
+  // Copy a set of sequential ranges. The ranges may not overlap and the offsets
+  // must be sequential and monotically increasing.
+  void CopyRanges(const ShapeRange* ranges, unsigned num_ranges) const;
 
   // Create a new ShapeResult instance from a range within an existing result.
-  //
-  // For sequential copies the opaque_context in/out parameter can be used to
-  // improve performance by avoding a linear scan to find the first run for the
-  // range. It should be set to zero for the first call and the resulting out
-  // value for one call is the appropiate input value for the next.
-  // NOTE: opaque_context assumes non-overlapping ranges.
   scoped_refptr<ShapeResult> SubRange(unsigned start_offset,
-                                      unsigned end_offset,
-                                      unsigned* opaque_context = nullptr) const;
+                                      unsigned end_offset) const;
 
   // Create a new ShapeResult instance with the start offset adjusted.
   scoped_refptr<ShapeResult> CopyAdjustedOffset(unsigned start_offset) const;
@@ -402,6 +404,17 @@
     friend class ShapeResult;
   };
 
+  // Append a copy of a range within an existing result to another result.
+  //
+  // For sequential copies the run_index argument indicates the run to start at.
+  // If set to zero it will always scan from the first run which is guaranteed
+  // to produce the correct results at the cost of run-time performance.
+  // Returns the appropriate run_index for the next sequential invocation.
+  unsigned CopyRangeInternal(unsigned run_index,
+                             unsigned start,
+                             unsigned end,
+                             ShapeResult* target) const;
+
   template <bool>
   void ComputePositionData() const;
 
@@ -447,6 +460,7 @@
   friend class ShapeResultBuffer;
   friend class ShapeResultBloberizer;
   friend class ShapeResultView;
+  friend class ShapeResultTest;
 };
 
 PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const ShapeResult&);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
index 2e03906..0e70769 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
@@ -112,12 +112,14 @@
 }
 
 class GlyphCallbackContext {
-  WTF_MAKE_NONCOPYABLE(GlyphCallbackContext);
   STACK_ALLOCATED();
 
  public:
   ShapeResultBloberizer* bloberizer;
   const StringView& text;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GlyphCallbackContext);
 };
 
 void AddGlyphToBloberizer(void* context,
@@ -171,7 +173,6 @@
 }
 
 class ClusterCallbackContext {
-  WTF_MAKE_NONCOPYABLE(ClusterCallbackContext);
   STACK_ALLOCATED();
 
  public:
@@ -179,6 +180,9 @@
   const StringView& text;
   const GlyphData& emphasis_data;
   FloatPoint glyph_center;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ClusterCallbackContext);
 };
 
 void AddEmphasisMarkToBloberizer(void* context,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
index 2183219..589f4af9 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
@@ -21,7 +21,6 @@
 struct TextRunPaintInfo;
 
 class PLATFORM_EXPORT ShapeResultBloberizer {
-  WTF_MAKE_NONCOPYABLE(ShapeResultBloberizer);
   STACK_ALLOCATED();
 
  public:
@@ -139,6 +138,8 @@
 
   // Constructed blobs.
   BlobBuffer blobs_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShapeResultBloberizer);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h
index f089b7fb..12821956 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h
@@ -20,7 +20,6 @@
 class TextRun;
 
 class PLATFORM_EXPORT ShapeResultBuffer {
-  WTF_MAKE_NONCOPYABLE(ShapeResultBuffer);
   STACK_ALLOCATED();
 
  public:
@@ -79,6 +78,8 @@
   // rare.
   Vector<scoped_refptr<const ShapeResult>, 64> results_;
   bool has_vertical_offsets_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShapeResultBuffer);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
index 4ad568d..30ab296 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
@@ -36,7 +36,6 @@
 #include <memory>
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
new file mode 100644
index 0000000..e2ca15b
--- /dev/null
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
@@ -0,0 +1,231 @@
+// 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.
+
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/fonts/font_cache.h"
+#include "third_party/blink/renderer/platform/fonts/font_test_utilities.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h"
+#include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+class ShapeResultTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    font_description.SetComputedSize(12.0);
+    font = Font(font_description);
+    font.Update(nullptr);
+
+    FontDescription::VariantLigatures ligatures;
+    arabic_font = blink::test::CreateTestFont(
+        "Noto",
+        blink::test::PlatformTestDataPath(
+            "third_party/Noto/NotoNaskhArabic-regular.woff2"),
+        12.0, &ligatures);
+  }
+
+  void TearDown() override {}
+
+  void TestCopyRangesLatin(const ShapeResult*) const;
+  void TestCopyRangesArabic(const ShapeResult*) const;
+
+  ShapeResult* CreateShapeResult(TextDirection direction) const {
+    return new ShapeResult(
+        direction == TextDirection::kLtr ? &font : &arabic_font, 0, direction);
+  }
+
+  FontCachePurgePreventer font_cache_purge_preventer;
+  FontDescription font_description;
+  Font font;
+  Font arabic_font;
+};
+
+void ShapeResultTest::TestCopyRangesLatin(const ShapeResult* result) const {
+  const unsigned num_ranges = 4;
+  ShapeResult::ShapeRange ranges[num_ranges] = {
+      {0, 10, CreateShapeResult(TextDirection::kLtr)},
+      {10, 20, CreateShapeResult(TextDirection::kLtr)},
+      {20, 30, CreateShapeResult(TextDirection::kLtr)},
+      {30, 38, CreateShapeResult(TextDirection::kLtr)}};
+  result->CopyRanges(&ranges[0], num_ranges);
+
+  Vector<ShapeResultTestGlyphInfo> glyphs[num_ranges];
+  for (unsigned i = 0; i < num_ranges; i++)
+    ComputeGlyphResults(*ranges[i].target, &glyphs[i]);
+  EXPECT_EQ(glyphs[0].size(), 10u);
+  EXPECT_EQ(glyphs[1].size(), 10u);
+  EXPECT_EQ(glyphs[2].size(), 10u);
+  EXPECT_EQ(glyphs[3].size(), 8u);
+
+  scoped_refptr<ShapeResult> reference[num_ranges];
+  reference[0] = result->SubRange(0, 10);
+  reference[1] = result->SubRange(10, 20);
+  reference[2] = result->SubRange(20, 30);
+  reference[3] = result->SubRange(30, 38);
+  Vector<ShapeResultTestGlyphInfo> reference_glyphs[num_ranges];
+  for (unsigned i = 0; i < num_ranges; i++)
+    ComputeGlyphResults(*reference[i], &reference_glyphs[i]);
+  EXPECT_EQ(reference_glyphs[0].size(), 10u);
+  EXPECT_EQ(reference_glyphs[1].size(), 10u);
+  EXPECT_EQ(reference_glyphs[2].size(), 10u);
+  EXPECT_EQ(reference_glyphs[3].size(), 8u);
+
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[0], reference_glyphs[0], 0u, 10u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[1], reference_glyphs[1], 0u, 10u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[2], reference_glyphs[2], 0u, 10u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[3], reference_glyphs[3], 0u, 8u));
+}
+
+void ShapeResultTest::TestCopyRangesArabic(const ShapeResult* result) const {
+  const unsigned num_ranges = 4;
+  ShapeResult::ShapeRange ranges[num_ranges] = {
+      {0, 4, CreateShapeResult(TextDirection::kRtl)},
+      {4, 7, CreateShapeResult(TextDirection::kRtl)},
+      {7, 10, CreateShapeResult(TextDirection::kRtl)},
+      {10, 15, CreateShapeResult(TextDirection::kRtl)}};
+  result->CopyRanges(&ranges[0], num_ranges);
+
+  Vector<ShapeResultTestGlyphInfo> glyphs[num_ranges];
+  for (unsigned i = 0; i < num_ranges; i++)
+    ComputeGlyphResults(*ranges[i].target, &glyphs[i]);
+  EXPECT_EQ(glyphs[0].size(), 4u);
+  EXPECT_EQ(glyphs[1].size(), 3u);
+  EXPECT_EQ(glyphs[2].size(), 3u);
+  EXPECT_EQ(glyphs[3].size(), 5u);
+
+  scoped_refptr<ShapeResult> reference[num_ranges];
+  reference[0] = result->SubRange(0, 4);
+  reference[1] = result->SubRange(4, 7);
+  reference[2] = result->SubRange(7, 10);
+  reference[3] = result->SubRange(10, 17);
+  Vector<ShapeResultTestGlyphInfo> reference_glyphs[num_ranges];
+  for (unsigned i = 0; i < num_ranges; i++)
+    ComputeGlyphResults(*reference[i], &reference_glyphs[i]);
+  EXPECT_EQ(reference_glyphs[0].size(), 4u);
+  EXPECT_EQ(reference_glyphs[1].size(), 3u);
+  EXPECT_EQ(reference_glyphs[2].size(), 3u);
+  EXPECT_EQ(reference_glyphs[3].size(), 5u);
+
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[0], reference_glyphs[0], 0u, 4u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[1], reference_glyphs[1], 0u, 3u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[2], reference_glyphs[2], 0u, 3u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[3], reference_glyphs[3], 0u, 5u));
+}
+
+TEST_F(ShapeResultTest, CopyRangeLatin) {
+  String string = "Testing ShapeResultIterator::CopyRange";
+  TextDirection direction = TextDirection::kLtr;
+
+  HarfBuzzShaper shaper(string);
+  scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
+  TestCopyRangesLatin(result.get());
+}
+
+// Identical to CopyRangeLatin except the source range shape result is split
+// into multiple runs to test the handling of ranges spanning runs and runs
+// spanning ranges.
+TEST_F(ShapeResultTest, CopyRangeLatinMultiRun) {
+  TextDirection direction = TextDirection::kLtr;
+  String string = "Testing ShapeResultIterator::CopyRange";
+  HarfBuzzShaper shaper_a(string.Substring(0, 5));
+  HarfBuzzShaper shaper_b(string.Substring(5, 7));
+  HarfBuzzShaper shaper_c(string.Substring(7, 32));
+  HarfBuzzShaper shaper_d(string.Substring(32, 38));
+
+  // Combine four separate results into a single one to ensure we have a result
+  // with multiple runs.
+  scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 0, direction);
+  shaper_a.Shape(&font, direction)->CopyRange(0u, 5u, result.get());
+  shaper_b.Shape(&font, direction)->CopyRange(0u, 2u, result.get());
+  shaper_c.Shape(&font, direction)->CopyRange(0u, 25u, result.get());
+  shaper_d.Shape(&font, direction)->CopyRange(0u, 6u, result.get());
+  TestCopyRangesLatin(result.get());
+}
+
+TEST_F(ShapeResultTest, CopyRangeLatinMultiRunWithHoles) {
+  TextDirection direction = TextDirection::kLtr;
+  String string = "Testing copying a range with holes";
+  HarfBuzzShaper shaper_a(string.Substring(0, 5));
+  HarfBuzzShaper shaper_b(string.Substring(5, 7));
+  HarfBuzzShaper shaper_c(string.Substring(7, 32));
+  HarfBuzzShaper shaper_d(string.Substring(32, 34));
+
+  scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 0, direction);
+  shaper_a.Shape(&font, direction)->CopyRange(0u, 5u, result.get());
+  shaper_b.Shape(&font, direction)->CopyRange(0u, 2u, result.get());
+  shaper_c.Shape(&font, direction)->CopyRange(0u, 25u, result.get());
+  shaper_d.Shape(&font, direction)->CopyRange(0u, 2u, result.get());
+
+  ShapeResult::ShapeRange ranges[] = {
+      {4, 17, CreateShapeResult(TextDirection::kLtr)},
+      {20, 23, CreateShapeResult(TextDirection::kLtr)},
+      {25, 31, CreateShapeResult(TextDirection::kLtr)}};
+  result->CopyRanges(&ranges[0], 3);
+  Vector<ShapeResultTestGlyphInfo> glyphs[3];
+  ComputeGlyphResults(*ranges[0].target, &glyphs[0]);
+  ComputeGlyphResults(*ranges[1].target, &glyphs[1]);
+  ComputeGlyphResults(*ranges[2].target, &glyphs[2]);
+  EXPECT_EQ(glyphs[0].size(), 13u);
+  EXPECT_EQ(glyphs[1].size(), 3u);
+  EXPECT_EQ(glyphs[2].size(), 6u);
+
+  scoped_refptr<ShapeResult> reference[3];
+  reference[0] = result->SubRange(4, 17);
+  reference[1] = result->SubRange(20, 23);
+  reference[2] = result->SubRange(25, 31);
+  Vector<ShapeResultTestGlyphInfo> reference_glyphs[3];
+  ComputeGlyphResults(*reference[0], &reference_glyphs[0]);
+  ComputeGlyphResults(*reference[1], &reference_glyphs[1]);
+  ComputeGlyphResults(*reference[2], &reference_glyphs[2]);
+  EXPECT_EQ(reference_glyphs[0].size(), 13u);
+  EXPECT_EQ(reference_glyphs[1].size(), 3u);
+  EXPECT_EQ(reference_glyphs[2].size(), 6u);
+
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[0], reference_glyphs[0], 0u, 13u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[1], reference_glyphs[1], 0u, 3u));
+  EXPECT_TRUE(CompareResultGlyphs(glyphs[2], reference_glyphs[2], 0u, 6u));
+}
+
+TEST_F(ShapeResultTest, CopyRangeArabic) {
+  // نص اختبار العربية
+  String string(
+      u"\u0646\u0635\u0627\u062E\u062A\u0628\u0627\u0631\u0627\u0644\u0639"
+      u"\u0631\u0628\u064A\u0629");
+  TextDirection direction = TextDirection::kRtl;
+
+  HarfBuzzShaper shaper(string);
+  scoped_refptr<ShapeResult> result = shaper.Shape(&arabic_font, direction);
+  TestCopyRangesArabic(result.get());
+}
+
+// Identical to CopyRangeArabic except the source range shape result is split
+// into multiple runs to test the handling of ranges spanning runs and runs
+// spanning ranges.
+TEST_F(ShapeResultTest, CopyRangeArabicMultiRun) {
+  // نص اختبار العربية
+  String string(
+      u"\u0646\u0635\u0627\u062E\u062A\u0628\u0627\u0631\u0627\u0644\u0639"
+      u"\u0631\u0628\u064A\u0629");
+  TextDirection direction = TextDirection::kRtl;
+
+  HarfBuzzShaper shaper_a(string.Substring(0, 2));
+  HarfBuzzShaper shaper_b(string.Substring(2, 9));
+  HarfBuzzShaper shaper_c(string.Substring(9, 15));
+
+  // Combine three separate results into a single one to ensure we have a result
+  // with multiple runs.
+  scoped_refptr<ShapeResult> result =
+      ShapeResult::Create(&arabic_font, 0, direction);
+  shaper_a.Shape(&arabic_font, direction)->CopyRange(0u, 2u, result.get());
+  shaper_b.Shape(&arabic_font, direction)->CopyRange(0u, 7u, result.get());
+  shaper_c.Shape(&arabic_font, direction)->CopyRange(0u, 8u, result.get());
+
+  TestCopyRangesArabic(result.get());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc
index 49baaaf..8a1bbf5 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc
@@ -68,4 +68,74 @@
   return character_indexes;
 }
 
+void AddGlyphInfo(void* context,
+                  unsigned character_index,
+                  Glyph glyph,
+                  FloatSize glyph_offset,
+                  float advance,
+                  bool is_horizontal,
+                  CanvasRotationInVertical rotation,
+                  const SimpleFontData* font_data) {
+  auto* list = static_cast<Vector<ShapeResultTestGlyphInfo>*>(context);
+  ShapeResultTestGlyphInfo glyph_info = {character_index, glyph, advance};
+  list->push_back(glyph_info);
+}
+
+void ComputeGlyphResults(const ShapeResult& result,
+                         Vector<ShapeResultTestGlyphInfo>* glyphs) {
+  result.ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(glyphs));
+}
+
+bool CompareResultGlyphs(const Vector<ShapeResultTestGlyphInfo>& test,
+                         const Vector<ShapeResultTestGlyphInfo>& reference,
+                         unsigned reference_start,
+                         unsigned num_glyphs) {
+  float advance_offset = reference[reference_start].advance;
+  bool glyphs_match = true;
+  for (unsigned i = 0; i < test.size(); i++) {
+    const auto& test_glyph = test[i];
+    const auto& reference_glyph = reference[i + reference_start];
+    if (test_glyph.character_index != reference_glyph.character_index ||
+        test_glyph.glyph != reference_glyph.glyph ||
+        test_glyph.advance != reference_glyph.advance - advance_offset) {
+      glyphs_match = false;
+      break;
+    }
+  }
+  if (!glyphs_match) {
+    fprintf(stderr, "╔══ Actual ═══════╤═══════╤═════════╗    ");
+    fprintf(stderr, "╔══ Expected ═════╤═══════╤═════════╗\n");
+    fprintf(stderr, "║ Character Index │ Glyph │ Advance ║    ");
+    fprintf(stderr, "║ Character Index │ Glyph │ Advance ║\n");
+    fprintf(stderr, "╟─────────────────┼───────┼─────────╢    ");
+    fprintf(stderr, "╟─────────────────┼───────┼─────────╢\n");
+    for (unsigned i = 0; i < test.size(); i++) {
+      const auto& test_glyph = test[i];
+      const auto& reference_glyph = reference[i + reference_start];
+
+      if (test_glyph.character_index == reference_glyph.character_index)
+        fprintf(stderr, "║      %10u │", test_glyph.character_index);
+      else
+        fprintf(stderr, "║▶     %10u◀│", test_glyph.character_index);
+
+      if (test_glyph.glyph == reference_glyph.glyph)
+        fprintf(stderr, "  %04X │", test_glyph.glyph);
+      else
+        fprintf(stderr, "▶ %04X◀│", test_glyph.glyph);
+
+      if (test_glyph.advance == reference_glyph.advance)
+        fprintf(stderr, " %7.2f ║    ", test_glyph.advance);
+      else
+        fprintf(stderr, "▶%7.2f◀║    ", test_glyph.advance);
+
+      fprintf(stderr, "║      %10u │  %04X │ %7.2f ║\n",
+              reference_glyph.character_index, reference_glyph.glyph,
+              reference_glyph.advance - advance_offset);
+    }
+    fprintf(stderr, "╚═════════════════╧═══════╧═════════╝    ");
+    fprintf(stderr, "╚═════════════════╧═══════╧═════════╝\n");
+  }
+  return glyphs_match;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h
index 27cc6a4..039b216 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h
@@ -67,6 +67,30 @@
   }
 };
 
+struct PLATFORM_EXPORT ShapeResultTestGlyphInfo {
+  unsigned character_index;
+  Glyph glyph;
+  float advance;
+};
+
+void PLATFORM_EXPORT AddGlyphInfo(void* context,
+                                  unsigned character_index,
+                                  Glyph,
+                                  FloatSize glyph_offset,
+                                  float advance,
+                                  bool is_horizontal,
+                                  CanvasRotationInVertical,
+                                  const SimpleFontData*);
+
+void PLATFORM_EXPORT ComputeGlyphResults(const ShapeResult&,
+                                         Vector<ShapeResultTestGlyphInfo>*);
+
+bool PLATFORM_EXPORT
+CompareResultGlyphs(const Vector<ShapeResultTestGlyphInfo>& test,
+                    const Vector<ShapeResultTestGlyphInfo>& reference,
+                    unsigned reference_start,
+                    unsigned num_glyphs);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_TEST_INFO_H_
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
index 214fd54..e6cbd2b 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
index 04af141c..8a96202 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_test_utilities.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
 
 namespace blink {
@@ -30,81 +31,6 @@
   Font font;
 };
 
-namespace {
-
-struct ShapeResultViewGlyphInfo {
-  unsigned character_index;
-  Glyph glyph;
-  float advance;
-};
-
-void AddGlyphInfo(void* context,
-                  unsigned character_index,
-                  Glyph glyph,
-                  FloatSize glyph_offset,
-                  float advance,
-                  bool is_horizontal,
-                  CanvasRotationInVertical rotation,
-                  const SimpleFontData* font_data) {
-  auto* list = static_cast<Vector<ShapeResultViewGlyphInfo>*>(context);
-  ShapeResultViewGlyphInfo glyph_info = {character_index, glyph, advance};
-  list->push_back(glyph_info);
-}
-
-bool CompareResultGlyphs(const Vector<ShapeResultViewGlyphInfo>& test,
-                         const Vector<ShapeResultViewGlyphInfo>& reference,
-                         unsigned reference_start,
-                         unsigned num_glyphs) {
-  float advance_offset = reference[reference_start].advance;
-  bool glyphs_match = true;
-  for (unsigned i = 0; i < test.size(); i++) {
-    const auto& test_glyph = test[i];
-    const auto& reference_glyph = reference[i + reference_start];
-    if (test_glyph.character_index != reference_glyph.character_index ||
-        test_glyph.glyph != reference_glyph.glyph ||
-        test_glyph.advance != reference_glyph.advance - advance_offset) {
-      glyphs_match = false;
-      break;
-    }
-  }
-  if (!glyphs_match) {
-    fprintf(stderr, "╔══ Actual ═══════╤═══════╤═════════╗    ");
-    fprintf(stderr, "╔══ Expected ═════╤═══════╤═════════╗\n");
-    fprintf(stderr, "║ Character Index │ Glyph │ Advance ║    ");
-    fprintf(stderr, "║ Character Index │ Glyph │ Advance ║\n");
-    fprintf(stderr, "╟─────────────────┼───────┼─────────╢    ");
-    fprintf(stderr, "╟─────────────────┼───────┼─────────╢\n");
-    for (unsigned i = 0; i < test.size(); i++) {
-      const auto& test_glyph = test[i];
-      const auto& reference_glyph = reference[i + reference_start];
-
-      if (test_glyph.character_index == reference_glyph.character_index)
-        fprintf(stderr, "║      %10u │", test_glyph.character_index);
-      else
-        fprintf(stderr, "║▶     %10u◀│", test_glyph.character_index);
-
-      if (test_glyph.glyph == reference_glyph.glyph)
-        fprintf(stderr, "  %04X │", test_glyph.glyph);
-      else
-        fprintf(stderr, "▶ %04X◀│", test_glyph.glyph);
-
-      if (test_glyph.advance == reference_glyph.advance)
-        fprintf(stderr, " %7.2f ║    ", test_glyph.advance);
-      else
-        fprintf(stderr, "▶%7.2f◀║    ", test_glyph.advance);
-
-      fprintf(stderr, "║      %10u │  %04X │ %7.2f ║\n",
-              reference_glyph.character_index, reference_glyph.glyph,
-              reference_glyph.advance - advance_offset);
-    }
-    fprintf(stderr, "╚═════════════════╧═══════╧═════════╝    ");
-    fprintf(stderr, "╚═════════════════╧═══════╧═════════╝\n");
-  }
-  return glyphs_match;
-}
-
-}  // anonymous namespace
-
 TEST_F(ShapeResultViewTest, LatinSingleView) {
   String string =
       To16Bit("Test run with multiple words and breaking opportunities.", 56);
@@ -112,7 +38,7 @@
 
   HarfBuzzShaper shaper(string);
   scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> glyphs;
+  Vector<ShapeResultTestGlyphInfo> glyphs;
   result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs));
 
   // Test view at the start of the result: "Test run with multiple"
@@ -123,7 +49,7 @@
   EXPECT_EQ(first4->NumCharacters(), 22u);
   EXPECT_EQ(first4->NumGlyphs(), 22u);
 
-  Vector<ShapeResultViewGlyphInfo> first4_glyphs;
+  Vector<ShapeResultTestGlyphInfo> first4_glyphs;
   first4->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&first4_glyphs));
   EXPECT_EQ(first4_glyphs.size(), 22u);
   EXPECT_TRUE(CompareResultGlyphs(first4_glyphs, glyphs, 0u, 22u));
@@ -136,7 +62,7 @@
   EXPECT_EQ(middle4->NumCharacters(), 27u);
   EXPECT_EQ(middle4->NumGlyphs(), 27u);
 
-  Vector<ShapeResultViewGlyphInfo> middle4_glyphs;
+  Vector<ShapeResultTestGlyphInfo> middle4_glyphs;
   middle4->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&middle4_glyphs));
   EXPECT_EQ(middle4_glyphs.size(), 27u);
   EXPECT_TRUE(CompareResultGlyphs(middle4_glyphs, glyphs, 14u, 27u));
@@ -149,7 +75,7 @@
   EXPECT_EQ(last2->NumCharacters(), 23u);
   EXPECT_EQ(last2->NumGlyphs(), 23u);
 
-  Vector<ShapeResultViewGlyphInfo> last2_glyphs;
+  Vector<ShapeResultTestGlyphInfo> last2_glyphs;
   last2->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&last2_glyphs));
   EXPECT_EQ(last2_glyphs.size(), 23u);
   EXPECT_TRUE(CompareResultGlyphs(last2_glyphs, glyphs, 33u, 23u));
@@ -161,13 +87,13 @@
 
   HarfBuzzShaper shaper(string);
   scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> glyphs;
+  Vector<ShapeResultTestGlyphInfo> glyphs;
   result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs));
 
   // Test view at the start of the result: "عربى"
   ShapeResultView::Segment segment = {result.get(), 0, 4};
   auto first_word = ShapeResultView::Create(&segment, 1);
-  Vector<ShapeResultViewGlyphInfo> first_glyphs;
+  Vector<ShapeResultTestGlyphInfo> first_glyphs;
   first_word->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&first_glyphs));
 
   EXPECT_EQ(first_word->StartIndex(), 0u);
@@ -179,7 +105,7 @@
   HarfBuzzShaper first_reference_shaper(first_reference_string);
   scoped_refptr<const ShapeResult> first_wortd_reference =
       first_reference_shaper.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> first_reference_glyphs;
+  Vector<ShapeResultTestGlyphInfo> first_reference_glyphs;
   first_wortd_reference->ForEachGlyph(
       0, AddGlyphInfo, static_cast<void*>(&first_reference_glyphs));
   EXPECT_EQ(first_reference_glyphs.size(), 4u);
@@ -191,7 +117,7 @@
   // Test view at the end of the result: "نص"
   segment = {result.get(), 4, 7};
   auto last_word = ShapeResultView::Create(&segment, 1);
-  Vector<ShapeResultViewGlyphInfo> last_glyphs;
+  Vector<ShapeResultTestGlyphInfo> last_glyphs;
   last_word->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&last_glyphs));
 
   EXPECT_EQ(last_word->StartIndex(), 4u);
@@ -215,7 +141,7 @@
   shaper_c.Shape(&font, direction)->CopyRange(0u, 4u, result.get());
   shaper_d.Shape(&font, direction)->CopyRange(0u, 1u, result.get());
 
-  Vector<ShapeResultViewGlyphInfo> result_glyphs;
+  Vector<ShapeResultTestGlyphInfo> result_glyphs;
   result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&result_glyphs));
 
   // Create composite view out of multiple segments where at least some of the
@@ -228,7 +154,7 @@
       {result.get(), 9, 12},   // "ld!"
   };
   auto composite_view = ShapeResultView::Create(&segments[0], 5);
-  Vector<ShapeResultViewGlyphInfo> view_glyphs;
+  Vector<ShapeResultTestGlyphInfo> view_glyphs;
   composite_view->ForEachGlyph(0, AddGlyphInfo,
                                static_cast<void*>(&view_glyphs));
 
@@ -239,14 +165,14 @@
 
   HarfBuzzShaper shaper2(To16Bit("hello world!", 12));
   scoped_refptr<const ShapeResult> result2 = shaper2.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> glyphs2;
+  Vector<ShapeResultTestGlyphInfo> glyphs2;
   result2->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs2));
   EXPECT_TRUE(CompareResultGlyphs(result_glyphs, glyphs2, 0u, 12u));
 
   HarfBuzzShaper reference_shaper(To16Bit("hello wood wold!", 16));
   scoped_refptr<const ShapeResult> reference_result =
       reference_shaper.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> reference_glyphs;
+  Vector<ShapeResultTestGlyphInfo> reference_glyphs;
   reference_result->ForEachGlyph(0, AddGlyphInfo,
                                  static_cast<void*>(&reference_glyphs));
 
@@ -258,7 +184,7 @@
   result->CopyRange(5, 8, composite_copy.get());
   result->CopyRange(9, 12, composite_copy.get());
 
-  Vector<ShapeResultViewGlyphInfo> composite_copy_glyphs;
+  Vector<ShapeResultTestGlyphInfo> composite_copy_glyphs;
   composite_copy->ForEachGlyph(0, AddGlyphInfo,
                                static_cast<void*>(&composite_copy_glyphs));
 
@@ -274,14 +200,14 @@
 
   HarfBuzzShaper shaper(string);
   scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> glyphs;
+  Vector<ShapeResultTestGlyphInfo> glyphs;
   result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs));
 
   String reference_string = To16Bit("multiple breaking opportunities Test", 36);
   HarfBuzzShaper reference_shaper(reference_string);
   scoped_refptr<const ShapeResult> reference_result =
       reference_shaper.Shape(&font, direction);
-  Vector<ShapeResultViewGlyphInfo> reference_glyphs;
+  Vector<ShapeResultTestGlyphInfo> reference_glyphs;
 
   // Match the character index logic of ShapeResult::CopyRange where the the
   // character index of the first result is preserved and all subsequent ones
@@ -312,7 +238,7 @@
   EXPECT_EQ(composite_view->NumCharacters(), reference_result->NumCharacters());
   EXPECT_EQ(composite_view->NumGlyphs(), reference_result->NumGlyphs());
 
-  Vector<ShapeResultViewGlyphInfo> composite_glyphs;
+  Vector<ShapeResultTestGlyphInfo> composite_glyphs;
   composite_view->ForEachGlyph(0, AddGlyphInfo,
                                static_cast<void*>(&composite_glyphs));
   EXPECT_EQ(composite_glyphs.size(), 36u);
@@ -344,7 +270,7 @@
   result_b->CopyRange(0, 7, composite_copy.get());
   EXPECT_EQ(composite_copy->NumCharacters(), reference_result->NumCharacters());
   EXPECT_EQ(composite_copy->NumGlyphs(), reference_result->NumGlyphs());
-  Vector<ShapeResultViewGlyphInfo> reference_glyphs;
+  Vector<ShapeResultTestGlyphInfo> reference_glyphs;
   composite_copy->ForEachGlyph(0, AddGlyphInfo,
                                static_cast<void*>(&reference_glyphs));
 
@@ -356,7 +282,7 @@
   EXPECT_EQ(composite_view->NumCharacters(), reference_result->NumCharacters());
   EXPECT_EQ(composite_view->NumGlyphs(), reference_result->NumGlyphs());
 
-  Vector<ShapeResultViewGlyphInfo> composite_glyphs;
+  Vector<ShapeResultTestGlyphInfo> composite_glyphs;
   composite_view->ForEachGlyph(0, AddGlyphInfo,
                                static_cast<void*>(&composite_glyphs));
   EXPECT_TRUE(CompareResultGlyphs(composite_glyphs, reference_glyphs, 0u,
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h
index 055acaf..7cf3793 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.h
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -178,7 +178,6 @@
 
   struct DerivedFontData {
     USING_FAST_MALLOC(DerivedFontData);
-    WTF_MAKE_NONCOPYABLE(DerivedFontData);
 
    public:
     static std::unique_ptr<DerivedFontData> Create();
@@ -188,6 +187,8 @@
 
    private:
     DerivedFontData() = default;
+
+    DISALLOW_COPY_AND_ASSIGN(DerivedFontData);
   };
 
   mutable std::unique_ptr<DerivedFontData> derived_font_data_;
diff --git a/third_party/blink/renderer/platform/fonts/small_caps_iterator.h b/third_party/blink/renderer/platform/fonts/small_caps_iterator.h
index 6753fcaf..294a46a 100644
--- a/third_party/blink/renderer/platform/fonts/small_caps_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/small_caps_iterator.h
@@ -6,17 +6,17 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SMALL_CAPS_ITERATOR_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/fonts/font_orientation.h"
 #include "third_party/blink/renderer/platform/fonts/script_run_iterator.h"
 #include "third_party/blink/renderer/platform/fonts/utf16_text_iterator.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT SmallCapsIterator {
   USING_FAST_MALLOC(SmallCapsIterator);
-  WTF_MAKE_NONCOPYABLE(SmallCapsIterator);
 
  public:
   enum SmallCapsBehavior {
@@ -37,6 +37,8 @@
 
   SmallCapsBehavior current_small_caps_behavior_;
   SmallCapsBehavior previous_small_caps_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SmallCapsIterator);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/symbols_iterator.h b/third_party/blink/renderer/platform/fonts/symbols_iterator.h
index c6ea4ff..b6343c1 100644
--- a/third_party/blink/renderer/platform/fonts/symbols_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/symbols_iterator.h
@@ -6,16 +6,16 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SYMBOLS_ITERATOR_H_
 
 #include <memory>
+
+#include "base/macros.h"
 #include "third_party/blink/renderer/platform/fonts/font_fallback_priority.h"
 #include "third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 namespace blink {
 
 class PLATFORM_EXPORT SymbolsIterator {
   USING_FAST_MALLOC(SymbolsIterator);
-  WTF_MAKE_NONCOPYABLE(SymbolsIterator);
 
  public:
   SymbolsIterator(const UChar* buffer, unsigned buffer_size);
@@ -28,6 +28,8 @@
 
   unsigned next_token_end_;
   bool next_token_emoji_;
+
+  DISALLOW_COPY_AND_ASSIGN(SymbolsIterator);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/vdmx_parser.cc b/third_party/blink/renderer/platform/fonts/vdmx_parser.cc
index cb178d56..a520527 100644
--- a/third_party/blink/renderer/platform/fonts/vdmx_parser.cc
+++ b/third_party/blink/renderer/platform/fonts/vdmx_parser.cc
@@ -30,9 +30,9 @@
 
 #include "third_party/blink/renderer/platform/fonts/vdmx_parser.h"
 
+#include "base/macros.h"
 #include "base/sys_byteorder.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -47,7 +47,6 @@
 // updating the current offset otherwise.
 class Buffer {
   STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(Buffer);
 
  public:
   Buffer(const uint8_t* buffer, size_t length)
@@ -89,6 +88,8 @@
   const uint8_t* const buffer_;
   const size_t length_;
   size_t offset_;
+
+  DISALLOW_COPY_AND_ASSIGN(Buffer);
 };
 
 }  // namespace
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 2eecbd9a9..46048212 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -786,4 +786,88 @@
   return context_provider_wrapper_;
 }
 
+// ExternalCanvasResource
+//==============================================================================
+scoped_refptr<ExternalCanvasResource> ExternalCanvasResource::Create(
+    const gpu::Mailbox& mailbox,
+    const IntSize& size,
+    GLenum texture_target,
+    const CanvasColorParams& color_params,
+    base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
+    base::WeakPtr<CanvasResourceProvider> provider,
+    SkFilterQuality filter_quality) {
+  TRACE_EVENT0("blink", "ExternalCanvasResource::Create");
+  auto resource = AdoptRef(
+      new ExternalCanvasResource(mailbox, size, texture_target, color_params,
+                                 std::move(context_provider_wrapper),
+                                 std::move(provider), filter_quality));
+  return resource->IsValid() ? resource : nullptr;
+}
+
+ExternalCanvasResource::~ExternalCanvasResource() {
+  OnDestroy();
+}
+
+bool ExternalCanvasResource::IsValid() const {
+  return !!context_provider_wrapper_ && !mailbox_.IsZero();
+}
+
+void ExternalCanvasResource::Abandon() {
+  mailbox_.SetZero();
+  sync_token_.Clear();
+}
+
+void ExternalCanvasResource::TakeSkImage(sk_sp<SkImage> image) {
+  NOTREACHED();
+}
+
+scoped_refptr<StaticBitmapImage> ExternalCanvasResource::Bitmap() {
+  NOTREACHED();
+  return nullptr;
+}
+
+void ExternalCanvasResource::TearDown() {
+  Abandon();
+}
+
+const gpu::Mailbox& ExternalCanvasResource::GetOrCreateGpuMailbox(
+    MailboxSyncMode sync_mode) {
+  TRACE_EVENT0("blink", "ExternalCanvasResource::GetOrCreateGpuMailbox");
+  DCHECK_EQ(sync_mode, kVerifiedSyncToken);
+  return mailbox_;
+}
+
+bool ExternalCanvasResource::HasGpuMailbox() const {
+  return !mailbox_.IsZero();
+}
+
+const gpu::SyncToken ExternalCanvasResource::GetSyncToken() {
+  TRACE_EVENT0("blink", "ExternalCanvasResource::GetSyncToken");
+  if (!sync_token_.HasData()) {
+    auto* gl = ContextGL();
+    if (gl)
+      gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
+  }
+  return sync_token_;
+}
+
+base::WeakPtr<WebGraphicsContext3DProviderWrapper>
+ExternalCanvasResource::ContextProviderWrapper() const {
+  return context_provider_wrapper_;
+}
+
+ExternalCanvasResource::ExternalCanvasResource(
+    const gpu::Mailbox& mailbox,
+    const IntSize& size,
+    GLenum texture_target,
+    const CanvasColorParams& color_params,
+    base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
+    base::WeakPtr<CanvasResourceProvider> provider,
+    SkFilterQuality filter_quality)
+    : CanvasResource(std::move(provider), filter_quality, color_params),
+      context_provider_wrapper_(std::move(context_provider_wrapper)),
+      size_(size),
+      texture_target_(texture_target),
+      mailbox_(mailbox) {}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.h b/third_party/blink/renderer/platform/graphics/canvas_resource.h
index 050e8ce1..e1497651 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -327,6 +327,7 @@
   bool IsValid() const final;
   IntSize Size() const final { return size_; }
   scoped_refptr<StaticBitmapImage> Bitmap() final;
+
   bool OriginClean() const final { return is_origin_clean_; }
   void SetOriginClean(bool value) final { is_origin_clean_ = value; }
   scoped_refptr<CanvasResource> MakeAccelerated(
@@ -365,6 +366,70 @@
   GLuint texture_id_ = 0u;
   bool is_overlay_candidate_ = false;
   IntSize size_;
+
+  bool is_origin_clean_ = true;
+};
+
+// Resource type for a given opaque external resource described on construction
+// via a Mailbox; this CanvasResource IsAccelerated() by definition.
+class PLATFORM_EXPORT ExternalCanvasResource final : public CanvasResource {
+ public:
+  static scoped_refptr<ExternalCanvasResource> Create(
+      const gpu::Mailbox&,
+      const IntSize&,
+      GLenum texture_target,
+      const CanvasColorParams&,
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
+      base::WeakPtr<CanvasResourceProvider>,
+      SkFilterQuality);
+  ~ExternalCanvasResource() override;
+  bool IsRecycleable() const final { return IsValid(); }
+  bool IsAccelerated() const final { return true; }
+  bool IsValid() const override;
+  bool SupportsAcceleratedCompositing() const override { return true; }
+  bool NeedsReadLockFences() const final { return false; }
+  bool OriginClean() const final { return is_origin_clean_; }
+  void SetOriginClean(bool value) final { is_origin_clean_ = value; }
+  scoped_refptr<CanvasResource> MakeAccelerated(
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>) final {
+    NOTREACHED();
+    return nullptr;
+  };
+  scoped_refptr<CanvasResource> MakeUnaccelerated() final {
+    NOTREACHED();
+    return nullptr;
+  }
+  void Abandon() final;
+  IntSize Size() const final { return size_; }
+  void TakeSkImage(sk_sp<SkImage> image) final;
+
+  scoped_refptr<StaticBitmapImage> Bitmap() override;
+
+ private:
+  void TearDown() override;
+  GLenum TextureTarget() const final { return texture_target_; }
+  bool IsOverlayCandidate() const final { return true; }
+  const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override;
+  bool HasGpuMailbox() const override;
+  const gpu::SyncToken GetSyncToken() override;
+  base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
+      const override;
+
+  ExternalCanvasResource(const gpu::Mailbox&,
+                         const IntSize&,
+                         GLenum texture_target,
+                         const CanvasColorParams&,
+                         base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
+                         base::WeakPtr<CanvasResourceProvider>,
+                         SkFilterQuality);
+
+  const base::WeakPtr<WebGraphicsContext3DProviderWrapper>
+      context_provider_wrapper_;
+  const IntSize size_;
+  const GLenum texture_target_;
+  gpu::Mailbox mailbox_;
+  gpu::SyncToken sync_token_;
+
   bool is_origin_clean_ = true;
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index bdb7f35..67baebc1 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -549,10 +549,57 @@
   scoped_refptr<CanvasResource> resource_;
 };
 
+// This class does nothing except answering to ProduceFrame() by piping it to
+// NewOrRecycledResource().  This ResourceProvider is meant to be used with an
+// imported external CanvasResource, and all drawing and lifetime logic must be
+// kept at a higher level.
+class CanvasResourceProviderPassThrough final : public CanvasResourceProvider {
+ public:
+  CanvasResourceProviderPassThrough(
+      const IntSize& size,
+      const CanvasColorParams color_params,
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>
+          context_provider_wrapper,
+      base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
+      : CanvasResourceProvider(size,
+                               color_params,
+                               std::move(context_provider_wrapper),
+                               std::move(resource_dispatcher)) {}
+
+  ~CanvasResourceProviderPassThrough() override = default;
+  bool IsValid() const final { return true; }
+  bool IsAccelerated() const final { return true; }
+  bool SupportsDirectCompositing() const override { return true; }
+  bool SupportsSingleBuffering() const override { return true; }
+
+ private:
+  scoped_refptr<CanvasResource> CreateResource() final {
+    // This class has no CanvasResource to provide: this must be imported via
+    // ImportResource() and kept in the parent class.
+    NOTREACHED();
+    return nullptr;
+  }
+
+  scoped_refptr<CanvasResource> ProduceFrame() final {
+    return NewOrRecycledResource();
+  }
+
+  sk_sp<SkSurface> CreateSkSurface() const override {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  scoped_refptr<StaticBitmapImage> Snapshot() override {
+    NOTREACHED();
+    return nullptr;
+  }
+};
+
 namespace {
 
 enum class CanvasResourceType {
-  kDirectGpuMemoryBuffer,
+  kDirect3DGpuMemoryBuffer,
+  kDirect2DGpuMemoryBuffer,
   kTextureGpuMemoryBuffer,
   kBitmapGpuMemoryBuffer,
   kSharedBitmap,
@@ -598,22 +645,41 @@
                     kSoftwareCompositedFallbackList.begin(),
                     kSoftwareCompositedFallbackList.end()));
 
-  static const std::vector<CanvasResourceType> kAcceleratedDirectFallbackList({
-      CanvasResourceType::kDirectGpuMemoryBuffer,
-      // The rest is equal to |kAcceleratedCompositedFallbackList|.
-      CanvasResourceType::kTextureGpuMemoryBuffer,
-      CanvasResourceType::kTexture,
-      // Fallback to software composited
-      CanvasResourceType::kBitmapGpuMemoryBuffer,
-      CanvasResourceType::kSharedBitmap,
-      // Fallback to no direct compositing support
-      CanvasResourceType::kBitmap,
-  });
-  DCHECK(std::equal(kAcceleratedDirectFallbackList.begin() + 1,
-                    kAcceleratedDirectFallbackList.end(),
+  static const std::vector<CanvasResourceType> kAcceleratedDirect2DFallbackList(
+      {
+          CanvasResourceType::kDirect2DGpuMemoryBuffer,
+          // The rest is equal to |kAcceleratedCompositedFallbackList|.
+          CanvasResourceType::kTextureGpuMemoryBuffer,
+          CanvasResourceType::kTexture,
+          // Fallback to software composited
+          CanvasResourceType::kBitmapGpuMemoryBuffer,
+          CanvasResourceType::kSharedBitmap,
+          // Fallback to no direct compositing support
+          CanvasResourceType::kBitmap,
+      });
+  DCHECK(std::equal(kAcceleratedDirect2DFallbackList.begin() + 1,
+                    kAcceleratedDirect2DFallbackList.end(),
                     kAcceleratedCompositedFallbackList.begin(),
                     kAcceleratedCompositedFallbackList.end()));
 
+  static const std::vector<CanvasResourceType> kAcceleratedDirect3DFallbackList(
+      {
+          CanvasResourceType::kDirect3DGpuMemoryBuffer,
+          CanvasResourceType::kDirect2DGpuMemoryBuffer,
+          // The rest is equal to |kAcceleratedCompositedFallbackList|.
+          CanvasResourceType::kTextureGpuMemoryBuffer,
+          CanvasResourceType::kTexture,
+          // Fallback to software composited
+          CanvasResourceType::kBitmapGpuMemoryBuffer,
+          CanvasResourceType::kSharedBitmap,
+          // Fallback to no direct compositing support
+          CanvasResourceType::kBitmap,
+      });
+  DCHECK(std::equal(kAcceleratedDirect3DFallbackList.begin() + 1,
+                    kAcceleratedDirect3DFallbackList.end(),
+                    kAcceleratedDirect2DFallbackList.begin(),
+                    kAcceleratedDirect2DFallbackList.end()));
+
   switch (usage) {
     case CanvasResourceProvider::kSoftwareResourceUsage:
       return kSoftwareFallbackList;
@@ -623,8 +689,10 @@
       return kAcceleratedFallbackList;
     case CanvasResourceProvider::kAcceleratedCompositedResourceUsage:
       return kAcceleratedCompositedFallbackList;
-    case CanvasResourceProvider::kAcceleratedDirectResourceUsage:
-      return kAcceleratedDirectFallbackList;
+    case CanvasResourceProvider::kAcceleratedDirect2DResourceUsage:
+      return kAcceleratedDirect2DFallbackList;
+    case CanvasResourceProvider::kAcceleratedDirect3DResourceUsage:
+      return kAcceleratedDirect3DFallbackList;
   }
   NOTREACHED();
 }
@@ -642,58 +710,55 @@
   std::unique_ptr<CanvasResourceProvider> provider;
   const std::vector<CanvasResourceType>& fallback_list =
       GetResourceTypeFallbackList(usage);
+
+  const bool is_gpu_memory_buffer_image_allowed =
+      SharedGpuContext::IsGpuCompositingEnabled() && context_provider_wrapper &&
+      presentation_mode == kAllowImageChromiumPresentationMode &&
+      gpu::IsImageSizeValidForGpuMemoryBufferFormat(
+          gfx::Size(size), color_params.GetBufferFormat()) &&
+      gpu::IsImageFromGpuMemoryBufferFormatSupported(
+          color_params.GetBufferFormat(),
+          context_provider_wrapper->ContextProvider()->GetCapabilities());
+
   for (CanvasResourceType resource_type : fallback_list) {
     // Note: We are deliberately not using std::move() on
     // |context_provider_wrapper| and |resource_dispatcher| to ensure that the
     // pointers remain valid for the next iteration of this loop if necessary.
     switch (resource_type) {
       case CanvasResourceType::kTextureGpuMemoryBuffer:
-        FALLTHROUGH;
-      case CanvasResourceType::kDirectGpuMemoryBuffer:
-        if (!SharedGpuContext::IsGpuCompositingEnabled())
+        if (!is_gpu_memory_buffer_image_allowed)
           continue;
-        if (presentation_mode != kAllowImageChromiumPresentationMode)
-          continue;
-        if (!context_provider_wrapper)
-          continue;
-        if (!gpu::IsImageFromGpuMemoryBufferFormatSupported(
-                color_params.GetBufferFormat(),
-                context_provider_wrapper->ContextProvider()
-                    ->GetCapabilities())) {
-          continue;
-        }
-        if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(
-                gfx::Size(size), color_params.GetBufferFormat())) {
-          continue;
-        }
         DCHECK_EQ(color_params.GLUnsizedInternalFormat(),
                   gpu::InternalFormatForGpuMemoryBufferFormat(
                       color_params.GetBufferFormat()));
-        if (resource_type == CanvasResourceType::kDirectGpuMemoryBuffer) {
-          provider =
-              std::make_unique<CanvasResourceProviderDirectGpuMemoryBuffer>(
-                  size, msaa_sample_count, color_params,
-                  context_provider_wrapper, resource_dispatcher,
-                  is_origin_top_left);
-        } else {
-          provider =
-              std::make_unique<CanvasResourceProviderTextureGpuMemoryBuffer>(
-                  size, msaa_sample_count, color_params,
-                  context_provider_wrapper, resource_dispatcher,
-                  is_origin_top_left);
-        }
+        provider =
+            std::make_unique<CanvasResourceProviderTextureGpuMemoryBuffer>(
+                size, msaa_sample_count, color_params, context_provider_wrapper,
+                resource_dispatcher, is_origin_top_left);
+        break;
+      case CanvasResourceType::kDirect2DGpuMemoryBuffer:
+        if (!is_gpu_memory_buffer_image_allowed)
+          continue;
+        DCHECK_EQ(color_params.GLUnsizedInternalFormat(),
+                  gpu::InternalFormatForGpuMemoryBufferFormat(
+                      color_params.GetBufferFormat()));
+        provider =
+            std::make_unique<CanvasResourceProviderDirectGpuMemoryBuffer>(
+                size, msaa_sample_count, color_params, context_provider_wrapper,
+                resource_dispatcher, is_origin_top_left);
+        break;
+      case CanvasResourceType::kDirect3DGpuMemoryBuffer:
+        if (!is_gpu_memory_buffer_image_allowed)
+          continue;
+        DCHECK_EQ(color_params.GLUnsizedInternalFormat(),
+                  gpu::InternalFormatForGpuMemoryBufferFormat(
+                      color_params.GetBufferFormat()));
+        provider = std::make_unique<CanvasResourceProviderPassThrough>(
+            size, color_params, context_provider_wrapper, resource_dispatcher);
         break;
       case CanvasResourceType::kBitmapGpuMemoryBuffer:
-        if (!SharedGpuContext::IsGpuCompositingEnabled())
-          continue;
-        if (presentation_mode != kAllowImageChromiumPresentationMode)
-          continue;
-        if (!context_provider_wrapper)
-          continue;
-        if (!Platform::Current()->GetGpuMemoryBufferManager())
-          continue;
-        if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(
-                gfx::Size(size), color_params.GetBufferFormat())) {
+        if (!is_gpu_memory_buffer_image_allowed ||
+            !Platform::Current()->GetGpuMemoryBufferManager()) {
           continue;
         }
         provider =
@@ -1083,4 +1148,13 @@
   SetResourceRecyclingEnabled(false);
 }
 
+bool CanvasResourceProvider::ImportResource(
+    scoped_refptr<CanvasResource> resource) {
+  if (!IsSingleBuffered() || !SupportsSingleBuffering())
+    return false;
+  canvas_resources_.clear();
+  canvas_resources_.push_back(std::move(resource));
+  return true;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 1d699f27..4659d39 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -54,7 +54,8 @@
     kSoftwareCompositedResourceUsage,
     kAcceleratedResourceUsage,
     kAcceleratedCompositedResourceUsage,
-    kAcceleratedDirectResourceUsage,
+    kAcceleratedDirect2DResourceUsage,
+    kAcceleratedDirect3DResourceUsage,
   };
 
   enum PresentationMode {
@@ -123,6 +124,9 @@
   // operation.
   void TryEnableSingleBuffering();
 
+  // Only works in single buffering mode.
+  bool ImportResource(scoped_refptr<CanvasResource>);
+
   void RecycleResource(scoped_refptr<CanvasResource>);
   void SetResourceRecyclingEnabled(bool);
   void ClearRecycledResources();
@@ -146,6 +150,10 @@
   void Clear();
   ~CanvasResourceProvider() override;
 
+  base::WeakPtr<CanvasResourceProvider> CreateWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
  protected:
   gpu::gles2::GLES2Interface* ContextGL() const;
   GrContext* GetGrContext() const;
@@ -153,9 +161,6 @@
     return context_provider_wrapper_;
   }
   SkFilterQuality FilterQuality() const { return filter_quality_; }
-  base::WeakPtr<CanvasResourceProvider> CreateWeakPtr() {
-    return weak_ptr_factory_.GetWeakPtr();
-  }
   scoped_refptr<StaticBitmapImage> SnapshotInternal();
 
   CanvasResourceProvider(const IntSize&,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
index 90bf30b..a6a31c9 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/platform/graphics/test/gpu_memory_buffer_test_platform.h"
@@ -142,6 +143,7 @@
   const IntSize kSize(10, 10);
   const CanvasColorParams kColorParams(kSRGBCanvasColorSpace,
                                        kRGBA8CanvasPixelFormat, kNonOpaque);
+  EnsureBufferFormatIsSupported(kColorParams.GetBufferFormat());
 
   auto provider = CanvasResourceProvider::Create(
       kSize, CanvasResourceProvider::kSoftwareCompositedResourceUsage,
@@ -218,14 +220,14 @@
 }
 
 TEST_F(CanvasResourceProviderTest,
-       CanvasResourceProviderDirectGpuMemoryBuffer) {
+       CanvasResourceProviderDirect2DGpuMemoryBuffer) {
   const IntSize kSize(10, 10);
   const CanvasColorParams kColorParams(kSRGBCanvasColorSpace,
                                        kRGBA8CanvasPixelFormat, kNonOpaque);
   EnsureBufferFormatIsSupported(kColorParams.GetBufferFormat());
 
   auto provider = CanvasResourceProvider::Create(
-      kSize, CanvasResourceProvider::kAcceleratedDirectResourceUsage,
+      kSize, CanvasResourceProvider::kAcceleratedDirect2DResourceUsage,
       context_provider_wrapper_, 0 /* msaa_sample_count */, kColorParams,
       CanvasResourceProvider::kAllowImageChromiumPresentationMode,
       nullptr /* resource_dispatcher */, true /* is_origin_top_left */);
@@ -245,4 +247,45 @@
   EXPECT_TRUE(provider->IsSingleBuffered());
 }
 
+TEST_F(CanvasResourceProviderTest,
+       CanvasResourceProviderDirect3DGpuMemoryBuffer) {
+  const IntSize kSize(10, 10);
+  const CanvasColorParams kColorParams(kSRGBCanvasColorSpace,
+                                       kRGBA8CanvasPixelFormat, kNonOpaque);
+  EnsureBufferFormatIsSupported(kColorParams.GetBufferFormat());
+
+  auto provider = CanvasResourceProvider::Create(
+      kSize, CanvasResourceProvider::kAcceleratedDirect3DResourceUsage,
+      context_provider_wrapper_, 0 /* msaa_sample_count */, kColorParams,
+      CanvasResourceProvider::kAllowImageChromiumPresentationMode,
+      nullptr /* resource_dispatcher */, true /* is_origin_top_left */);
+
+  EXPECT_EQ(provider->Size(), kSize);
+  EXPECT_TRUE(provider->IsValid());
+  EXPECT_TRUE(provider->IsAccelerated());
+  EXPECT_TRUE(provider->SupportsDirectCompositing());
+  EXPECT_TRUE(provider->SupportsSingleBuffering());
+  EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
+  EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
+  EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
+            kColorParams.GetOpacityMode());
+
+  EXPECT_FALSE(provider->IsSingleBuffered());
+  provider->TryEnableSingleBuffering();
+  EXPECT_TRUE(provider->IsSingleBuffered());
+
+  gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+  scoped_refptr<ExternalCanvasResource> resource =
+      ExternalCanvasResource::Create(
+          mailbox, kSize, GL_TEXTURE_2D, kColorParams,
+          SharedGpuContext::ContextProviderWrapper(), provider->CreateWeakPtr(),
+          kNone_SkFilterQuality);
+
+  // NewOrRecycledResource() would return nullptr before an ImportResource().
+  EXPECT_TRUE(provider->ImportResource(resource));
+  EXPECT_EQ(provider->NewOrRecycledResource(), resource);
+  // NewOrRecycledResource() will always return the same |resource|.
+  EXPECT_EQ(provider->NewOrRecycledResource(), resource);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 86db6a1..ddb40b5c4 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -429,6 +429,7 @@
       GetEffectTree().Insert(cc::EffectNode(), current_.effect_id));
   mask_effect.stable_id = mask_effect_id.GetInternalValue();
   mask_effect.clip_id = clip_id;
+  mask_effect.has_render_surface = true;
   mask_effect.blend_mode = SkBlendMode::kDstIn;
 
   const auto& clip_space = current_.clip->LocalTransformSpace();
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index f0a7225..812672c1 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -51,6 +51,7 @@
 #include "gpu/config/gpu_feature_info.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
@@ -607,7 +608,8 @@
       AcceleratedStaticBitmapImage::MailboxType::kSharedImageId);
 }
 
-scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateOrRecycleColorBuffer() {
+scoped_refptr<DrawingBuffer::ColorBuffer>
+DrawingBuffer::CreateOrRecycleColorBuffer() {
   DCHECK(state_restorer_);
   if (!recycled_color_buffer_queue_.IsEmpty()) {
     scoped_refptr<ColorBuffer> recycled =
@@ -637,6 +639,14 @@
   }
 }
 
+scoped_refptr<CanvasResource> DrawingBuffer::AsCanvasResource(
+    base::WeakPtr<CanvasResourceProvider> resource_provider) {
+  return ExternalCanvasResource::Create(
+      back_color_buffer_->mailbox, back_color_buffer_->size, texture_target_,
+      CanvasColorParams(), context_provider_->GetWeakPtr(), resource_provider,
+      kLow_SkFilterQuality);
+}
+
 DrawingBuffer::ColorBuffer::ColorBuffer(
     DrawingBuffer* drawing_buffer,
     const IntSize& size,
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
index 616722f..3031b8c 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
@@ -67,6 +67,8 @@
 
 namespace blink {
 class CanvasColorParams;
+class CanvasResource;
+class CanvasResourceProvider;
 class Extensions3DUtil;
 class StaticBitmapImage;
 class WebGraphicsContext3DProvider;
@@ -262,6 +264,9 @@
     bool doing_work_ = false;
   };
 
+  scoped_refptr<CanvasResource> AsCanvasResource(
+      base::WeakPtr<CanvasResourceProvider> resource_provider);
+
  protected:  // For unittests
   DrawingBuffer(std::unique_ptr<WebGraphicsContext3DProvider>,
                 bool using_gpu_compositing,
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc
index becf1ca..2e059b3 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.cc
+++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -201,6 +201,21 @@
   heap_ = std::make_unique<ThreadHeap>(this);
 }
 
+// Implementation for WebRAILModeObserver
+void ThreadState::OnRAILModeChanged(v8::RAILMode new_mode) {
+  should_optimize_for_load_time_ = new_mode == v8::RAILMode::PERFORMANCE_LOAD;
+  // When switching RAIL mode to load we try to avoid incremental marking as
+  // the write barrier cost is noticeable on throughput and garbage
+  // accumulated during loading is likely to be alive during that phase. The
+  // same argument holds for unified heap garbage collections with the
+  // difference that these collections are triggered by V8 and should thus be
+  // avoided on that end.
+  if (should_optimize_for_load_time_ && IsIncrementalMarking() &&
+      !IsUnifiedGCMarkingInProgress() &&
+      GetGCState() == GCState::kIncrementalMarkingStepScheduled)
+    ScheduleIncrementalMarkingFinalize();
+}
+
 ThreadState::~ThreadState() {
   DCHECK(CheckThread());
   if (IsMainThread())
diff --git a/third_party/blink/renderer/platform/heap/thread_state.h b/third_party/blink/renderer/platform/heap/thread_state.h
index e640173d..b60ce9e 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.h
+++ b/third_party/blink/renderer/platform/heap/thread_state.h
@@ -534,19 +534,7 @@
   MarkingVisitor* CurrentVisitor() { return current_gc_data_.visitor.get(); }
 
   // Implementation for WebRAILModeObserver
-  void OnRAILModeChanged(v8::RAILMode new_mode) override {
-    should_optimize_for_load_time_ = new_mode == v8::RAILMode::PERFORMANCE_LOAD;
-    // When switching RAIL mode to load we try to avoid incremental marking as
-    // the write barrier cost is noticeable on throughput and garbage
-    // accumulated during loading is likely to be alive during that phase. The
-    // same argument holds for unified heap garbage collections with the
-    // difference that these collections are triggered by V8 and should thus be
-    // avoided on that end.
-    if (should_optimize_for_load_time_ && IsIncrementalMarking() &&
-        !IsUnifiedGCMarkingInProgress() &&
-        GetGCState() == GCState::kIncrementalMarkingStepScheduled)
-      ScheduleIncrementalMarkingFinalize();
-  }
+  void OnRAILModeChanged(v8::RAILMode new_mode) override;
 
  private:
   // Stores whether some ThreadState is currently in incremental marking.
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
index bc2e11e..50579ba 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
+++ b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
@@ -8,6 +8,10 @@
 #include "base/macros.h"
 #include "third_party/blink/renderer/platform/heap/marking_visitor.h"
 
+namespace v8 {
+class EmbedderHeapTracer;
+}
+
 namespace blink {
 
 struct WrapperTypeInfo;
diff --git a/third_party/blink/renderer/platform/heap/visitor.h b/third_party/blink/renderer/platform/heap/visitor.h
index 2a53f1a..03a8c49 100644
--- a/third_party/blink/renderer/platform/heap/visitor.h
+++ b/third_party/blink/renderer/platform/heap/visitor.h
@@ -39,7 +39,10 @@
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
 #include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#include "v8/include/v8.h"
+
+namespace v8 {
+class Value;
+}
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/instrumentation/tracing/traced_value_test.cc b/third_party/blink/renderer/platform/instrumentation/tracing/traced_value_test.cc
index ba8b9de..88489eff 100644
--- a/third_party/blink/renderer/platform/instrumentation/tracing/traced_value_test.cc
+++ b/third_party/blink/renderer/platform/instrumentation/tracing/traced_value_test.cc
@@ -15,7 +15,7 @@
     std::unique_ptr<TracedValue> value) {
   base::JSONReader reader;
   CString utf8 = value->ToString().Utf8();
-  return reader.Read(utf8.data());
+  return reader.ReadDeprecated(utf8.data());
 }
 
 TEST(TracedValueTest, FlatDictionary) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
index f6a5b74..e4db443 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
@@ -33,10 +33,26 @@
  public:
   virtual ~FetchClientSettingsObject() = default;
 
+  // The URL of the environment settings object's global object.
+  // https://html.spec.whatwg.org/#concept-settings-object-global
+  //
+  // Note: "global object's URL" is not explcitly defined in the spec.
+  // This currently returns what ExecutionContext::Url() returns, i.e.
+  // - Document's URL
+  //   https://dom.spec.whatwg.org/#concept-document-url
+  //   but can return a null URL in cases where "about:blank" should have
+  //   been returned.
+  // - WorkerGlobalScope's URL.
+  //   https://html.spec.whatwg.org/#concept-workerglobalscope-url
+  // - Worklet's parent Document's URL.
+  // TODO(crbug.com/931532): Fix spec issues and make the implementation
+  // spec-conformant.
+  virtual const KURL& GlobalObjectUrl() const = 0;
+
   // "A URL used by APIs called by scripts that use this environment settings
   // object to parse URLs."
   // https://html.spec.whatwg.org/C/#api-base-url
-  virtual const KURL& BaseURL() const = 0;
+  virtual const KURL& BaseUrl() const = 0;
 
   // "An origin used in security checks."
   // https://html.spec.whatwg.org/C/#concept-settings-object-origin
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
index 038116c..b558c4dd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
@@ -11,7 +11,8 @@
 FetchClientSettingsObjectSnapshot::FetchClientSettingsObjectSnapshot(
     const FetchClientSettingsObject& fetch_client_setting_object)
     : FetchClientSettingsObjectSnapshot(
-          fetch_client_setting_object.BaseURL(),
+          fetch_client_setting_object.GlobalObjectUrl(),
+          fetch_client_setting_object.BaseUrl(),
           fetch_client_setting_object.GetSecurityOrigin(),
           fetch_client_setting_object.GetReferrerPolicy(),
           fetch_client_setting_object.GetOutgoingReferrer(),
@@ -22,6 +23,7 @@
 FetchClientSettingsObjectSnapshot::FetchClientSettingsObjectSnapshot(
     std::unique_ptr<CrossThreadFetchClientSettingsObjectData> data)
     : FetchClientSettingsObjectSnapshot(
+          data->global_object_url,
           data->base_url,
           data->security_origin,
           data->referrer_policy,
@@ -31,6 +33,7 @@
           data->address_space) {}
 
 FetchClientSettingsObjectSnapshot::FetchClientSettingsObjectSnapshot(
+    const KURL& global_object_url,
     const KURL& base_url,
     const scoped_refptr<const SecurityOrigin> security_origin,
     network::mojom::ReferrerPolicy referrer_policy,
@@ -38,7 +41,8 @@
     HttpsState https_state,
     AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script,
     base::Optional<mojom::IPAddressSpace> address_space)
-    : base_url_(base_url),
+    : global_object_url_(global_object_url),
+      base_url_(base_url),
       security_origin_(std::move(security_origin)),
       referrer_policy_(referrer_policy),
       outgoing_referrer_(outgoing_referrer),
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
index 3e900b8b..91172103 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
@@ -28,6 +28,7 @@
 
  public:
   CrossThreadFetchClientSettingsObjectData(
+      KURL global_object_url,
       KURL base_url,
       scoped_refptr<const SecurityOrigin> security_origin,
       network::mojom::ReferrerPolicy referrer_policy,
@@ -35,7 +36,8 @@
       HttpsState https_state,
       AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script,
       base::Optional<mojom::IPAddressSpace> address_space)
-      : base_url(std::move(base_url)),
+      : global_object_url(std::move(global_object_url)),
+        base_url(std::move(base_url)),
         security_origin(std::move(security_origin)),
         referrer_policy(referrer_policy),
         outgoing_referrer(std::move(outgoing_referrer)),
@@ -44,6 +46,7 @@
             mime_type_check_for_classic_worker_script),
         address_space(address_space) {}
 
+  const KURL global_object_url;
   const KURL base_url;
   const scoped_refptr<const SecurityOrigin> security_origin;
   const network::mojom::ReferrerPolicy referrer_policy;
@@ -71,6 +74,7 @@
   explicit FetchClientSettingsObjectSnapshot(
       std::unique_ptr<CrossThreadFetchClientSettingsObjectData>);
   FetchClientSettingsObjectSnapshot(
+      const KURL& global_object_url,
       const KURL& base_url,
       const scoped_refptr<const SecurityOrigin> security_origin,
       network::mojom::ReferrerPolicy referrer_policy,
@@ -81,7 +85,8 @@
 
   ~FetchClientSettingsObjectSnapshot() override = default;
 
-  const KURL& BaseURL() const override { return base_url_; }
+  const KURL& GlobalObjectUrl() const override { return global_object_url_; }
+  const KURL& BaseUrl() const override { return base_url_; }
   const SecurityOrigin* GetSecurityOrigin() const override {
     return security_origin_.get();
   }
@@ -105,12 +110,14 @@
   // Gets a copy of the data suitable for passing to another thread.
   std::unique_ptr<CrossThreadFetchClientSettingsObjectData> CopyData() const {
     return std::make_unique<CrossThreadFetchClientSettingsObjectData>(
-        base_url_.Copy(), security_origin_->IsolatedCopy(), referrer_policy_,
+        global_object_url_.Copy(), base_url_.Copy(),
+        security_origin_->IsolatedCopy(), referrer_policy_,
         outgoing_referrer_.IsolatedCopy(), https_state_,
         mime_type_check_for_classic_worker_script_, address_space_);
   }
 
  private:
+  const KURL global_object_url_;
   const KURL base_url_;
   const scoped_refptr<const SecurityOrigin> security_origin_;
   const network::mojom::ReferrerPolicy referrer_policy_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc b/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
index 16039f53..78e1d45 100644
--- a/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
@@ -17,6 +17,7 @@
     : fetch_client_settings_object_(
           *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
               KURL(),
+              KURL(),
               nullptr /* security_origin */,
               network::mojom::ReferrerPolicy::kDefault,
               String(),
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
index fe542bb..1ae0225 100644
--- a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
@@ -271,12 +271,18 @@
 
 void RawResource::ResponseBodyReceived(
     ResponseBodyLoaderDrainableInterface& body_loader) {
+  DCHECK_LE(Clients().size(), 1u);
+  RawResourceClient* client =
+      ResourceClientWalker<RawResourceClient>(Clients()).Next();
   if (IsUnusedPreload()) {
     // For preload, we want to store the body while dispatching
     // onload and onerror events.
     bytes_consumer_for_preload_ = MakeGarbageCollected<BufferingBytesConsumer>(
         &body_loader.DrainAsBytesConsumer());
+    return;
+  }
 
+  if (!client) {
     return;
   }
 
@@ -285,6 +291,14 @@
     // The loading was initiated as a preload (hence UseStreamOnResponse is
     // set), but this resource has been matched with a request without
     // UseStreamOnResponse set.
+    auto* bytes_consumer_for_preload =
+        MakeGarbageCollected<BufferingBytesConsumer>(
+            &body_loader.DrainAsBytesConsumer());
+    auto* bytes_consumer_client =
+        MakeGarbageCollected<PreloadBytesConsumerClient>(
+            *bytes_consumer_for_preload, *this, *client);
+    bytes_consumer_for_preload->SetClient(bytes_consumer_client);
+    bytes_consumer_client->OnStateChange();
     return;
   }
 
@@ -292,12 +306,7 @@
     return;
   }
 
-  BytesConsumer& bytes_consumer = body_loader.DrainAsBytesConsumer();
-  DCHECK_LE(Clients().size(), 1u);
-  ResourceClientWalker<RawResourceClient> w(Clients());
-  while (RawResourceClient* c = w.Next()) {
-    c->ResponseBodyReceived(this, bytes_consumer);
-  }
+  client->ResponseBodyReceived(this, body_loader.DrainAsBytesConsumer());
 }
 
 CachedMetadataHandler* RawResource::CreateCachedMetadataHandler(
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 908fdb6..6bf5587 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -929,6 +929,7 @@
   const auto& original_client_settings_object =
       *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
           KURL("https://example.com/foo.html"),
+          KURL("https://example.com/foo.html"),
           SecurityOrigin::Create(KURL("https://example.com/")),
           network::mojom::ReferrerPolicy::kDefault,
           "https://example.com/foo.html", HttpsState::kModern,
@@ -961,7 +962,7 @@
 
   EXPECT_NE(&client_settings_object,
             &properties.GetFetchClientSettingsObject());
-  EXPECT_EQ(properties.GetFetchClientSettingsObject().BaseURL(),
+  EXPECT_EQ(properties.GetFetchClientSettingsObject().BaseUrl(),
             KURL("https://example.com/foo.html"));
   EXPECT_FALSE(properties.IsMainFrame());
   EXPECT_EQ(properties.GetControllerServiceWorkerMode(),
@@ -978,6 +979,7 @@
   const auto& original_client_settings_object =
       *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
           KURL("https://example.com/foo.html"),
+          KURL("https://example.com/foo.html"),
           SecurityOrigin::Create(KURL("https://example.com/")),
           network::mojom::ReferrerPolicy::kDefault,
           "https://example.com/foo.html", HttpsState::kModern,
@@ -1020,7 +1022,7 @@
 
   EXPECT_NE(&client_settings_object,
             &properties.GetFetchClientSettingsObject());
-  EXPECT_EQ(properties.GetFetchClientSettingsObject().BaseURL(),
+  EXPECT_EQ(properties.GetFetchClientSettingsObject().BaseUrl(),
             KURL("https://example.com/foo.html"));
   EXPECT_TRUE(properties.IsMainFrame());
   EXPECT_EQ(properties.GetControllerServiceWorkerMode(),
diff --git a/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc b/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
index 17960d7..7903570 100644
--- a/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
+++ b/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
@@ -21,6 +21,7 @@
     : TestResourceFetcherProperties(
           *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
               KURL(),
+              KURL(),
               std::move(origin),
               network::mojom::ReferrerPolicy::kDefault,
               String(),
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 0798bb1..fa5ca25 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -619,6 +619,10 @@
       origin_trial_feature_name: "WebComponentsV0",
       status: "stable",
     },
+    // Allow import only chrome internal resources.
+    {
+      name: "HTMLImportsOnlyChrome",
+    },
     // https://crbug.com/523952 for testing disabling the feature.
     {
       name: "HTMLImportsStyleApplication",
@@ -1070,10 +1074,6 @@
       status: {"Android": "", "default": "stable"},
     },
     {
-      name: "PictureInPictureControl",
-      status: "experimental",
-    },
-    {
       name: "PointerRawMove",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 1aa060f..08b77ed4 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
+#include "v8/include/v8.h"
 
 namespace blink {
 namespace scheduler {
@@ -1999,6 +2000,14 @@
   state->SetBoolean("use_virtual_time", use_virtual_time);
 }
 
+MainThreadSchedulerImpl::Policy::Policy()
+    : rail_mode_(v8::PERFORMANCE_ANIMATION),
+      should_disable_throttling_(false),
+      frozen_when_backgrounded_(false),
+      compositor_priority_(
+          base::sequence_manager::TaskQueue::QueuePriority::kNormalPriority),
+      use_case_(UseCase::kNone) {}
+
 void MainThreadSchedulerImpl::Policy::AsValueInto(
     base::trace_event::TracedValue* state) const {
   state->BeginDictionary("compositor_queue_policy");
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 758d738..c05ef3e 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -457,14 +457,7 @@
 
   class Policy {
    public:
-    Policy()
-        : rail_mode_(v8::PERFORMANCE_ANIMATION),
-          should_disable_throttling_(false),
-          frozen_when_backgrounded_(false),
-          compositor_priority_(base::sequence_manager::TaskQueue::
-                                   QueuePriority::kNormalPriority),
-          use_case_(UseCase::kNone) {}
-
+    Policy();
     ~Policy() = default;
 
     TaskQueuePolicy& compositor_queue_policy() {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 156ce240..28cf444a 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "v8/include/v8.h"
 
 using base::sequence_manager::TaskQueue;
 
diff --git a/third_party/blink/renderer/platform/testing/data/third_party/Noto/LICENSE_OFL.txt b/third_party/blink/renderer/platform/testing/data/third_party/Noto/LICENSE_OFL.txt
new file mode 100644
index 0000000..d952d62
--- /dev/null
+++ b/third_party/blink/renderer/platform/testing/data/third_party/Noto/LICENSE_OFL.txt
@@ -0,0 +1,92 @@
+This Font Software is licensed under the SIL Open Font License,
+Version 1.1.
+
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/third_party/blink/renderer/platform/testing/data/third_party/Noto/NotoNaskhArabic-regular.woff2 b/third_party/blink/renderer/platform/testing/data/third_party/Noto/NotoNaskhArabic-regular.woff2
new file mode 100644
index 0000000..e24020d
--- /dev/null
+++ b/third_party/blink/renderer/platform/testing/data/third_party/Noto/NotoNaskhArabic-regular.woff2
Binary files differ
diff --git a/third_party/blink/renderer/platform/testing/data/third_party/Noto/README b/third_party/blink/renderer/platform/testing/data/third_party/Noto/README
new file mode 100644
index 0000000..d228764
--- /dev/null
+++ b/third_party/blink/renderer/platform/testing/data/third_party/Noto/README
@@ -0,0 +1,11 @@
+This package is part of the noto project.  Visit
+google.com/get/noto for more information.
+
+Built on 2017-10-24 from the following noto repository:
+-----
+Repo: noto-fonts
+Tag: v2017-10-24-phase3-second-cleanup
+Date: 2017-10-24 12:10:34 GMT
+Commit: 8ef14e6c606a7a0ef3943b9ca01fd49445620d79
+
+Remove some files that aren't for release.
diff --git a/third_party/blink/renderer/platform/testing/data/third_party/Noto/README.chromium b/third_party/blink/renderer/platform/testing/data/third_party/Noto/README.chromium
new file mode 100644
index 0000000..6b9e805
--- /dev/null
+++ b/third_party/blink/renderer/platform/testing/data/third_party/Noto/README.chromium
@@ -0,0 +1,11 @@
+Name: Google Noto Font
+Short Name: Noto
+URL: https://www.google.com/get/noto/
+Date: 2019-02-12
+License: SIL Open Font License, Version 1.1.
+License File: LICENSE_OFL.txt
+Security Critical: no
+
+Description:
+Arabic font for testing. Based on fonts/noto/NotoNaskhArabic-regular.woff2
+in the WPT repository.
\ No newline at end of file
diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.h b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
index be44daba..ec54f68 100644
--- a/third_party/blink/renderer/platform/testing/empty_web_media_player.h
+++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
@@ -29,8 +29,6 @@
   void SetRate(double) override {}
   void SetVolume(double) override {}
   void OnRequestPictureInPicture() override {}
-  void SetPictureInPictureCustomControls(
-      const std::vector<PictureInPictureControlInfo>&) override {}
   SurfaceLayerMode GetVideoSurfaceLayerMode() const override {
     return SurfaceLayerMode::kNever;
   }
diff --git a/third_party/blink/renderer/platform/weborigin/kurl.cc b/third_party/blink/renderer/platform/weborigin/kurl.cc
index 40dfe35..d4b4a21 100644
--- a/third_party/blink/renderer/platform/weborigin/kurl.cc
+++ b/third_party/blink/renderer/platform/weborigin/kurl.cc
@@ -898,4 +898,8 @@
   return a != b.GetString();
 }
 
+std::ostream& operator<<(std::ostream& os, const KURL& url) {
+  return os << url.GetString();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/weborigin/kurl.h b/third_party/blink/renderer/platform/weborigin/kurl.h
index eb4fa3d7..41b5e9c 100644
--- a/third_party/blink/renderer/platform/weborigin/kurl.h
+++ b/third_party/blink/renderer/platform/weborigin/kurl.h
@@ -27,6 +27,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_KURL_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_KURL_H_
 
+#include <iosfwd>
 #include <memory>
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -276,6 +277,10 @@
 PLATFORM_EXPORT bool operator!=(const KURL&, const String&);
 PLATFORM_EXPORT bool operator!=(const String&, const KURL&);
 
+// Pretty printer for gtest and base/logging.*.  It prepends and appends
+// double-quotes, and escapes characters other than ASCII printables.
+PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const KURL&);
+
 PLATFORM_EXPORT bool EqualIgnoringFragmentIdentifier(const KURL&, const KURL&);
 
 PLATFORM_EXPORT const KURL& BlankURL();
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index 6f816506..43c64339 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -223,3 +223,19 @@
 crbug.com/931660 [ Linux ] external/wpt/payment-handler/idlharness.https.any.sharedworker.html [ Pass Timeout ]
 crbug.com/931660 [ Linux ] external/wpt/trusted-types/idlharness.window.html [ Pass Timeout ]
 crbug.com/931660 [ Linux ] fast/history/replacestate-nocrash.html [ Pass Timeout ]
+
+# Sheriff 2019-02-18
+crbug.com/856601 [ Linux ] external/wpt/fetch/api/idl.any.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/secure-contexts/idlharness.any.sharedworker.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/wake-lock/idlharness.https.window.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/BackgroundSync/interfaces.https.any.worker.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/animation-worklet/idlharness.any.worker.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/fullscreen/idlharness.window.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/payment-handler/idlharness.https.any.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/payment-handler/idlharness.https.any.serviceworker.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] external/wpt/payment-request/idlharness.https.window.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/interfaces-window.https.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/omt-worker-fetch/external/wpt/resource-timing/idlharness.any.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/idlharness.window.html [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/unified-autoplay/external/wpt/feature-policy/idlharness.window.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index c4d61503..f2cfc2d3 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -671,6 +671,11 @@
   },
   {
     "prefix": "omt-worker-fetch",
+    "base": "external/wpt/resource-timing",
+    "args": ["--enable-features=OffMainThreadDedicatedWorkerScriptFetch,OffMainThreadSharedWorkerScriptFetch,NetworkService"]
+  },
+  {
+    "prefix": "omt-worker-fetch",
     "base": "external/wpt/upgrade-insecure-requests",
     "args": ["--enable-features=OffMainThreadDedicatedWorkerScriptFetch,OffMainThreadSharedWorkerScriptFetch,NetworkService"]
   },
diff --git a/third_party/blink/web_tests/compositing/overflow/tiled-mask-expected.png b/third_party/blink/web_tests/compositing/overflow/tiled-mask-expected.png
index 2fb86778..0eac266 100644
--- a/third_party/blink/web_tests/compositing/overflow/tiled-mask-expected.png
+++ b/third_party/blink/web_tests/compositing/overflow/tiled-mask-expected.png
Binary files differ
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 b3281a0..d1f9868 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
@@ -178546,11 +178546,6 @@
      {}
     ]
    ],
-   "payment-request/historical.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "payment-request/idlharness.https.window-expected.txt": [
     [
      {}
@@ -213706,12 +213701,6 @@
      {}
     ]
    ],
-   "css/css-position/position-absolute-container-dynamic.html": [
-    [
-     "/css/css-position/position-absolute-container-dynamic.html",
-     {}
-    ]
-   ],
    "css/css-position/position-absolute-crash-chrome-001.html": [
     [
      "/css/css-position/position-absolute-crash-chrome-001.html",
@@ -213730,12 +213719,6 @@
      {}
     ]
    ],
-   "css/css-position/position-absolute-percentage-height.html": [
-    [
-     "/css/css-position/position-absolute-percentage-height.html",
-     {}
-    ]
-   ],
    "css/css-position/position-absolute-replaced-minmax.html": [
     [
      "/css/css-position/position-absolute-replaced-minmax.html",
@@ -215200,6 +215183,12 @@
      {}
     ]
    ],
+   "css/css-syntax/cdc-vs-ident-tokens.html": [
+    [
+     "/css/css-syntax/cdc-vs-ident-tokens.html",
+     {}
+    ]
+   ],
    "css/css-syntax/charset-is-not-a-rule.html": [
     [
      "/css/css-syntax/charset-is-not-a-rule.html",
@@ -355861,10 +355850,6 @@
    "2b158a86f6599e43f6a2315a2943b4d394405ba5",
    "testharness"
   ],
-  "css/css-position/position-absolute-container-dynamic.html": [
-   "711d31766da2e324d3d5ddf0362bc1c71b76d7f3",
-   "testharness"
-  ],
   "css/css-position/position-absolute-crash-chrome-001.html": [
    "592e5d22e70f1b0c5e3e4b9222cbd1ccef99bdef",
    "testharness"
@@ -355877,10 +355862,6 @@
    "5d36710b6fe694b256d9841b3e7a0fff4535c85b",
    "testharness"
   ],
-  "css/css-position/position-absolute-percentage-height.html": [
-   "9fffab8092ef28b184efbfaa32633bda09eb1029",
-   "testharness"
-  ],
   "css/css-position/position-absolute-replaced-minmax-expected.txt": [
    "04879688d39bde3776226c5254f7df8a8a10c638",
    "support"
@@ -358989,6 +358970,10 @@
    "787700cebf39e5cc4fa0d5a2934a7e52bec6da32",
    "testharness"
   ],
+  "css/css-syntax/cdc-vs-ident-tokens.html": [
+   "02cfbe11ae906f50ec3498f554395b7ad495bd70",
+   "testharness"
+  ],
   "css/css-syntax/charset-is-not-a-rule.html": [
    "81b2a04dc5a0dd2f3434150f7bfb6a6d3f1cfef3",
    "testharness"
@@ -422730,7 +422715,7 @@
    "testharness"
   ],
   "kv-storage/cause-errors-via-idb.https.html": [
-   "21fe36b36cb1dbedca5383abb526b9b4f6c8ce3e",
+   "d77e56621e037b71fa6ae9bfb3e80a0ab85677fc",
    "testharness"
   ],
   "kv-storage/entries.https.html": [
@@ -422746,7 +422731,7 @@
    "support"
   ],
   "kv-storage/helpers/kvs-tests.js": [
-   "a6c4d58dfa5e928768d483df11c7d06180bac9fb",
+   "0cf4c2fd3d5fcaa392e8cbbcf64101155bcbe441",
    "support"
   ],
   "kv-storage/key-types.https.html": [
@@ -435001,10 +434986,6 @@
    "56866b43a481e738c844537cb9c355e9638a29fa",
    "testharness"
   ],
-  "payment-request/historical.https-expected.txt": [
-   "34cd1710caca9a6d09c9f1a14889980db40e34ab",
-   "support"
-  ],
   "payment-request/historical.https.html": [
    "e681f6486b9bdd46d7420cac15855dc9acaa2ca7",
    "testharness"
@@ -458610,7 +458591,7 @@
    "testharness"
   ],
   "webrtc/RTCRtpReceiver-getParameters-expected.txt": [
-   "4f8f48aa02bc6d15d95f5b94195dce4dd732574d",
+   "69215e4e591d485e0ed16fbbf28b7dfff430b431",
    "support"
   ],
   "webrtc/RTCRtpReceiver-getParameters.html": [
@@ -463394,7 +463375,7 @@
    "support"
   ],
   "webxr/idlharness.https.window-expected.txt": [
-   "cb0fa2ae3e42af5854e11ff2fa7b159d69ee29ce",
+   "0ddbaadb2162c74c6c2cd77a0de6fa57cf308add",
    "support"
   ],
   "webxr/idlharness.https.window.js": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/cdc-vs-ident-tokens.html b/third_party/blink/web_tests/external/wpt/css/css-syntax/cdc-vs-ident-tokens.html
new file mode 100644
index 0000000..02cfbe1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/cdc-vs-ident-tokens.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>CDC versus Ident Token</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+
+-->
+
+--foo { color: blue; }
+
+</style>
+
+<meta name=author content="Tab Atkins-Bittner">
+<link rel=help href="https://drafts.csswg.org/css-syntax/#consume-token">
+
+<!--
+The ordering of the checks in the HYPHEN-MINUS step is important;
+if you get it wrong, ident-token can swallow cdc-token.
+-->
+
+<script>
+
+test(()=>{
+    const rule = document.styleSheets[0].cssRules[0];
+    assert_equals(rule.selectorText, "--foo");
+}, "CDC-token is properly emitted, and not parsed as an ident.");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/preload/preload-xhr.html b/third_party/blink/web_tests/external/wpt/preload/preload-xhr.html
new file mode 100644
index 0000000..53515bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/preload/preload-xhr.html
@@ -0,0 +1,57 @@
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<script>
+
+const dummyContent = '<?xml version="1.0" encoding="utf-8"?>\n<root>Text.me</root>\n';
+promise_test(async (t) => {
+  const url = `resources/dummy.xml?token=${token()}`;
+  const link = document.createElement('link');
+  link.rel = 'preload';
+  link.as = 'fetch';
+  link.href = url;
+  link.crossOrigin = 'anonymous';
+
+  document.head.appendChild(link);
+
+  const xhr = new XMLHttpRequest();
+  await new Promise((resolve, reject) => {
+    xhr.onloadend = resolve;
+    xhr.onloaderror = reject;
+    xhr.open('GET', url);
+    xhr.send();
+  });
+  verifyNumberOfResourceTimingEntries(url, 1);
+  assert_equals(xhr.status, 200);
+  assert_equals(xhr.responseText, dummyContent);
+
+}, 'Make an XHR request immediately after creating link rel=preload.');
+
+promise_test(async (t) => {
+  const url = `resources/dummy.xml?token=${token()}`;
+  const link = document.createElement('link');
+  link.rel = 'preload';
+  link.as = 'fetch';
+  link.href = url;
+  link.crossOrigin = 'anonymous';
+
+  await new Promise((resolve, reject) => {
+    link.addEventListener('load', resolve, {once: true});
+    link.addEventListener('error', reject, {once: true});
+    document.head.appendChild(link);
+  });
+
+  const xhr = new XMLHttpRequest();
+  await new Promise((resolve, reject) => {
+    xhr.onloadend = resolve;
+    xhr.onloaderror = reject;
+    xhr.open('GET', url);
+    xhr.send();
+  });
+  verifyNumberOfResourceTimingEntries(url, 1);
+  assert_equals(xhr.status, 200);
+  assert_equals(xhr.responseText, dummyContent);
+}, 'Make an XHR request after loading link rel=preload.');
+
+</script>
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-navigate-to-click-handler.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-navigate-to-click-handler.html
new file mode 100644
index 0000000..f24c4b2
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-navigate-to-click-handler.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!--
+  This test checks that elements that are otherwise unfocusable are spat-nav
+  navigable if they have a click handler.
+-->
+
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    margin: 5px;
+    border: 1px solid black;
+  }
+</style>
+
+<div id="first">First</div>
+<div id="second">Second</div>
+
+<!--
+  Wrap the target in a div and give it a child to ensure the event
+  handler doesn't in any way transfer to the parent or child.
+-->
+<div id="wrapper">
+  <div id="third">
+    <div id="inner">Third</div>
+  </div>
+</div>
+
+<script>
+  let first = document.getElementById("first");
+  let second = document.getElementById("second");
+  let third = document.getElementById("third");
+
+  snav.assertSnavEnabledAndTestable(true /* focuslessSpatNav */ );
+
+  third.addEventListener('click', () => {});
+
+  test(() => {
+    assert_true(!!window.internals);
+
+    // Move interest. Since the first two boxes don't have tabindex, they're
+    // unfocusable and spat-nav will skip them.
+    snav.triggerMove('Down');
+    assert_equals(window.internals.interestedElement,
+                  third,
+                  "'third' should be interested");
+  }, "Click handlers cause elements to become intersting to spat-nav.");
+</script>
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js b/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js
index 27424cc..2ce7cae5 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js
@@ -1,48 +1,43 @@
 onmessage = function(event) {
-    if (event.data == "noport") {
-        if (event.ports && !event.ports.length)
-            testPassed("event.ports is non-null and zero length when no port sent");
-        else
-            testFailed("event.ports is null or non-zero length when no port sent");
-    } else if (event.data == "zero ports") {
-        if (event.ports && !event.ports.length)
-            testPassed("event.ports is non-null and zero length when empty array sent");
-        else
-            testFailed("event.ports is null or non-zero length when empty array sent");
-    } else if (event.data == "two ports") {
-        if (!event.ports) {
-            testFailed("event.ports should be non-null when ports sent");
-            return;
-        }
-        if (event.ports.length == 2)
-            testPassed("event.ports contains two ports when two ports sent");
-        else
-            testFailed("event.ports contained " + event.ports.length + " when two ports sent");
-    } else if (event.data == "failed ports") {
-        if (event.ports.length == 2)
-            testPassed("event.ports contains two ports when two ports re-sent after error");
-        else
-            testFailed("event.ports contained " + event.ports.length + " when two ports re-sent after error");
-    } else if (event.data == "done") {
-        postMessage("done");
-        event.ports[0].postMessage("done");
-    } else if (event.data == "noargs") {
-        try {
-            postMessage();
-            testFailed("postMessage() did not throw");
-        } catch (e) {
-            testPassed("postMessage() threw exception: " + e);
-        }
-    } else
-        testFailed("Received unexpected message: " + event.data);
+  if (event.data == "noport") {
+    if (event.ports && !event.ports.length)
+      testPassed("event.ports is non-null and zero length when no port sent");
+    else
+      testFailed("event.ports is null or non-zero length when no port sent");
+  } else if (event.data == "zero ports") {
+    if (event.ports && !event.ports.length)
+      testPassed("event.ports is non-null and zero length when empty array sent");
+    else
+      testFailed("event.ports is null or non-zero length when empty array sent");
+  } else if (event.data == "two ports") {
+    if (!event.ports) {
+      testFailed("event.ports should be non-null when ports sent");
+      return;
+    }
+    if (event.ports.length == 2)
+      testPassed("event.ports contains two ports when two ports sent");
+    else
+      testFailed("event.ports contained " + event.ports.length + " when two ports sent");
+  } else if (event.data == "failed ports") {
+    if (event.ports.length == 2)
+      testPassed("event.ports contains two ports when two ports re-sent after error");
+    else
+      testFailed("event.ports contained " + event.ports.length + " when two ports re-sent after error");
+  } else if (event.data == "noargs") {
+    try {
+      postMessage();
+      testFailed("postMessage() did not throw");
+    } catch (e) {
+      testPassed("postMessage() threw exception: " + e);
+    }
+  } else
+    testFailed("Received unexpected message: " + event.data);
 };
 
-function testPassed(msg)
-{
-    postMessage("PASS"+msg);
+function testPassed(msg) {
+  postMessage("PASS"+msg);
 }
 
-function testFailed(msg)
-{
-    postMessage("FAIL"+msg);
+function testFailed(msg) {
+  postMessage("FAIL"+msg);
 }
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js
index e530f7ff..afc66cf 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js
@@ -1,8 +1,7 @@
-self.postMessage("Test started.");
-// The test will create 3 timeouts with their intervals decreasing.
-// If the timeouts execute in order then the test is PASS.
+// The test will create 2 timeouts and cancel the first one. If only the second
+// timeout executes then the test passes.
 self.addEventListener('message', function(e) {
     var t1 = setTimeout(function () { postMessage(1); }, 5);
-    setTimeout(function () { postMessage(2); postMessage("DONE"); }, 10);
+    setTimeout(function () { postMessage(2); }, 10);
     clearTimeout(t1);
-}, false);
\ No newline at end of file
+}, false);
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js
index e16507a..b93dd5dc 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js
@@ -1,8 +1,7 @@
-self.postMessage("Test started.");
 // The test will create 3 timeouts with their intervals decreasing.
 // If the timeouts execute in order then the test is PASS.
 self.addEventListener('message', function(e) {
-    setTimeout(function () { postMessage(3); postMessage("DONE"); }, 15);
+    setTimeout(function () { postMessage(3); }, 15);
     setTimeout(function () { postMessage(2); }, 10);
     setTimeout(function () { postMessage(1); }, 5);
-}, false);
\ No newline at end of file
+}, false);
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js
index 522b051..42f81daa 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js
@@ -1,8 +1,7 @@
-self.postMessage("Test started.");
 // The test will create 3 timeouts with their intervals increasing.
 // If the timeouts execute in order then the test is PASS.
 self.addEventListener('message', function(e) {
     setTimeout(function () { postMessage(1); }, 5);
     setTimeout(function () { postMessage(2); }, 10);
-    setTimeout(function () { postMessage(3); postMessage("DONE"); }, 15);
-}, false);
\ No newline at end of file
+    setTimeout(function () { postMessage(3); }, 15);
+}, false);
diff --git a/third_party/blink/web_tests/fast/workers/worker-close-expected.txt b/third_party/blink/web_tests/fast/workers/worker-close-expected.txt
deleted file mode 100644
index e129059..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-close-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test WorkerContext.close functionality. Should print a series of PASS messages, followed with DONE.
-
-PASS: typeof close: function
-PASS: received message before close
-PASS: Received message posted right after close() was invoked: Should be delivered
-PASS: no messages arrive to worker after JS fragment with close() exits
-PASS: Error arrived after close: Uncaught ReferenceError: nonExistentFunction is not defined
-PASS: close() did not dispatch pending events
-PASS: Received message after worker closed: Should be delivered
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-close.html b/third_party/blink/web_tests/fast/workers/worker-close.html
index 55dc7cb..f54af13 100644
--- a/third_party/blink/web_tests/fast/workers/worker-close.html
+++ b/third_party/blink/web_tests/fast/workers/worker-close.html
@@ -1,108 +1,66 @@
-<body>
-<p>Test WorkerContext.close functionality. Should print a series of PASS messages, followed with DONE.</p>
-<div id=result></div>
+<!DOCTYPE html>
+<title>Test WorkerGlobalScope.close functionality.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
+setup({ allow_uncaught_exception: true });
 
-if (window.testRunner)
-{
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("typeofClose");
+    worker.onmessage = t.step_func_done(function(evt) {
+    assert_equals(evt.data, "typeof close: function");
+    });
+}, 'Test type of close function.');
 
-var worker = new Worker('resources/worker-close.js');
-var timeout = 0;
-
-worker.postMessage("typeofClose");
-worker.onmessage = testTypeofClose;
-
-function testTypeofClose(evt)
-{
-    if (evt.data == "typeof close: function")
-        log("PASS: " + evt.data);
-    else
-        log("FAIL: " + evt.data);
-    worker.onmessage = testMessageAfterClose;
-    worker.postMessage("ping");
-}
-
-function testMessageAfterClose(evt) {
-    if (evt.data == "pong")
-        log("PASS: received message before close");
-    else
-        log("FAIL: received unknown response: " + evt.data);
-
-    // Tell the worker to close, then send a followup message. This message should not be delivered,
-    // since that would require JS to invoke the onmessage handler, which does not happen after the JS
-    // fragment with 'close()' in it exits. So, the 'ping' should not come back as 'pong'.
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');  
+  worker.postMessage("ping");
+    worker.onmessage = t.step_func(function(evt) {
+    assert_equals(evt.data, "pong");
+    // Tell the worker to close, then send a followup message. This message
+    // should not be delivered, since that would require JS to invoke the
+    //  onmessage handler, which does not happen after the JS fragment with
+    // 'close()' in it exits. So, the 'ping' should not come back as 'pong'.
     worker.postMessage("close");
     worker.postMessage("ping");
-    worker.onmessage = function(evt) {
-        if (evt.data != "pong") {
-            log("PASS: Received message posted right after close() was invoked: " + evt.data);
-            timeout = setTimeout(testErrorAfterClose, 1000);
-        } else {
-            log("FAIL: Received a message originated from a handler in the worker after the JS fragment with close() exited" + evt.data);
-            done();
-        }
-    };
-}
+      worker.onmessage = t.step_func(function(evt) {
+      assert_not_equals(evt.data, "pong");
+      t.step_timeout(function() { t.done(); }, 500);
+    });
+  });
+}, 'Test sending a message after closing.');
 
-function testErrorAfterClose()
-{
-    log("PASS: no messages arrive to worker after JS fragment with close() exits");
-    // Test that errors are delivered after close.
-    worker = new Worker('resources/worker-close.js');
-    worker.postMessage("closeWithError");
-    worker.onerror = function(event) {
-        log("PASS: Error arrived after close: " + event.message);
-        testPendingEvents();
-        return false;
-    }
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("closeWithError");
+  worker.onerror = function(event) {
+    t.done()
+  };
+}, 'Test errors are delivered after close.');
 
-function testPendingEvents()
-{
-    // Now test that workers do not deliver pending events
-    worker = new Worker('resources/worker-close.js');
-    worker.postMessage("closeWithPendingEvents");
-    worker.onmessage = function(evt) {
-        log("FAIL: pending events should not fire:" + evt.data);
-        done();
-    }
-    worker.onerror = function(evt) {
-        log("FAIL: pending events should not fire:" + evt.message);
-        done();
-    }
-    timeout = setTimeout(testTerminateAfterClose, 500);
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("closeWithPendingEvents");
+  worker.onmessage = t.step_func(function(evt) {
+    assert_unreached("Pending events should not fire: " + evt.data);
+  });
+  worker.onerror = t.step_func(function(evt) {
+    assert_unreached("Pending events should not fire:" + evt.message);
+  });
+  t.step_timeout(function() { t.done(); }, 500);
+}, 'Test workers do not deliver pending events.');
 
-function testTerminateAfterClose()
-{
-    log("PASS: close() did not dispatch pending events");
-    worker = new Worker('resources/worker-close.js');
-    worker.postMessage("close");
-    worker.onmessage = function(evt) {
-        log("PASS: Received message after worker closed: " + evt.data);
-        // Give worker a chance to close first, then terminate it.
-        timeout = setTimeout(function() {
-            worker.terminate();
-            done();
-        }, 500);
-    };
-}
-
-function done() {
-    if (timeout)
-        clearTimeout(timeout);
-    log("DONE");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("close");
+  worker.onmessage = function(evt) {
+    assert_equals(evt.data, "Should be delivered");
+    // Give worker a chance to close first, then terminate it.
+    t.step_timeout(function() {
+      worker.terminate();
+      t.done();
+    }, 500);
+  };
+}, 'Test terminating a worker after close.');
 </script>
-</body>
-</html>
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-constructor-expected.txt b/third_party/blink/web_tests/fast/workers/worker-constructor-expected.txt
deleted file mode 100644
index 708955f..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-constructor-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test Worker constructor functionality. Should print a series of PASS messages, followed with DONE.
-
-PASS: toString exception propagated correctly.
-PASS: trying to create workers recursively resulted in an exception (RangeError: Maximum call stack size exceeded)
-PASS: invoking Worker constructor without arguments resulted in an exception (TypeError: Failed to construct 'Worker': 1 argument required, but only 0 present.)
-PASS: onerror invoked for an empty script URL, resolving to this HTML document's URL.
-PASS: invoking Worker constructor with invalid script URL resulted in an exception (SyntaxError: Failed to construct 'Worker': 'http://invalid:123$' is not a valid URL.)
-PASS: onerror invoked for a script that could not be loaded.
-PASS: Successfully created worker.
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-constructor.html b/third_party/blink/web_tests/fast/workers/worker-constructor.html
index 38f5423..e6af447 100644
--- a/third_party/blink/web_tests/fast/workers/worker-constructor.html
+++ b/third_party/blink/web_tests/fast/workers/worker-constructor.html
@@ -1,138 +1,60 @@
-<body>
-<p>Test Worker constructor functionality. Should print a series of PASS messages, followed with DONE.</p>
-<div id=result></div>
+<!DOCTYPE html>
+<title>Test Worker constructor functionality.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
 
-var testCases = [
-    "testArgumentException",
-    "testRecursiveWorkerCreation",
-    "testNoArgument",
-    "testEmptyScriptUrl",
-    "testInvalidScriptUrl",
-    "testNotExistentScriptUrl",
-    "testSuccessWorkerCreation",
-];
-var testIndex = 0;
+test(() => {
+  assert_throws(new Error(),
+                function() {
+                    new Worker({toString:function(){throw new Error()}})},
+                'toString exception should be propagated');
+}, 'Test toString propagation exception.');
 
-function runNextTest()
-{
-    if (testIndex < testCases.length) {
-        testIndex++;
-        window[testCases[testIndex - 1]]();
-    } else {
-        log("DONE");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-}
+test(() => {
+  try {
+    var foo = {toString:function(){new Worker(foo)}};
+    new Worker(foo);
+  } catch(ex) {
+    assert_true(true, 'trying to create workers recursively should result in an: ' +
+                ex + 'exception.')
+  }
+}, 'Test recursive Worker creation.');
 
-function testArgumentException()
-{
-    try {
-        new Worker({toString:function(){throw "exception"}})
-        log("FAIL: toString exception not propagated.");
-    } catch (ex) {
-        if (ex == "exception")
-            log("PASS: toString exception propagated correctly.");
-        else
-            log("FAIL: unexpected exception (" + ex + ") received instead of one propagated from toString.");
-    }
-    runNextTest();
-}
+test(() => {
+  assert_throws(new TypeError(),
+                function() { new Worker(); },
+                'invoking Worker constructor without arguments should result' +
+                'in an exception.')
+}, 'Test worker creation with no arguments');
 
-function testRecursiveWorkerCreation()
-{
-    try {
-        var foo = {toString:function(){new Worker(foo)}}
-        new Worker(foo);
-        log("FAIL: no exception when trying to create workers recursively");
-    } catch (ex) {
-        log("PASS: trying to create workers recursively resulted in an exception (" + ex + ")");
-    }
-    runNextTest();
-}
+async_test(t => {
+  var worker = new Worker('');
+  worker.onerror = function(e) {
+    e.preventDefault();
+    t.done();
+  }
+}, 'Test Worker creation with empty script URL.');
 
-function testNoArgument()
-{
-    try {
-        new Worker();
-        log("FAIL: invoking Worker constructor without arguments did not result in an exception");
-    } catch (ex) {
-        log("PASS: invoking Worker constructor without arguments resulted in an exception (" + ex + ")");
-    }
-    runNextTest();
-}
+test(() => {
+  assert_throws(new SyntaxError(),
+                function() { var worker = new Worker('http://invalid:123$'); },
+                'Invoking Worker constructor with invalid script URL should' +
+                'result in an exception.');
+}, 'Test invalid script URL.');
 
-function testEmptyScriptUrl()
-{
-    try {
-        var worker = new Worker("");
-        worker.onerror = function(e) {
-            log("PASS: onerror invoked for an empty script URL, resolving to this HTML document's URL.");
-            e.preventDefault();
-            runNextTest();
-        }
-    } catch (ex) {
-        log("FAIL: invoking Worker constructor with empty script URL resulted in a exception (" + ex + ")");
-        runNextTest();
-    }
-}
+async_test(t => {
+  var worker = new Worker('does-not-exist.js');
+  worker.onerror = function(e) {
+    t.done();
+  }
+}, 'Test not existent script URL.');
 
-function testInvalidScriptUrl()
-{
-    try {
-        var worker = new Worker("http://invalid:123$");
-        worker.onerror = function() {
-            log("FAIL: onerror invoked for an invalid script URL.");
-            runNextTest();
-        }
-    } catch (ex) {
-        log("PASS: invoking Worker constructor with invalid script URL resulted in an exception (" + ex + ")");
-        runNextTest();
-    }
-}
-
-function testNotExistentScriptUrl()
-{
-    try {
-        var worker = new Worker("does-not-exist.js");
-        worker.onerror = function() {
-            log("PASS: onerror invoked for a script that could not be loaded.");
-            runNextTest();
-        }
-    } catch (ex) {
-        log("FAIL: unexpected exception " + ex);
-        runNextTest();
-    }
-}
-
-function testSuccessWorkerCreation()
-{
-    try {
-        var worker = new Worker("resources/worker-common.js");
-        // Make sure attributes from both Worker and AbstractWorker are visible.
-        if (!worker.postMessage)
-            log("FAIL: worker.postMessage did not exist.");
-        else if (!worker.addEventListener)
-            log("FAIL: worker.addEventListener did not exist.");
-        else
-            log("PASS: Successfully created worker.");
-    } catch (ex) {
-        log("FAIL: unexpected exception (" + ex + ") thrown when creating worker");
-    }
-    runNextTest();
-}
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-runNextTest();
-
+test(() => {
+  var worker = new Worker('resources/worker-common.js');
+  assert_true('postMessage' in worker,
+              'worker.postMessage did not exist.');
+  assert_true('addEventListener' in worker,
+              'worker.addEventListener did not exist.');
+}, 'Test the Worker object defines postMessage() and addEventListener().');
 </script>
-</body>
diff --git a/third_party/blink/web_tests/fast/workers/worker-messageport-expected.txt b/third_party/blink/web_tests/fast/workers/worker-messageport-expected.txt
deleted file mode 100644
index 906b6b80a..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-messageport-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Test that pages and workers can send MessagePorts to one another. Should print "DONE" when done.
-
-PASS: evt.ports = [] as expected
-PASS: Received message port
-PASS: Received response from Worker via MessagePort
-PASS: Got port from worker
-PASS: Received final response from worker
-PASS: Got 1000 messages
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-messageport.html b/third_party/blink/web_tests/fast/workers/worker-messageport.html
index aa81d7c..1c59195e 100644
--- a/third_party/blink/web_tests/fast/workers/worker-messageport.html
+++ b/third_party/blink/web_tests/fast/workers/worker-messageport.html
@@ -1,100 +1,69 @@
-<body>
-<p>Test that pages and workers can send MessagePorts to one another.
-Should print "DONE" when done.</p>
-<div id=result></div>
+<!DOCTYPE html>
+<title>Test that pages and workers can send MessagePorts to one another.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
 
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
+  // Send messages with and without ports to the worker to make sure it gets them.
+  worker.postMessage("noport");
+  worker.onmessage = t.step_func_done(evt => {
+    assert_equals(evt.data, "PASS: evt.ports = [] as expected");
+  });
+}, 'Test sending messages to workers with no port.');
 
-var worker = new Worker("resources/worker-messageport.js");
-var channel = new MessageChannel();
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
+  var channel = new MessageChannel();
 
-// Send messages with and without ports to the worker to make sure it gets them.
-worker.postMessage("noport");
-worker.onmessage = function(evt) {
-    log(evt.data);
-    worker.postMessage("port", [channel.port1]);
-    worker.onmessage = function(evt) {
-        log(evt.data);
-    }
-};
+  worker.postMessage("port", [channel.port1]);
+  worker.onmessage = t.step_func(evt => {
+    assert_equals(evt.data, "PASS: Received message port");
+  });
 
-// Send a message on the new port to make sure it gets to the worker.
-channel.port2.postMessage("ping");
+  // Send a message on the new port to make sure it gets to the worker.
+  channel.port2.postMessage("ping");
 
-// Wait for the response.
-channel.port2.onmessage = function(evt) {
-    if (evt.data == "pong") {
-        log("PASS: Received response from Worker via MessagePort");
-        worker.onmessage = awaitPortFromWorker;
-        worker.postMessage("getport");
-    } else {
-        log("FAIL: Received unknown event: " + evt.data);
-    }
-}
-channel.port2.start();
+  // Wait for the response.
+  channel.port2.onmessage = t.step_func_done(evt => {
+    assert_equals(evt.data, "pong");
+  });
+  channel.port2.start();
+}, 'Test sending message to a worker on a port.');
 
-// Invoked once the first batch of tests are done, to test sending from the worker.
-function awaitPortFromWorker(evt)
-{
-    if (evt.data == "port") {
-        if (!evt.ports) {
-            log("FAIL: Did not get port from worker");
-        } else if (evt.ports.length != 1) {
-            log("FAIL: Got the wrong number of ports from worker: " + evt.ports.length);
-        } else {
-            log("PASS: Got port from worker");
-            evt.ports[0].postMessage("ping");
-            evt.ports[0].onmessage = function(evt) {
-                if (evt.data == "pong") {
-                    log("PASS: Received final response from worker");
-                } else {
-                    log("FAIL: Got unexpected response: " + evt.data);
-                }
-                startSpamTest();
-            }
-            evt.ports[0].start();
-        }
-    } else {
-        log(evt.data);
-    }
-}
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
+  var channel = new MessageChannel();
 
-function startSpamTest()
-{
-    var channel = new MessageChannel();
-    worker.onmessage = function () { gotSpam(channel.port1); }
-    worker.postMessage("spam", [channel.port2]);
-}
+  worker.onmessage = t.step_func(evt => {
+    assert_equals(evt.data, "port");
+    assert_equals(String(evt.ports), "[object MessagePort]");
+    assert_equals(evt.ports.length, 1);
+    evt.ports[0].postMessage("ping");
+    evt.ports[0].onmessage = t.step_func_done(evt => {
+      assert_equals(evt.data, "pong");
+    });
+    evt.ports[0].start();
+  });
+  worker.postMessage("getport");
+}, 'Test getting messages from a worker on a port.');
 
-function gotSpam(port)
-{
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
+  var channel = new MessageChannel();
+  worker.onmessage = t.step_func(evt => { gotSpam(channel.port1); });
+  worker.postMessage("spam", [channel.port2]);
+
+  function gotSpam(port) {
     var spamCount = 0;
-    port.onmessage = function(evt) {
-        if (evt.data != spamCount)
-            log("FAIL: Got out of order message: " + spamCount);
-        spamCount++;
-        if (spamCount == 1000) {
-            log("PASS: Got 1000 messages");
-            done();
-        }
-    }
-}
-
-function done()
-{
-    log("DONE");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
+    port.onmessage = t.step_func(evt => {
+      assert_equals(evt.data, spamCount);
+      spamCount++;
+      if (spamCount == 1000) {
+        t.done();
+      }
+    });
+  }
+}, 'Test sending many messages to workers using ports.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-multi-port-expected.txt b/third_party/blink/web_tests/fast/workers/worker-multi-port-expected.txt
deleted file mode 100644
index edd4cbf..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-multi-port-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This test checks the various use cases around sending multiple ports through Worker.postMessage
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS worker.postMessage() threw exception TypeError: Failed to execute 'postMessage' on 'Worker': 1 argument required, but only 0 present..
-PASS worker.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception TypeError: Failed to execute 'postMessage' on 'Worker': Value at index 1 is an untransferable 'null' value..
-PASS worker.postMessage("notAPort", [channel3.port1, {}, channel3.port2]) threw exception TypeError: Failed to execute 'postMessage' on 'Worker': Value at index 1 does not have a transferable type..
-PASS worker.postMessage("notASequence", [{length: 3}]) threw exception TypeError: Failed to execute 'postMessage' on 'Worker': Value at index 0 does not have a transferable type..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-PASS postMessage() threw exception: TypeError: Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope': 1 argument required, but only 0 present.
-PASS event.ports is non-null and zero length when no port sent
-PASS event.ports is non-null and zero length when empty array sent
-PASS event.ports contains two ports when two ports sent
-PASS event.ports contains two ports when two ports re-sent after error
-
-TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/workers/worker-multi-port.html b/third_party/blink/web_tests/fast/workers/worker-multi-port.html
index 9efcd645..1a721f2 100644
--- a/third_party/blink/web_tests/fast/workers/worker-multi-port.html
+++ b/third_party/blink/web_tests/fast/workers/worker-multi-port.html
@@ -1,7 +1,86 @@
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="resources/worker-util.js"></script>
-<script src="resources/worker-multi-port.js"></script>
-</body>
+<!DOCTYPE html>
+<title>Test sending multiple ports through Worker.postMessage.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("noport");
+}, 'Test postMessage with no port.');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("noargs");
+}, 'Test postMessage with no arguments.');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("zero ports", []);
+}, 'Test postMessage with no ports and empty array.');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  var channel = new MessageChannel();
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("two ports", [channel.port1, channel.port2]);
+}, 'Test postMessage with two ports.');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  assert_throws(new TypeError(),
+                function() { worker.postMessage(); },
+                'Empty postMessage should throw exception.');
+}, 'Test empty postMessage throws exception.');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  var channel = new MessageChannel();
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("null port",
+                                                [channel.port1, null,
+                                                 channel.port2]); },
+                'postMessage with null ports should throw exception.');
+}, 'Test postMessage with null ports throws exception.');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js")
+  var channel = new MessageChannel();
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("notAPort",
+                                                [channel.port1, {},
+                                                 channel.port2]); },
+                'postMessage with incorrect ports should throw exception.');
+}, 'Test postMessage with incorrect ports throws exception');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("notASequence", [{length: 3}]) },
+                'postMessage without sequence should throw exception.');
+}, 'Test postMessage without sequence throws exception');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  var channel = new MessageChannel();
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("notAPort",
+                                                [channel.port1, {},
+                                                 channel.port2]); },
+                'postMessage with incorrect ports should throw exception.');
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("failed ports", [channel.port1, channel.port2]);
+}, 'Test postMessage on channel with previous failed postMessage calls.');
+</script>
diff --git a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error-expected.txt b/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error-expected.txt
deleted file mode 100644
index bcf9af0c1a..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This tests that errors from nested importScripts have the expected provenance.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-Starting worker: resources/importScripts-1.js
-PASS event.type is "error"
-PASS event.filename.indexOf('invalidScript.js') >= 0 is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html b/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html
index 49cdacc..61cdf4c7 100644
--- a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html
+++ b/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html
@@ -1,22 +1,17 @@
 <!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
+<title>This tests that errors from nested importScripts have the expected provenance.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-description("This tests that errors from nested importScripts have the expected provenance.");
+promise_test(t => {
+  let worker;
 
-self.jsTestIsAsync = true;
-
-var worker = startWorker("resources/importScripts-1.js");
-var event;
-worker.onerror = function (e) {
-    event = e;
-    shouldBeEqualToString("event.type", "error");
-    shouldBeTrue("event.filename.indexOf('invalidScript.js') >= 0");
-    finishJSTest();
-};
+  return new Promise((resolve) => {
+    worker = new Worker("resources/importScripts-1.js");
+    worker.onerror = resolve;
+  }).then(e => {
+    assert_equals(e.type, "error");
+    assert_true(e.filename.indexOf('invalidScript.js') >= 0);
+  });
+}, 'Tests that errors from the import scripts come from the expected file.')
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-structure-message-expected.txt b/third_party/blink/web_tests/fast/workers/worker-structure-message-expected.txt
deleted file mode 100644
index de7381f9..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-structure-message-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Test that pages and workers can send Structure Message to one another.
-
-On success, you will see a series of "PASS" messages, followed by "DONE".
-
-PASS: Worker receives correct structure message.
-PASS: Receive correct structure message from Worker.
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-structure-message.html b/third_party/blink/web_tests/fast/workers/worker-structure-message.html
index 10749af..200f863 100644
--- a/third_party/blink/web_tests/fast/workers/worker-structure-message.html
+++ b/third_party/blink/web_tests/fast/workers/worker-structure-message.html
@@ -1,53 +1,27 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test that pages and workers can send Structure Message to one another.</p>
-<p>On success, you will see a series of "PASS" messages, followed by "DONE".</p>
-<div id=result></div>
+<title>Test that pages and workers can send Structure Message to one another.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
+promise_test(t => {
+  let worker;
 
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-var worker = new Worker("resources/worker-structure-message.js");
-worker.onmessage = function(evt) {
-    log(evt.data);
-    if (evt.data.indexOf("FAIL") == 0) {
-        done();
-    }
-    worker.onmessage = function(evt) {
-        if (evt.data.operation == 'find-edges' &&
-            ArrayBuffer.prototype.isPrototypeOf(evt.data.input) &&
-            evt.data.input.byteLength == 20 &&
-            evt.data.threshold == 0.6) {
-                log("PASS: Receive correct structure message from Worker.");
-        }
-        else
-            log("FAIL: Receive error structure message from Worker.");
-        done();
-    }
-}
-
-var buf = new ArrayBuffer(20);
-worker.postMessage({
-    operation: 'find-edges',
-    input: buf,
-    threshold: 0.6
-});
-
-function done()
-{
-    log("DONE");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
+  return new Promise(resolve => {
+    worker = new Worker("resources/worker-structure-message.js");
+    worker.onmessage = resolve;
+    worker.postMessage({
+      operation: 'find-edges',
+      input: new ArrayBuffer(20),
+      threshold: 0.6
+    });
+  }).then(evt => {
+    assert_false(evt.data.startsWith('FAIL'));
+    return new Promise(resolve => worker.onmessage = resolve);
+  }).then(evt => {
+    assert_equals(evt.data.operation, 'find-edges');
+    assert_true(ArrayBuffer.prototype.isPrototypeOf(evt.data.input));
+    assert_equals(evt.data.input.byteLength, 20);
+    assert_equals(evt.data.threshold, 0.6);
+  });
+}, 'Tests sending structure message to/from worker.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-terminate-forever-expected.txt b/third_party/blink/web_tests/fast/workers/worker-terminate-forever-expected.txt
deleted file mode 100644
index be53ddf3..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-terminate-forever-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test Worker.terminate() for a worker that tries to run forever.
diff --git a/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html b/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html
index e3ca759..cd6db3e 100644
--- a/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html
+++ b/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html
@@ -1,11 +1,11 @@
-<body>
-<p>Test Worker.terminate() for a worker that tries to run forever.</p>
+<!DOCTYPE html>
+<title>Test Worker.terminate() for a worker that tries to run forever.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-var worker = new Worker('resources/worker-run-forever.js');
-worker.terminate();
+test((t) => {
+  var worker = new Worker('resources/worker-run-forever.js');
+  worker.terminate();
+  t.step_timeout(function() { t.done(); }, 500);
+}, 'Tests terminating a worker that is trying to run forever.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order-expected.txt b/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order-expected.txt
deleted file mode 100644
index 06d670f..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Test setTimeOut,cancelTimeout in Web Workers.
-
-Test started.
-PASS: Timeout canceled.
-DONE.
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html b/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html
index aa70fdf5..f15d51c9 100644
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html
+++ b/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html
@@ -1,41 +1,17 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test setTimeOut,cancelTimeout in Web Workers.</p>
-<div id="result"></div>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "</br>";
-}
+<title>Test setTimeOut,cancelTimeout in Web Workers.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+  let worker
 
-if (window.testRunner) {
-   testRunner.dumpAsText();
-   testRunner.waitUntilDone();
-}
-
-var worker = new Worker('resources/worker-timeout-cancel-order.js');
-var testAlreadyFailed = false;
-
-worker.postMessage("TS");
-
-worker.onmessage = function(evt) {
-    if (evt.data == "DONE") {
-        log("DONE.");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-    if(2 == evt.data && !testAlreadyFailed) {
-        log("PASS: Timeout canceled.");
-    }
-    else if(1 == evt.data) {
-        testAlreadyFailed = true;
-        log("FAIL: Timeout did not cancel.");
-    }
-    if(evt.data == "Test started.") {
-        log(evt.data);
-    }
-}
+  return new Promise(resolve => {
+    worker = new Worker('resources/worker-timeout-cancel-order.js');
+    worker.postMessage('start');
+    worker.onmessage = resolve;
+  }).then(evt => {
+    assert_equals(evt.data, 2, 'Timeout not canceled');
+  });
+}, 'Tests setting and canceling timeout in workers.');
 </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order-expected.txt b/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order-expected.txt
deleted file mode 100644
index 3e57e03..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Test setTimeOut,fired in decreasing order in Web Workers.
-
-Test started.
-PASS: Timeouts executed in order.
-DONE.
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html b/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html
index 14257bc..da4056c 100644
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html
+++ b/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html
@@ -1,56 +1,23 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test setTimeOut,fired in decreasing order in Web Workers.</p>
-<div id="result"></div>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "</br>";
-}
-
-if (window.testRunner) {
-   testRunner.dumpAsText();
-   testRunner.waitUntilDone();
-}
-
-var worker = new Worker('resources/worker-timeout-decreasing-order.js');
-// Start the first test of settimeout's
-var lastTestResult = 0;
-var testCounterLimit = 3;
-var timerLimit = 3;
-var testStarted = false;
-var testAlreadyFailed = false;
-
-worker.postMessage("TS");
-
-worker.onmessage = function(evt) {
-    if(testStarted) {
-        var currentNum = evt.data;
-        if(lastTestResult == currentNum - 1 && !testAlreadyFailed) {
-            lastTestResult = currentNum;
-            --timerLimit;
-            // we got all the results in order
-            if(lastTestResult == testCounterLimit && timerLimit == 0)
-                log("PASS: Timeouts executed in order.");
-        }
-        else {
-            testAlreadyFailed = true;
-            --timerLimit;
-            if(timerLimit == 0)
-                log("FAIL: Timeouts executed out of order.");
-        }
-    }
-    if(evt.data == "Test started.") {
-        log(evt.data);
-        testStarted = true;
-    }
-    if (evt.data == "DONE") {
-        log("DONE.");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    } 
-}
+<title>Test setTimeOut,fired in decreasing order in Web Workers.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+promise_test (t => {
+  let worker;
+    
+  return new Promise(resolve => {
+    worker = new Worker('resources/worker-timeout-decreasing-order.js');
+    worker.postMessage('start');
+    worker.onmessage = resolve;
+  }).then(evt => {
+    assert_equals(evt.data, 1);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 2);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 3);
+  });
+}, 'Tests timeouts on the worker are fired in decreasing order.');
 </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order-expected.txt b/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order-expected.txt
deleted file mode 100644
index 96299ea..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Test setTimeOut,fired in increasing order in Web Workers.
-
-Test started.
-PASS: Timeouts executed in order.
-DONE.
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html b/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html
index 3c40a306..3e44116 100644
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html
+++ b/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html
@@ -1,55 +1,23 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test setTimeOut,fired in increasing order in Web Workers.</p>
-<div id="result"></div>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "</br>";
-}
+<title>Test setTimeOut,fired in increasing order in Web Workers.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+promise_test (t => {
+  let worker;
 
-if (window.testRunner) {
-   testRunner.dumpAsText();
-   testRunner.waitUntilDone();
-}
-
-var worker = new Worker('resources/worker-timeout-increasing-order.js');
-var lastTestResult = 0;
-var testCounterLimit = 3;
-var timerLimit = 3;
-var testStarted = false;
-var testAlreadyFailed = false;
-
-worker.postMessage("TS");
-
-worker.onmessage = function(evt) {
-    if(testStarted) {
-        var currentNum = evt.data;
-        if(lastTestResult == currentNum - 1 && !testAlreadyFailed) {
-            lastTestResult = currentNum;
-            --timerLimit;
-            // we got all the results in order
-            if(lastTestResult == testCounterLimit && timerLimit == 0)
-                log("PASS: Timeouts executed in order.");
-        }
-        else {
-            testAlreadyFailed = true;
-            --timerLimit;
-            if(timerLimit == 0)
-                log("FAIL: PASS: Timeouts executed out of order.");
-        }
-    }
-    if(evt.data == "Test started.") {
-        log(evt.data);
-        testStarted = true;
-    }
-    if (evt.data == "DONE") {
-        log("DONE.");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-}
+  return new Promise(resolve => {
+    worker = new Worker('resources/worker-timeout-increasing-order.js');
+    worker.postMessage('start');
+    worker.onmessage = resolve;
+  }).then(evt => {
+    assert_equals(evt.data, 1);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 2);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 3);
+  });
+}, 'Tests timeouts on the worker are fired in increasing order.');
 </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
index 8de8cd8..9b79eae9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
@@ -29,6 +29,7 @@
 ScriptPromises
 TaskDuration
 TaskOtherDuration
+ThreadTime
 Timestamp
 UACSSResources
 V8CompileDuration
diff --git a/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt b/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
index 46961bf..40bc7a2 100644
--- a/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
@@ -27,6 +27,7 @@
 	V8CompileDuration
 	TaskDuration
 	TaskOtherDuration
+	ThreadTime
 	JSHeapUsedSize
 	JSHeapTotalSize
 	FirstMeaningfulPaint
@@ -60,6 +61,7 @@
 	V8CompileDuration
 	TaskDuration
 	TaskOtherDuration
+	ThreadTime
 	JSHeapUsedSize
 	JSHeapTotalSize
 	FirstMeaningfulPaint
@@ -93,6 +95,7 @@
 	V8CompileDuration
 	TaskDuration
 	TaskOtherDuration
+	ThreadTime
 	JSHeapUsedSize
 	JSHeapTotalSize
 	FirstMeaningfulPaint
diff --git a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/resource-timing/resource_dedicated_worker-expected.txt b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/resource-timing/resource_dedicated_worker-expected.txt
new file mode 100644
index 0000000..7a7c389
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/resource-timing/resource_dedicated_worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL There should be six entries: 4 scripts, 1 stylesheet, and the worker itself assert_equals: There should be six entries: 4 scripts, 1 stylesheet, and the worker itself expected 6 but got 5
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index 54c4281f..ff94f3d 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -1146,7 +1146,6 @@
     property onencrypted
     property onenterpictureinpicture
     property onleavepictureinpicture
-    property onpictureinpicturecontrolclick
     property onwaitingforkey
     property pause
     property paused
@@ -1161,7 +1160,6 @@
     property seekable
     property seeking
     property setMediaKeys
-    property setPictureInPictureControls
     property setSinkId
     property sinkId
     property src
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index f0e6d703..0296a9e 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -3903,7 +3903,6 @@
     getter intrinsicSize
     getter onenterpictureinpicture
     getter onleavepictureinpicture
-    getter onpictureinpicturecontrolclick
     getter poster
     getter videoHeight
     getter videoWidth
@@ -3915,7 +3914,6 @@
     method constructor
     method getVideoPlaybackQuality
     method requestPictureInPicture
-    method setPictureInPictureControls
     method webkitEnterFullScreen
     method webkitEnterFullscreen
     method webkitExitFullScreen
@@ -3926,7 +3924,6 @@
     setter intrinsicSize
     setter onenterpictureinpicture
     setter onleavepictureinpicture
-    setter onpictureinpicturecontrolclick
     setter poster
     setter width
 interface HashChangeEvent : Event
@@ -5411,11 +5408,6 @@
     getter imageWidth
     getter redEyeReduction
     method constructor
-interface PictureInPictureControlEvent : Event
-    attribute @@toStringTag
-    getter id
-    method constructor
-    setter id
 interface PictureInPictureWindow : EventTarget
     attribute @@toStringTag
     getter height
diff --git a/third_party/feed/README.chromium b/third_party/feed/README.chromium
index dd85354e..f56f58e 100644
--- a/third_party/feed/README.chromium
+++ b/third_party/feed/README.chromium
@@ -2,7 +2,7 @@
 Short name: feed
 URL: https://chromium.googlesource.com/feed
 Version: 0
-Revision: 3293f23ae831c666be27273fbf2a73d9b2fe7552
+Revision: d21310a7afa812e54d9d235de12cb409a0fd28c4
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/feed/java_sources.gni b/third_party/feed/java_sources.gni
index 29b85be..b4487c5 100644
--- a/third_party/feed/java_sources.gni
+++ b/third_party/feed/java_sources.gni
@@ -9,6 +9,8 @@
   "src/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionReader.java",
   "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionParser.java",
   "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionParserFactory.java",
+  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionSource.java",
+  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionSourceConverter.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/DismissActionWithSemanticProperties.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/MutationContext.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/PayloadWithId.java",
@@ -227,7 +229,6 @@
   "src/src/main/java/com/google/android/libraries/feed/piet/RecyclerKey.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/RecyclerPool.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/SingleKeyRecyclerPool.java",
-  "src/src/main/java/com/google/android/libraries/feed/piet/SpacerElementAdapter.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/StyleProvider.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/TemplateBinder.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/TextElementAdapter.java",
@@ -265,6 +266,7 @@
   "src/src/main/java/com/google/android/libraries/feed/sharedstream/offlinemonitor/StreamOfflineMonitor.java",
   "src/src/main/java/com/google/android/libraries/feed/sharedstream/pendingdismiss/PendingDismissCallback.java",
   "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietCustomElementProvider.java",
+  "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietEventLogger.java",
   "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietHostBindingProvider.java",
   "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietImageLoader.java",
   "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietStringFormatter.java",
diff --git a/third_party/gvr-android-sdk/BUILD.gn b/third_party/gvr-android-sdk/BUILD.gn
index e1156c03..2394d26b 100644
--- a/third_party/gvr-android-sdk/BUILD.gn
+++ b/third_party/gvr-android-sdk/BUILD.gn
@@ -114,9 +114,7 @@
       "//clank/third_party/gvr_shim",
     ]
   } else {
-    if (!use_custom_libcxx) {
-      cxx_abi_version = "ndk1"
-    } else if (is_component_build) {
+    if (is_component_build) {
       cxx_abi_version = "Cr"
     } else {
       cxx_abi_version = "1"
diff --git a/third_party/ijar/BUILD.gn b/third_party/ijar/BUILD.gn
index 89b863a9..62bf29e 100644
--- a/third_party/ijar/BUILD.gn
+++ b/third_party/ijar/BUILD.gn
@@ -20,11 +20,14 @@
       sources += [ "mapped_file_unix.cc" ]
     }
 
+    deps = [
+      "//third_party/zlib",
+    ]
+
     # Always build release since this is a build tool.
     if (is_debug) {
       configs -= [ "//build/config:debug" ]
       configs += [ "//build/config:release" ]
     }
-    ldflags = [ "-lz" ]
   }
 }
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_cc.template b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
index ed33164..5c4b8c6 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_cc.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
@@ -136,7 +136,7 @@
         reinterpret_cast<const uint8_t*>(message.data()),
         message.length());
   }
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(message);
   return toProtocolValue(value.get(), 1000);
 }
 
diff --git a/third_party/libaddressinput/chromium/json.cc b/third_party/libaddressinput/chromium/json.cc
index 2423e91..feaa70a 100644
--- a/third_party/libaddressinput/chromium/json.cc
+++ b/third_party/libaddressinput/chromium/json.cc
@@ -28,7 +28,7 @@
   // |json| is converted to a |c_str()| here because rapidjson and other parts
   // of the standalone library use char* rather than std::string.
   ::std::unique_ptr<const base::Value> parsed(
-      base::JSONReader::Read(json.c_str()));
+      base::JSONReader::ReadDeprecated(json.c_str()));
   *parser_error = !parsed || !parsed->is_dict();
 
   if (*parser_error)
diff --git a/third_party/ow2_asm/README.chromium b/third_party/ow2_asm/README.chromium
index cdcf29e8..09ea3cb 100644
--- a/third_party/ow2_asm/README.chromium
+++ b/third_party/ow2_asm/README.chromium
@@ -1,6 +1,6 @@
 Name: ASM
 URL: http://asm.ow2.org/
-Version: 5.0.1
+Version: 6.0
 License: BSD 3-Clause
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/robolectric/BUILD.gn b/third_party/robolectric/BUILD.gn
index 63a19e63..3b90a712 100644
--- a/third_party/robolectric/BUILD.gn
+++ b/third_party/robolectric/BUILD.gn
@@ -7,7 +7,7 @@
 java_group("robolectric_all_java") {
   testonly = true
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_annotations_java",
     ":robolectric_java",
     ":robolectric_junit_java",
@@ -20,29 +20,29 @@
   ]
 }
 
-java_prebuilt("android-all-4.1.2_r1-robolectric-0_java") {
+java_prebuilt("android-all-4.1.2_r1-robolectric-r1_java") {
   testonly = true
-  jar_path = "lib/android-all-4.1.2_r1-robolectric-0.jar"
+  jar_path = "lib/android-all-4.1.2_r1-robolectric-r1.jar"
 }
 
-java_prebuilt("android-all-4.3_r2-robolectric-0_java") {
+java_prebuilt("android-all-4.3_r2-robolectric-r1_java") {
   testonly = true
-  jar_path = "lib/android-all-4.3_r2-robolectric-0.jar"
+  jar_path = "lib/android-all-4.3_r2-robolectric-r1.jar"
 }
 
-java_prebuilt("android-all-5.0.0_r2-robolectric-1_java") {
+java_prebuilt("android-all-5.0.2_r3-robolectric-r0_java") {
   testonly = true
-  jar_path = "lib/android-all-5.0.0_r2-robolectric-1.jar"
+  jar_path = "lib/android-all-5.0.2_r3-robolectric-r0.jar"
 }
 
-java_prebuilt("android-all-7.1.0_r7-robolectric-0_java") {
+java_prebuilt("android-all-7.1.0_r7-robolectric-r1_java") {
   testonly = true
-  jar_path = "lib/android-all-7.1.0_r7-robolectric-0.jar"
+  jar_path = "lib/android-all-7.1.0_r7-robolectric-r1.jar"
 }
 
-java_prebuilt("android-all-8.0.0_r4-robolectric-0_java") {
+java_prebuilt("android-all-8.0.0_r4-robolectric-r1_java") {
   testonly = true
-  jar_path = "lib/android-all-8.0.0_r4-robolectric-0.jar"
+  jar_path = "lib/android-all-8.0.0_r4-robolectric-r1.jar"
 }
 
 java_prebuilt("android-all-8.1.0-robolectric-r4402310_java") {
@@ -50,6 +50,11 @@
   jar_path = "lib/android-all-8.1.0-robolectric-r4402310.jar"
 }
 
+java_prebuilt("android-all-9-robolectric-4913185-2_java") {
+  testonly = true
+  jar_path = "lib/android-all-9-robolectric-4913185-2.jar"
+}
+
 java_library("robolectric_java") {
   testonly = true
 
@@ -57,7 +62,7 @@
   # depends on targets that requires_android.
   bypass_platform_checks = true
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_annotations_java",
     ":robolectric_junit_java",
     ":robolectric_resources_java",
@@ -65,6 +70,9 @@
     ":robolectric_shadowapi_java",
     ":robolectric_utils_java",
     ":shadows_core_java",
+    "//third_party/androidx:androidx_core_java",
+    "//third_party/androidx:androidx_junit_java",
+    "//third_party/androidx:androidx_monitor_java",
     "//third_party/bouncycastle:bouncycastle_java",
     "//third_party/guava:guava_java",
     "//third_party/jsr-305:jsr_305_javalib",
@@ -72,14 +80,16 @@
     "//third_party/xstream:xstream_java",
   ]
   data_deps = [
-    ":android-all-4.1.2_r1-robolectric-0_java",
-    ":android-all-4.3_r2-robolectric-0_java",
-    ":android-all-5.0.0_r2-robolectric-1_java",
-    ":android-all-7.1.0_r7-robolectric-0_java",
-    ":android-all-8.0.0_r4-robolectric-0_java",
+    ":android-all-4.1.2_r1-robolectric-r1_java",
+    ":android-all-4.3_r2-robolectric-r1_java",
+    ":android-all-5.0.2_r3-robolectric-r0_java",
+    ":android-all-7.1.0_r7-robolectric-r1_java",
+    ":android-all-8.0.0_r4-robolectric-r1_java",
+    ":android-all-9-robolectric-4913185-2_java",
   ]
   java_files = [
     "local/robolectric/src/main/java/org/robolectric/internal/dependency/MavenDependencyResolver.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/ApkLoader.java",
     "robolectric/robolectric/src/main/java/org/robolectric/ConfigMerger.java",
     "robolectric/robolectric/src/main/java/org/robolectric/DefaultTestLifecycle.java",
     "robolectric/robolectric/src/main/java/org/robolectric/ParameterizedRobolectricTestRunner.java",
@@ -88,27 +98,21 @@
     "robolectric/robolectric/src/main/java/org/robolectric/SdkPicker.java",
     "robolectric/robolectric/src/main/java/org/robolectric/TestLifecycle.java",
     "robolectric/robolectric/src/main/java/org/robolectric/TestLifecycleApplication.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/TestLifecycleApplicationImpl.java",
     "robolectric/robolectric/src/main/java/org/robolectric/android/AndroidInterceptors.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/ApplicationTestUtil.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/ActivityController.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/BackupAgentController.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/ComponentController.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/ContentProviderController.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/FragmentController.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/IntentServiceController.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/controller/ServiceController.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/android/AttributeSetBuilder.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java",
     "robolectric/robolectric/src/main/java/org/robolectric/android/fakes/RoboCharsets.java",
     "robolectric/robolectric/src/main/java/org/robolectric/android/fakes/RoboExtendedResponseCache.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/fakes/RoboInstrumentation.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/android/fakes/RoboMonitoringInstrumentation.java",
     "robolectric/robolectric/src/main/java/org/robolectric/android/fakes/RoboResponseSource.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/android/internal/ClassNameResolver.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/android/internal/NoOpThreadChecker.java",
     "robolectric/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/android/internal/RoboUiController.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/AndroidConfigurer.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/BuckManifestFactory.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/internal/DeepCloner.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/DefaultManifestFactory.java",
-    "robolectric/robolectric/src/main/java/org/robolectric/internal/GradleManifestFactory.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/internal/DeprecatedMethodMarkerException.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/ManifestFactory.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/ManifestIdentifier.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/MavenManifestFactory.java",
@@ -121,7 +125,9 @@
     "robolectric/robolectric/src/main/java/org/robolectric/internal/dependency/DependencyResolver.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/dependency/LocalDependencyResolver.java",
     "robolectric/robolectric/src/main/java/org/robolectric/internal/dependency/PropertiesDependencyResolver.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/junit/rules/ExpectedLogMessagesRule.java",
     "robolectric/robolectric/src/main/java/org/robolectric/package-info.java",
+    "robolectric/robolectric/src/main/java/org/robolectric/res/NullResourceTable.java",
     "robolectric/robolectric/src/main/java/org/robolectric/util/FragmentTestUtil.java",
   ]
   additional_jar_files = [ [
@@ -136,7 +142,7 @@
 java_library("robolectric_annotations_java") {
   testonly = true
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_shadowapi_java",
     "//third_party/intellij:intellij_annotations_java",
     "//third_party/jsr-305:jsr_305_javalib",
@@ -159,11 +165,15 @@
   testonly = true
   deps = [
     ":robolectric_annotations_java",
+    ":sdk_list_txt",
     "//build/android:sun_tools_java",
     "//third_party/gson:gson_java",
     "//third_party/guava:guava_java",
     "//third_party/intellij:intellij_annotations_java",
     "//third_party/jsr-305:jsr_305_javalib",
+    "//third_party/ow2_asm:asm_commons_java",
+    "//third_party/ow2_asm:asm_java",
+    "//third_party/ow2_asm:asm_tree_java",
   ]
   provider_configurations = [ "local/processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor" ]
   main_class = "org.robolectric.annotation.processing.RobolectricProcessor"
@@ -172,6 +182,7 @@
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/DocumentedMethod.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/DocumentedPackage.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/DocumentedType.java",
+    "robolectric/processor/src/main/java/org/robolectric/annotation/processing/Helpers.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/RobolectricModel.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/RobolectricProcessor.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/generator/Generator.java",
@@ -185,18 +196,43 @@
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/validator/RealObjectValidator.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/validator/ResetterValidator.java",
+    "robolectric/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/validator/Validator.java",
     "robolectric/processor/src/main/java/org/robolectric/annotation/processing/validator/package-info.java",
   ]
 
+  sdk_target_dir = "$target_out_dir/sdks.txt"
+  include_java_resources = true
+  additional_jar_files = [ [
+        sdk_target_dir,
+        "sdks.txt",
+      ] ]
+
   # Work-around for gradle generator not yet supporting annotation processors.
   gradle_treat_as_prebuilt = true
 }
 
+group("sdk_list_txt") {
+  sdk_target_dir = "$target_out_dir/sdks.txt"
+
+  # Write to a file some GN vars that are useful to scripts that use the output
+  # directory. Format is chosen as easliy importable by both python and bash.
+  CR = "$0x0A"
+  _data = ""
+  _data += rebase_path("lib/android-all-4.1.2_r1-robolectric-r1.jar") + CR
+  _data += rebase_path("lib/android-all-4.3_r2-robolectric-r1.jar") + CR
+  _data += rebase_path("lib/android-all-5.0.2_r3-robolectric-r0.jar") + CR
+  _data += rebase_path("lib/android-all-7.1.0_r7-robolectric-r1.jar") + CR
+  _data += rebase_path("lib/android-all-8.0.0_r4-robolectric-r1.jar") + CR
+  _data += rebase_path("lib/android-all-8.1.0-robolectric-r4402310.jar") + CR
+  _data += rebase_path("lib/android-all-9-robolectric-4913185-2.jar") + CR
+  write_file(sdk_target_dir, _data)
+}
+
 java_library("robolectric_resources_java") {
   testonly = true
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_annotations_java",
     ":robolectric_utils_java",
     "//third_party/guava:guava_java",
@@ -204,6 +240,7 @@
   ]
   java_files = [
     "robolectric/resources/src/main/java/org/robolectric/RoboSettings.java",
+    "robolectric/resources/src/main/java/org/robolectric/UsesSdk.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/ActivityData.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/BroadcastReceiverData.java",
@@ -212,6 +249,7 @@
     "robolectric/resources/src/main/java/org/robolectric/manifest/MetaData.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/PackageItemData.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/PathPermissionData.java",
+    "robolectric/resources/src/main/java/org/robolectric/manifest/PermissionGroupItemData.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/PermissionItemData.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/RoboNotFoundException.java",
     "robolectric/resources/src/main/java/org/robolectric/manifest/ServiceData.java",
@@ -259,6 +297,51 @@
     "robolectric/resources/src/main/java/org/robolectric/res/ThemeStyleSet.java",
     "robolectric/resources/src/main/java/org/robolectric/res/TypedResource.java",
     "robolectric/resources/src/main/java/org/robolectric/res/XmlContext.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/AConfiguration.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ApkAssetsCookie.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Asset.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/AssetDir.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/AssetPath.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/AttributeResolution.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/AttributeResolution9.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ByteBucketArray.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Chunk.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ConfigDescription.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/CppApkAssets.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/DataType.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/DynamicRefTable.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Errors.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/FileMap.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Formatter.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Idmap.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/IdmapEntries.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/LocaleData.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/LocaleDataTables.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/NativeObjRegistry.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Ref.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Registries.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResStringPool.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResStringPoolHeader.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResStringPoolRef.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResTable.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResTableTheme.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResTable_config.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResXMLParser.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResXMLTree.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResourceString.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResourceTable.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ResourceUtils.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/SortedVector.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/String8.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/StringPiece.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/StringPoolRef.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/Util.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ZipArchiveHandle.java",
+    "robolectric/resources/src/main/java/org/robolectric/res/android/ZipFileRO.java",
     "robolectric/resources/src/main/java/org/robolectric/res/builder/XmlBlock.java",
   ]
 }
@@ -269,10 +352,15 @@
     ":robolectric_annotations_java",
   ]
   java_files = [
+    "robolectric/utils/src/main/java/org/robolectric/AndroidMetadata.java",
+    "robolectric/utils/src/main/java/org/robolectric/util/Clock.java",
+    "robolectric/utils/src/main/java/org/robolectric/util/Consumer.java",
     "robolectric/utils/src/main/java/org/robolectric/util/Join.java",
     "robolectric/utils/src/main/java/org/robolectric/util/Logger.java",
     "robolectric/utils/src/main/java/org/robolectric/util/NamedStream.java",
     "robolectric/utils/src/main/java/org/robolectric/util/Pair.java",
+    "robolectric/utils/src/main/java/org/robolectric/util/PerfStatsCollector.java",
+    "robolectric/utils/src/main/java/org/robolectric/util/PerfStatsReporter.java",
     "robolectric/utils/src/main/java/org/robolectric/util/Scheduler.java",
     "robolectric/utils/src/main/java/org/robolectric/util/SimpleFuture.java",
     "robolectric/utils/src/main/java/org/robolectric/util/SoftThreadLocal.java",
@@ -299,32 +387,42 @@
   ]
 
   java_files = [
+    "robolectric/sandbox/src/main/java/org/robolectric/JarInstrumentor.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassHandler.java",
-    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInfo.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassNodeProvider.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassValueMap.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/DirectObjectMarker.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/InstrumentationConfiguration.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/InstrumentingClassWriter.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/Interceptor.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/Interceptors.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/InvocationProfile.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/InvokeDynamic.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/InvokeDynamicClassInstrumentor.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/InvokeDynamicSupport.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/MethodCallSite.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/MethodRef.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/MethodSignature.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/MutableClass.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/OldClassInstrumentor.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ProxyMaker.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/RoboCallSite.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/RoboType.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/RobolectricGeneratorAdapter.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/RobolectricInternals.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/Sandbox.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/SandboxClassLoader.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/SandboxConfig.java",
-    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowConfig.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowConstants.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowDecorator.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowImpl.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowInfo.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowInvalidator.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowMap.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java",
     "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowedObject.java",
+    "robolectric/sandbox/src/main/java/org/robolectric/internal/bytecode/TypeMapper.java",
     "robolectric/sandbox/src/main/java/org/robolectric/util/Function.java",
     "robolectric/sandbox/src/main/java/org/robolectric/util/JavaVersion.java",
   ]
@@ -356,6 +454,7 @@
     "robolectric/shadowapi/src/main/java/org/robolectric/internal/IShadow.java",
     "robolectric/shadowapi/src/main/java/org/robolectric/internal/ShadowProvider.java",
     "robolectric/shadowapi/src/main/java/org/robolectric/shadow/api/Shadow.java",
+    "robolectric/shadowapi/src/main/java/org/robolectric/shadow/api/ShadowPicker.java",
     "robolectric/shadowapi/src/main/java/org/robolectric/util/ReflectionHelpers.java",
   ]
 }
@@ -410,9 +509,19 @@
   java_files = [
     "robolectric/shadows/framework/src/main/java/android/webkit/RoboCookieManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/ShadowsAdapter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/android/AccessibilityUtil.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/Bootstrap.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/ConfigurationV25.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/DeviceConfig.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/android/XmlResourceParserImpl.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/BackupAgentController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/ComponentController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/ContentProviderController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/FragmentController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/IntentServiceController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/controller/ServiceController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/android/internal/DisplayConfig.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/android/util/concurrent/RoboExecutorService.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/BaseCursor.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/RoboCursor.java",
@@ -420,20 +529,27 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/RoboMenu.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/RoboMenuItem.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/RoboSubMenu.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/RoboVibrator.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/RoboWebSettings.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/fakes/package-info.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/CachedPathIteratorFactory.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ClassNameResolver.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/CoreShadowsAdapter.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/Converter2.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ImageUtil.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/LegacyManifestParser.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/NativeAndroidInput.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/NativeBitSet64.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/NativeInput.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/Provider.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ResourceHelper.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ResourceHelper2.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ResourceModeShadowPicker.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/RoboLayoutInflater.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/RoundRectangle.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsListView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsSeekBar.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsSpinner.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbstractCursor.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityEvent.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityNodeInfo.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityRecord.java",
@@ -452,19 +568,31 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAndroidBidi.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAnimationBridge.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAnimationUtils.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppTask.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHost.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHostView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplication.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArrayAdapter.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetInputStream.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager9.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscResourcesImpl.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetInputStream.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncQueryHandler.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTask.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTaskBridge.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTaskLoader.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioEffect.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAutofillManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBackgroundThread.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBackupManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBaseAdapter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBatteryManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBinder.java",
@@ -474,17 +602,24 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapFactory.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapRegionDecoder.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapShader.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBlockGuardOs.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothDevice.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothGatt.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothServerSocket.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastPendingResult.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastReceiver.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBuild.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCamera.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraCharacteristics.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCanvas.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCaptioningManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCarrierConfigManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowChoreographer.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowClipboardManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColor.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColorMatrix.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColorMatrixColorFilter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCompoundButton.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowConnectivityManager.java",
@@ -502,7 +637,6 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieSyncManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCornerPathEffect.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorAdapter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWindow.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWrapper.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDashPathEffect.java",
@@ -510,18 +644,29 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormat.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDatePickerDialog.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDebug.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDevicePolicyManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDialog.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDiscoverySession.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplay.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManagerGlobal.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDrawable.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDropBoxManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEdgeEffect.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEnvironment.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEuiccManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEventLog.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowExifInterface.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowExpandableListView.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFileUtils.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFilter.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFingerprintManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFloatMath.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFrameLayout.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFontFamily.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGLES20.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGLSurfaceView.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGeocoder.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGestureDetector.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGradientDrawable.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHandler.java",
@@ -529,18 +674,27 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIAppOpsService.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowICU.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIcon.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputDevice.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEvent.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEventReceiver.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputMethodManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIntent.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIntentService.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIoUtils.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobScheduler.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobService.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJsPromptResult.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJsResult.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyguardManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLayoutAnimationController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetInputStream.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyResourcesImpl.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinearGradient.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinearLayout.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinkMovementMethod.java",
@@ -554,6 +708,7 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLog.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLooper.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMatrix.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMeasuredParagraph.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaMetadataRetriever.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaPlayer.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaRecorder.java",
@@ -567,12 +722,15 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMimeTypeMap.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMotionEvent.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeAllocationRegistry.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativePluralRules.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetwork.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetworkInfo.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetworkScoreManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNfcAdapter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNinePatch.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNotification.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNotificationManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNsdManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNumberPicker.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowObjectAnimator.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOpenGLMatrix.java",
@@ -580,21 +738,26 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOverScroller.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageInstaller.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageParser.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcel.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcelFileDescriptor.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPath.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathMeasure.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathParser.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPeerHandle.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPendingIntent.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindowFor22.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPicture.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPlayerBase.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPolicyManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupMenu.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupWindow.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPorterDuffColorFilter.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPosix.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPrecomputedText.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPreference.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProcess.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProgressBar.java",
@@ -606,22 +769,28 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRenderNode.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRenderNodeAnimator.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResolveInfo.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourceManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResources.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesImpl.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRestrictionsManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResultReceiver.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteConnection.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteOpenHelper.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScaleGestureDetector.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScanResult.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScrollView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScroller.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSearchManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSeekBar.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowService.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSharedMemory.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSharedPreferences.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowShortcutManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSliceManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSmsManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSocketTagger.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSoundPool.java",
@@ -630,31 +799,44 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatFs.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStateListDrawable.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStaticLayout.java",
-    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStrictMode.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStorageManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStrictModeVmPolicy.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStringBlock.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSubscriptionManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurface.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurfaceView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemProperties.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemServiceRegistry.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemVibrator.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabActivity.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabHost.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabWidget.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephony.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephonyManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextPaint.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextToSpeech.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextView.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTile.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTileService.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTime.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimePickerDialog.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowToast.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTouchDelegate.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTrafficStats.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypeface.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVMRuntime.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowValueAnimator.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVectorDrawable.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVelocityTracker.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVibrator.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVideoView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewAnimator.java",
@@ -662,7 +844,9 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewGroup.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVirtualRefBasePtr.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVisualVoicemailSms.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWallpaperManager.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebStorage.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebSyncManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebView.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebViewDatabase.java",
@@ -675,7 +859,9 @@
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManager.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerImpl.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowXmlBlock.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowZoomButtonsController.java",
+    "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/StorageVolumeBuilder.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/package-info.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/util/AppSingletonizer.java",
     "robolectric/shadows/framework/src/main/java/org/robolectric/shadows/util/DataSource.java",
@@ -685,7 +871,7 @@
 
   annotation_processor_deps = [ ":robolectric_processor" ]
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_annotations_java",
     ":robolectric_resources_java",
     ":robolectric_shadowapi_java",
@@ -716,13 +902,14 @@
   processor_args_javac = [ "org.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.multidex" ]
   provider_configurations = [ "local/shadows/multidex/src/main/resources/META-INF/services/org.robolectric.internal.ShadowProvider" ]
   java_files = [
+    "robolectric/shadows/multidex/src/main/java/org/robolectric/shadows/multidex/ShadowAndroidXMultiDex.java",
     "robolectric/shadows/multidex/src/main/java/org/robolectric/shadows/multidex/ShadowMultiDex.java",
     "robolectric/shadows/multidex/src/main/java/org/robolectric/shadows/multidex/package-info.java",
   ]
 
   annotation_processor_deps = [ ":robolectric_processor" ]
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_annotations_java",
     ":robolectric_shadowapi_java",
     ":robolectric_utils_java",
@@ -754,7 +941,7 @@
 
   annotation_processor_deps = [ ":robolectric_processor" ]
   deps = [
-    ":android-all-8.1.0-robolectric-r4402310_java",
+    ":android-all-9-robolectric-4913185-2_java",
     ":robolectric_annotations_java",
     ":robolectric_resources_java",
     ":robolectric_shadowapi_java",
diff --git a/third_party/robolectric/README.chromium b/third_party/robolectric/README.chromium
index 03d4238..0e029b4 100644
--- a/third_party/robolectric/README.chromium
+++ b/third_party/robolectric/README.chromium
@@ -1,6 +1,6 @@
 Name: Robolectric
 URL: http://robolectric.org
-Version: 3.5.1
+Version: 4.0.1
 License: Apache 2.0
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/robolectric/cipd.yaml b/third_party/robolectric/cipd.yaml
index 6d95512..a9e8a77 100644
--- a/third_party/robolectric/cipd.yaml
+++ b/third_party/robolectric/cipd.yaml
@@ -7,9 +7,10 @@
 package: chromium/third_party/robolectric
 description: robolectric modified Android SDKs
 data:
-  - file: lib/android-all-4.1.2_r1-robolectric-0.jar
-  - file: lib/android-all-4.3_r2-robolectric-0.jar
-  - file: lib/android-all-5.0.0_r2-robolectric-1.jar
-  - file: lib/android-all-7.1.0_r7-robolectric-0.jar
-  - file: lib/android-all-8.0.0_r4-robolectric-0.jar
+  - file: lib/android-all-4.1.2_r1-robolectric-r1.jar
+  - file: lib/android-all-4.3_r2-robolectric-r1.jar
+  - file: lib/android-all-5.0.2_r3-robolectric-r0.jar
+  - file: lib/android-all-7.1.0_r7-robolectric-r1.jar
+  - file: lib/android-all-8.0.0_r4-robolectric-r1.jar
   - file: lib/android-all-8.1.0-robolectric-r4402310.jar
+  - file: lib/android-all-9-robolectric-4913185-2.jar
diff --git a/third_party/robolectric/local/robolectric/src/main/resources/robolectric-version.properties b/third_party/robolectric/local/robolectric/src/main/resources/robolectric-version.properties
index 788eae44..d98b0ca 100644
--- a/third_party/robolectric/local/robolectric/src/main/resources/robolectric-version.properties
+++ b/third_party/robolectric/local/robolectric/src/main/resources/robolectric-version.properties
@@ -1 +1 @@
-robolectric.version=3.5.1
+robolectric.version=4.0.1
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl
index 65c6551d..71a2445 100644
--- a/tools/determinism/deterministic_build_whitelist.pyl
+++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -21,25 +21,6 @@
   'linux': [
     # https://crbug.com/908463
     'fontconfig_caches/df1acc8c-39d5-4a8b-8507-b1a7396ac3ac-le64.cache-7',
-
-    # https://crbug.com/918882
-    'nacl_helper_bootstrap',
-
-    # nacl stuff, https://crbug.com/429358
-    'nacl_helper_nonsfi',
-    'nacl_helper_nonsfi_unittests_main',
-    'nacl_test_data/nonsfi/irt_exception_test_pnacl_newlib_x32_nonsfi.nexe',
-    'nacl_test_data/nonsfi/irt_manifest_file_pnacl_newlib_x32_nonsfi.nexe',
-    'ppapi_nacl_tests_pnacl_newlib_x32_nonsfi.nexe',
-    'test_data/ppapi/tests/extensions/packaged_app/nonsfi/ppapi_tests_extensions_packaged_app_pnacl_newlib_x32_nonsfi.nexe',
-
-    # https://crbug.com/932387
-    'performance_browser_tests',
-  ],
-
-  'linux_component': [
-    # https://crbug.com/900696
-    'remoting-webapp.v2.zip',
   ],
 
   # https://crbug.com/330262
@@ -189,15 +170,5 @@
     # them probably should use build_utils.ZipDir() instead.
     'mini_installer_tests.zip',
     'policy_templates.zip',
-
-    # These two started being non-deterministic days 2 out of 3 builds days
-    # after we switched to using two distinct build dirs, for no apparent
-    # reason.
-    'nacl_irt_x86_32.nexe',
-    'nacl_irt_x86_32.nexe.debug',
-
-    # https://crbug.com/932387
-    'performance_browser_tests.exe',
-    'performance_browser_tests.exe.pdb',
   ],
 }
diff --git a/tools/json_schema_compiler/test/test_util.cc b/tools/json_schema_compiler/test/test_util.cc
index fd22ae6..a88184ba 100644
--- a/tools/json_schema_compiler/test/test_util.cc
+++ b/tools/json_schema_compiler/test/test_util.cc
@@ -16,8 +16,9 @@
 std::unique_ptr<base::Value> ReadJson(const base::StringPiece& json) {
   int error_code;
   std::string error_msg;
-  std::unique_ptr<base::Value> result(base::JSONReader::ReadAndReturnError(
-      json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code, &error_msg));
+  std::unique_ptr<base::Value> result(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code, &error_msg));
   // CHECK not ASSERT since passing invalid |json| is a test error.
   CHECK(result) << error_msg;
   return result;
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index f45384a..64d0845 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -783,9 +783,12 @@
       isolate_targets = set(contents.splitlines())
 
       isolate_map = self.ReadIsolateMap()
+      self.RemovePossiblyStaleRuntimeDepsFiles(vals, isolate_targets,
+                                               isolate_map, build_dir)
+
       err, labels = self.MapTargetsToLabels(isolate_map, isolate_targets)
       if err:
-          raise MBErr(err)
+        raise MBErr(err)
 
       gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
       self.WriteFile(gn_runtime_deps_path, '\n'.join(labels) + '\n')
@@ -793,14 +796,13 @@
 
     ret, _, _ = self.Run(cmd)
     if ret:
-        # If `gn gen` failed, we should exit early rather than trying to
-        # generate isolates. Run() will have already logged any error output.
-        self.Print('GN gen failed: %d' % ret)
-        return ret
+      # If `gn gen` failed, we should exit early rather than trying to
+      # generate isolates. Run() will have already logged any error output.
+      self.Print('GN gen failed: %d' % ret)
+      return ret
 
     if getattr(self.args, 'swarming_targets_file', None):
-      return self.GenerateIsolates(vals, isolate_targets, isolate_map,
-                                   build_dir)
+      self.GenerateIsolates(vals, isolate_targets, isolate_map, build_dir)
 
     return 0
 
@@ -844,7 +846,9 @@
         isolate_targets.append(isolate_dict_map[target]['isolate_key'])
         runtime_deps.append(target)
 
-    # Now we need to run "gn gen" again with --runtime-deps-list-file
+    self.RemovePossiblyStaleRuntimeDepsFiles(vals, isolate_targets,
+                                             isolate_map, build_dir)
+
     gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
     self.WriteFile(gn_runtime_deps_path, '\n'.join(runtime_deps) + '\n')
     cmd = self.GNCmd('gen', build_dir)
@@ -853,6 +857,35 @@
 
     return self.GenerateIsolates(vals, isolate_targets, isolate_map, build_dir)
 
+  def RemovePossiblyStaleRuntimeDepsFiles(self, vals, targets, isolate_map,
+                                          build_dir):
+    # TODO(crbug.com/932700): Because `gn gen --runtime-deps-list-file`
+    # puts the runtime_deps file in different locations based on the actual
+    # type of a target, we may end up with multiple possible runtime_deps
+    # files in a given build directory, where some of the entries might be
+    # stale (since we might be reusing an existing build directory).
+    #
+    # We need to be able to get the right one reliably; you might think
+    # we can just pick the newest file, but because GN won't update timestamps
+    # if the contents of the files change, an older runtime_deps
+    # file might actually be the one we should use over a newer one (see
+    # crbug.com/932387 for a more complete explanation and example).
+    #
+    # In order to avoid this, we need to delete any possible runtime_deps
+    # files *prior* to running GN. As long as the files aren't actually
+    # needed during the build, this hopefully will not cause unnecessary
+    # build work, and so it should be safe.
+    #
+    # Ultimately, we should just make sure we get the runtime_deps files
+    # in predictable locations so we don't have this issue at all, and
+    # that's what crbug.com/932700 is for.
+    possible_rpaths = self.PossibleRuntimeDepsPaths(vals, targets, isolate_map)
+    for rpaths in possible_rpaths.values():
+      for rpath in rpaths:
+        path = self.ToAbsPath(build_dir, rpath)
+        if self.Exists(path):
+          self.RemoveFile(path)
+
   def GenerateIsolates(self, vals, ninja_targets, isolate_map, build_dir):
     """
     Generates isolates for a list of ninja targets.
@@ -862,9 +895,50 @@
     This function assumes that a previous invocation of "mb.py gen" has
     generated runtime deps for all targets.
     """
+    possible_rpaths = self.PossibleRuntimeDepsPaths(vals, ninja_targets,
+                                                    isolate_map)
+
+    for target, rpaths in possible_rpaths.items():
+      # TODO(crbug.com/932700): We don't know where each .runtime_deps
+      # file might be, but assuming we called
+      # RemovePossiblyStaleRuntimeDepsFiles prior to calling `gn gen`,
+      # there should only be one file.
+      found_one = False
+      path_to_use = None
+      for r in rpaths:
+        path = self.ToAbsPath(build_dir, r)
+        if self.Exists(path):
+          if found_one:
+            raise MBErr('Found more than one of %s' % ', '.join(rpaths))
+          path_to_use = path
+          found_one = True
+
+      if not found_one:
+        raise MBErr('Did not find any of %s' % ', '.join(rpaths))
+
+      command, extra_files = self.GetIsolateCommand(target, vals)
+      runtime_deps = self.ReadFile(path_to_use).splitlines()
+
+      canonical_target = target.replace(':','_').replace('/','_')
+      self.WriteIsolateFiles(build_dir, command, canonical_target, runtime_deps,
+                             extra_files)
+
+  def PossibleRuntimeDepsPaths(self, vals, ninja_targets, isolate_map):
+    """Returns a map of targets to possible .runtime_deps paths.
+
+    Each ninja target maps on to a GN label, but depending on the type
+    of the GN target, `gn gen --runtime-deps-list-file` will write
+    the .runtime_deps files into different locations. Unfortunately, in
+    some cases we don't actually know which of multiple locations will
+    actually be used, so we return all plausible candidates.
+
+    The paths that are returned are relative to the build directory.
+    """
+
     android = 'target_os="android"' in vals['gn_args']
     fuchsia = 'target_os="fuchsia"' in vals['gn_args']
     win = self.platform == 'win32' or 'target_os="win"' in vals['gn_args']
+    possible_runtime_deps_rpaths = {}
     for target in ninja_targets:
       # TODO(https://crbug.com/876065): 'official_tests' use
       # type='additional_compile_target' to isolate tests. This is not the
@@ -873,22 +947,20 @@
           target != 'official_tests'):
         # By definition, additional_compile_targets are not tests, so we
         # shouldn't generate isolates for them.
-        self.Print('Cannot generate isolate for %s since it is an '
-                   'additional_compile_target.' % target)
-        return 1
+        raise MBErr('Cannot generate isolate for %s since it is an '
+                    'additional_compile_target.' % target)
       elif android:
         # Android targets may be either android_apk or executable. The former
         # will result in runtime_deps associated with the stamp file, while the
         # latter will result in runtime_deps associated with the executable.
         label = isolate_map[target]['label']
-        runtime_deps_targets = [
+        rpaths = [
             target + '.runtime_deps',
             'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
       elif fuchsia:
         # Only emit a runtime deps file for the group() target on Fuchsia.
         label = isolate_map[target]['label']
-        runtime_deps_targets = [
-          'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
+        rpaths = ['obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
       elif (isolate_map[target]['type'] == 'script' or
             isolate_map[target]['type'] == 'fuzzer' or
             isolate_map[target].get('label_type') == 'group'):
@@ -897,33 +969,19 @@
         # for the label, which lives under the obj/ directory, but it may
         # also be an executable.
         label = isolate_map[target]['label']
-        runtime_deps_targets = [
-            'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
+        rpaths = ['obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
         if win:
-          runtime_deps_targets += [ target + '.exe.runtime_deps' ]
+          rpaths += [ target + '.exe.runtime_deps' ]
         else:
-          runtime_deps_targets += [ target + '.runtime_deps' ]
+          rpaths += [ target + '.runtime_deps' ]
       elif win:
-        runtime_deps_targets = [target + '.exe.runtime_deps']
+        rpaths = [target + '.exe.runtime_deps']
       else:
-        runtime_deps_targets = [target + '.runtime_deps']
+        rpaths = [target + '.runtime_deps']
 
-      for r in runtime_deps_targets:
-        runtime_deps_path = self.ToAbsPath(build_dir, r)
-        if self.Exists(runtime_deps_path):
-          break
-      else:
-        raise MBErr('did not generate any of %s' %
-                    ', '.join(runtime_deps_targets))
+      possible_runtime_deps_rpaths[target] = rpaths
 
-      command, extra_files = self.GetIsolateCommand(target, vals)
-      runtime_deps = self.ReadFile(runtime_deps_path).splitlines()
-
-      canonical_target = target.replace(':','_').replace('/','_')
-      self.WriteIsolateFiles(build_dir, command, canonical_target, runtime_deps,
-                             extra_files)
-
-    return 0
+    return possible_runtime_deps_rpaths
 
   def RunGNIsolate(self, vals):
     target = self.args.target
@@ -931,6 +989,7 @@
     err, labels = self.MapTargetsToLabels(isolate_map, [target])
     if err:
       raise MBErr(err)
+
     label = labels[0]
 
     build_dir = self.args.path
diff --git a/tools/mb/mb_unittest.py b/tools/mb/mb_unittest.py
index df1c518..265ad4967 100755
--- a/tools/mb/mb_unittest.py
+++ b/tools/mb/mb_unittest.py
@@ -7,6 +7,7 @@
 
 import json
 import os
+import re
 import StringIO
 import sys
 import unittest
@@ -27,6 +28,7 @@
       self.platform = 'win32'
       self.executable = 'c:\\python\\python.exe'
       self.sep = '\\'
+      self.cwd = 'c:\\fake_src\\out\\Default'
     else:
       self.chromium_src_dir = '/fake_src'
       self.default_config = '/fake_src/tools/mb/mb_config.pyl'
@@ -34,6 +36,7 @@
       self.executable = '/usr/bin/python'
       self.platform = 'linux2'
       self.sep = '/'
+      self.cwd = '/fake_src/out/Default'
 
     self.files = {}
     self.calls = []
@@ -47,21 +50,23 @@
     return '$HOME/%s' % path
 
   def Exists(self, path):
-    return self.files.get(path) is not None
+    return self.files.get(self._AbsPath(path)) is not None
 
   def MaybeMakeDirectory(self, path):
-    self.files[path] = True
+    abpath = self._AbsPath(path)
+    self.files[abpath] = True
 
   def PathJoin(self, *comps):
     return self.sep.join(comps)
 
   def ReadFile(self, path):
-    return self.files[path]
+    return self.files[self._AbsPath(path)]
 
   def WriteFile(self, path, contents, force_verbose=False):
     if self.args.dryrun or self.args.verbose or force_verbose:
       self.Print('\nWriting """\\\n%s""" to %s.\n' % (contents, path))
-    self.files[path] = contents
+    abpath = self._AbsPath(path)
+    self.files[abpath] = contents
 
   def Call(self, cmd, env=None, buffer_output=True):
     self.calls.append(cmd)
@@ -82,14 +87,25 @@
     return FakeFile(self.files)
 
   def RemoveFile(self, path):
-    del self.files[path]
+    abpath = self._AbsPath(path)
+    self.files[abpath] = None
 
   def RemoveDirectory(self, path):
-    self.rmdirs.append(path)
-    files_to_delete = [f for f in self.files if f.startswith(path)]
+    abpath = self._AbsPath(path)
+    self.rmdirs.append(abpath)
+    files_to_delete = [f for f in self.files if f.startswith(abpath)]
     for f in files_to_delete:
       self.files[f] = None
 
+  def _AbsPath(self, path):
+    if not ((self.platform == 'win32' and path.startswith('c:')) or
+            (self.platform != 'win32' and path.startswith('/'))):
+      path = self.PathJoin(self.cwd, path)
+    if self.sep == '\\':
+      return re.sub(r'\\+', r'\\', path)
+    else:
+      return re.sub('/+', '/', path)
+
 
 class FakeFile(object):
   def __init__(self, files):
@@ -402,11 +418,20 @@
           "  'args': [],"
           "}}\n"
       ),
-      '/fake_src/out/Default/base_unittests.runtime_deps': (
-          "base_unittests\n"
-      ),
     }
+
     mbw = self.fake_mbw(files)
+
+    def fake_call(cmd, env=None, buffer_output=True):
+      del cmd
+      del env
+      del buffer_output
+      mbw.files['/fake_src/out/Default/base_unittests.runtime_deps'] = (
+          'base_unittests\n')
+      return 0, '', ''
+
+    mbw.Call = fake_call
+
     self.check(['gen',
                 '-c', 'debug_goma',
                 '--swarming-targets-file', '/tmp/swarming_targets',
@@ -427,20 +452,28 @@
           "  'args': [],"
           "}}\n"
       ),
-      'c:\\fake_src\out\Default\cc_perftests.exe.runtime_deps': (
-          "cc_perftests\n"
-      ),
     }
-    mbw = self.fake_mbw(files=files, win32=True)
+    mbw = self.fake_mbw(files=files)
+
+    def fake_call(cmd, env=None, buffer_output=True):
+      del cmd
+      del env
+      del buffer_output
+      mbw.files['/fake_src/out/Default/cc_perftests.runtime_deps'] = (
+          'cc_perftests\n')
+      return 0, '', ''
+
+    mbw.Call = fake_call
+
     self.check(['gen',
                 '-c', 'debug_goma',
                 '--swarming-targets-file', '/tmp/swarming_targets',
                 '--isolate-map-file',
                 '/fake_src/testing/buildbot/gn_isolate_map.pyl',
                 '//out/Default'], mbw=mbw, ret=0)
-    self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolate',
+    self.assertIn('/fake_src/out/Default/cc_perftests.isolate',
                   mbw.files)
-    self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolated.gen.json',
+    self.assertIn('/fake_src/out/Default/cc_perftests.isolated.gen.json',
                   mbw.files)
 
   def test_gen_fuzzer(self):
@@ -452,21 +485,30 @@
           "  'type': 'fuzzer',"
           "}}\n"
       ),
-      'c:\\fake_src\out\Default\cc_perftests_fuzzer.exe.runtime_deps': (
-          "cc_perftests_fuzzer\n"
-      ),
     }
-    mbw = self.fake_mbw(files=files, win32=True)
+
+    mbw = self.fake_mbw(files=files)
+
+    def fake_call(cmd, env=None, buffer_output=True):
+      del cmd
+      del env
+      del buffer_output
+      mbw.files['/fake_src/out/Default/cc_perftests_fuzzer.runtime_deps'] = (
+          'cc_perftests_fuzzer\n')
+      return 0, '', ''
+
+    mbw.Call = fake_call
+
     self.check(['gen',
                 '-c', 'debug_goma',
                 '--swarming-targets-file', '/tmp/swarming_targets',
                 '--isolate-map-file',
                 '/fake_src/testing/buildbot/gn_isolate_map.pyl',
                 '//out/Default'], mbw=mbw, ret=0)
-    self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests_fuzzer.isolate',
+    self.assertIn('/fake_src/out/Default/cc_perftests_fuzzer.isolate',
                   mbw.files)
     self.assertIn(
-        'c:\\fake_src\\out\\Default\\cc_perftests_fuzzer.isolated.gen.json',
+        '/fake_src/out/Default/cc_perftests_fuzzer.isolated.gen.json',
         mbw.files)
 
   def test_multiple_isolate_maps(self):
@@ -486,11 +528,19 @@
           "  'args': [],"
           "}}\n"
       ),
-      'c:\\fake_src\out\Default\cc_perftests.exe.runtime_deps': (
-          "cc_perftests\n"
-      ),
     }
-    mbw = self.fake_mbw(files=files, win32=True)
+    mbw = self.fake_mbw(files=files)
+
+    def fake_call(cmd, env=None, buffer_output=True):
+      del cmd
+      del env
+      del buffer_output
+      mbw.files['/fake_src/out/Default/cc_perftests.runtime_deps'] = (
+          'cc_perftests_fuzzer\n')
+      return 0, '', ''
+
+    mbw.Call = fake_call
+
     self.check(['gen',
                 '-c', 'debug_goma',
                 '--swarming-targets-file', '/tmp/swarming_targets',
@@ -499,9 +549,9 @@
                 '--isolate-map-file',
                 '/fake_src/testing/buildbot/gn_isolate_map2.pyl',
                 '//out/Default'], mbw=mbw, ret=0)
-    self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolate',
+    self.assertIn('/fake_src/out/Default/cc_perftests.isolate',
                   mbw.files)
-    self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolated.gen.json',
+    self.assertIn('/fake_src/out/Default/cc_perftests.isolated.gen.json',
                   mbw.files)
 
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e375c783..9e1c420 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -5023,6 +5023,11 @@
   <int value="1" label="inappropriate_fallback alert"/>
 </enum>
 
+<enum name="BooleanIncludesHash">
+  <int value="0" label="Hash Missing"/>
+  <int value="1" label="Hash Included"/>
+</enum>
+
 <enum name="BooleanIncognito">
   <int value="0" label="Not Incognito"/>
   <int value="1" label="Incognito"/>
@@ -15436,7 +15441,7 @@
   <int value="517" label="BrowserSwitcherEnabled"/>
   <int value="518" label="CertificateManagementAllowed"/>
   <int value="519" label="BrowserSwitcherKeepLastChromeTab"/>
-  <int value="520" label="DeviceRebootAfterArcSession"/>
+  <int value="520" label="DeviceRebootOnUserSignout"/>
   <int value="521" label="ForceNetworkInProcess"/>
   <int value="522" label="SchedulerConfiguration"/>
   <int value="523" label="CrostiniExportImportUIAllowed"/>
@@ -32089,6 +32094,7 @@
   <int value="292560715" label="ViewsCastDialog:disabled"/>
   <int value="293134455" label="AutofillSendBillingCustomerNumber:disabled"/>
   <int value="293996306" label="ArrayPrototypeValues:disabled"/>
+  <int value="296215399" label="WindowsMixedReality:disabled"/>
   <int value="300095239" label="FCMInvalidations:enabled"/>
   <int value="301869874" label="NTPPhysicalWebPageSuggestions:disabled"/>
   <int value="303058039" label="AccountConsistency:disabled"/>
@@ -32153,6 +32159,7 @@
   <int value="386138870" label="DesktopPWAsOmniboxInstall:enabled"/>
   <int value="387178525" label="VideoFullscreenOrientationLock:enabled"/>
   <int value="387233614" label="HomePageButtonForceEnabled:disabled"/>
+  <int value="388328387" label="WindowsMixedReality:enabled"/>
   <int value="388786873" label="EnableUnifiedMultiDeviceSettings:enabled"/>
   <int value="388996324" label="CustomContextMenu:disabled"/>
   <int value="392782890" label="SafeBrowsingTelemetryForApkDownloads:enabled"/>
@@ -40393,6 +40400,7 @@
   <int value="3" label="NSTemporaryDirectory"/>
   <int value="4" label="TMPDIR"/>
   <int value="5" label="/tmp"/>
+  <int value="6" label="/tmp, different volume"/>
 </enum>
 
 <enum name="OtherPossibleUsernamesUsage">
@@ -48570,6 +48578,9 @@
   <int value="10" label="CT verification error"/>
   <int value="11" label="OCSP error"/>
   <int value="12" label="Certificate requirements not met"/>
+  <int value="13"
+      label="No &quot;X-Content-Type-Options: nosniff&quot; header"/>
+  <int value="14" label="Merkle integrity error"/>
 </enum>
 
 <enum name="SignedExchangeSignatureVerificationResult">
@@ -51790,6 +51801,7 @@
   <int value="3" label="Download page paused"/>
   <int value="4" label="Download page resumed"/>
   <int value="5" label="Download page canceled"/>
+  <int value="6" label="Content suggestion settings"/>
 </enum>
 
 <enum name="SystemNotificationType">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 9b2da27..5bda9a6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -19313,6 +19313,14 @@
   </summary>
 </histogram>
 
+<histogram name="CryptohomeClient" units="ms" expires_after="2020-01-01">
+  <owner>menghuan@chromium.org</owner>
+  <summary>
+    Records the time duration of every dbus outgoing calls issued from the
+    client of Crypthome in Chrome side.
+  </summary>
+</histogram>
+
 <histogram base="true" name="CustomTab.SessionDuration" units="ms">
   <owner>ranj@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -25955,6 +25963,16 @@
   </summary>
 </histogram>
 
+<histogram name="Download.Service.Finish.ReportedHash"
+    enum="BooleanIncludesHash" expires_after="2019-10-01">
+  <owner>dtrainor@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <summary>
+    Records if a completed download service entry was sent to a client with a
+    hash or not.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Download.Service.Finish.Time" units="ms">
 <!-- Name completed by histogram_suffixes
      name="Download.Service.CompletionType" -->
@@ -32004,7 +32022,10 @@
 </histogram>
 
 <histogram name="ExtensionInstalledLoader.ForceDisabled2"
-    enum="BooleanForceDisabled" expires_after="2018-08-30">
+    enum="BooleanForceDisabled">
+  <obsolete>
+    Expired 2018-08-30
+  </obsolete>
   <owner>rdevlin.cronin@chromium.org</owner>
   <summary>
     Counts whether we force-disabled an installed extension at startup because
@@ -76651,14 +76672,27 @@
   </summary>
 </histogram>
 
-<histogram name="OSX.StagingDirectoryLocation" enum="OSXStagingDirectoryStep"
-    expires_after="2019-12-31">
+<histogram name="OSX.StagingDirectoryLocation" enum="OSXStagingDirectoryStep">
+  <obsolete>
+    Deprecated as of 02/2019 in favor of StagingDirectoryLocation2.
+  </obsolete>
   <owner>avi@chromium.org</owner>
   <owner>rsesek@chromium.org</owner>
   <owner>mark@chromium.org</owner>
   <summary>Records first staging directory location that works.</summary>
 </histogram>
 
+<histogram name="OSX.StagingDirectoryLocation2" enum="OSXStagingDirectoryStep"
+    expires_after="2019-12-31">
+  <owner>avi@chromium.org</owner>
+  <owner>rsesek@chromium.org</owner>
+  <owner>mark@chromium.org</owner>
+  <summary>
+    Records, during Chrome startup, the first staging directory location that
+    works. This is for the change to the updating system.
+  </summary>
+</histogram>
+
 <histogram name="OSX.SystemHotkeyMap.LoadSuccess" enum="BooleanSuccess"
     expires_after="2018-08-30">
   <owner>erikchen@chromium.org</owner>
@@ -107284,6 +107318,20 @@
 
 <histogram name="SignedExchange.LoadResult" enum="SignedExchangeLoadResult"
     expires_after="2019-09-20">
+  <obsolete>
+    Removed 2/2019 in favor of SignedExchange.LoadResult2.
+  </obsolete>
+  <owner>kinuko@chromium.org</owner>
+  <owner>kouhei@chromium.org</owner>
+  <owner>ksakamoto@chromium.org</owner>
+  <summary>
+    Records the result of loading a resource from Signed HTTP Exchange. Emitted
+    each time a response is handled as Signed Exchange.
+  </summary>
+</histogram>
+
+<histogram name="SignedExchange.LoadResult2" enum="SignedExchangeLoadResult"
+    expires_after="2019-09-20">
   <owner>kinuko@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
   <owner>ksakamoto@chromium.org</owner>
@@ -107318,6 +107366,19 @@
 
 <histogram name="SignedExchange.Prefetch.LoadResult"
     enum="SignedExchangeLoadResult" expires_after="2019-10-11">
+  <obsolete>
+    Removed 2/2019 in favor of SignedExchange.Prefetch.LoadResult2.
+  </obsolete>
+  <owner>kinuko@chromium.org</owner>
+  <owner>kouhei@chromium.org</owner>
+  <summary>
+    Records if the prefetched Signed Exchange was properly formatted and passed
+    verification steps. Reported for each completed SignedExchange prefetch.
+  </summary>
+</histogram>
+
+<histogram name="SignedExchange.Prefetch.LoadResult2"
+    enum="SignedExchangeLoadResult" expires_after="2019-10-11">
   <owner>kinuko@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
   <summary>
@@ -134431,6 +134492,97 @@
   <affected-histogram name="CrosFirstRun.TimeSpentOnStep"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="CryptohomeClientDBusMethod" separator=".">
+  <suffix name="AddKeyEx"/>
+  <suffix name="AsyncDoesUsersExist"/>
+  <suffix name="AsyncMigrateKey"/>
+  <suffix name="AsyncMount"/>
+  <suffix name="AsyncMountGuest"/>
+  <suffix name="AsyncRemove"/>
+  <suffix name="AsyncRemoveTrackedSubdirectories"/>
+  <suffix name="AsyncTpmAttestationCreateCertRequest"/>
+  <suffix name="AsyncTpmAttestationCreateCertRequestByProfile"/>
+  <suffix name="AsyncTpmAttestationCreateEnrollRequest"/>
+  <suffix name="AsyncTpmAttestationCreateEnrollRequestNew"/>
+  <suffix name="AsyncTpmAttestationEnroll"/>
+  <suffix name="AsyncTpmAttestationEnrollNew"/>
+  <suffix name="AsyncTpmAttestationFinishCertRequest"/>
+  <suffix name="CheckKeyEx"/>
+  <suffix name="FinalizeBootLockbox"/>
+  <suffix name="FlushAndSignBootAttributes"/>
+  <suffix name="GetAccountDiskUsage"/>
+  <suffix name="GetBootAttribute"/>
+  <suffix name="GetCurrentSpaceForGid"/>
+  <suffix name="GetCurrentSpaceForUid"/>
+  <suffix name="GetEndorsementInfo"/>
+  <suffix name="GetFirmwareManagementParameters"/>
+  <suffix name="GetKeyDataEx"/>
+  <suffix name="GetLoginStatus"/>
+  <suffix name="GetSanitizedUsername"/>
+  <suffix name="GetStatusString"/>
+  <suffix name="GetSupportedKeyPolicies"/>
+  <suffix name="GetSystemSalt"/>
+  <suffix name="GetTpmStatus"/>
+  <suffix name="InstallAttributesCount"/>
+  <suffix name="InstallAttributesFinalize"/>
+  <suffix name="InstallAttributesGet"/>
+  <suffix name="InstallAttributesIsFirstInstall"/>
+  <suffix name="InstallAttributesIsInvalid"/>
+  <suffix name="InstallAttributesIsReady"/>
+  <suffix name="InstallAttributesIsSecure"/>
+  <suffix name="InstallAttributesSet"/>
+  <suffix name="IsMounted"/>
+  <suffix name="IsQuotaSupported"/>
+  <suffix name="MigrateKey"/>
+  <suffix name="MigrateKeyEx"/>
+  <suffix name="MigrateToDircrypto"/>
+  <suffix name="Mount"/>
+  <suffix name="MountEx"/>
+  <suffix name="MountGuest"/>
+  <suffix name="MountGuestEx"/>
+  <suffix name="NeedsDircryptoMigration"/>
+  <suffix name="Pkcs11GetTpmTokenInfo"/>
+  <suffix name="Pkcs11GetTpmTokenInfoForUser"/>
+  <suffix name="Pkcs11IsTpmTokenReady"/>
+  <suffix name="RemoveEx"/>
+  <suffix name="RemoveFirmwareManagementParameters"/>
+  <suffix name="RemoveKeyEx"/>
+  <suffix name="RemoveTrackedSubdirectories"/>
+  <suffix name="RenameCryptohome"/>
+  <suffix name="SetBootAttribute"/>
+  <suffix name="SetFirmwareManagementParameters"/>
+  <suffix name="SignBootLockbox"/>
+  <suffix name="TpmAttestationCreateCertRequest"/>
+  <suffix name="TpmAttestationCreateEnrollRequest"/>
+  <suffix name="TpmAttestationDeleteKeys"/>
+  <suffix name="TpmAttestationDoesKeyExist"/>
+  <suffix name="TpmAttestationEnroll"/>
+  <suffix name="TpmAttestationFinishCertRequest"/>
+  <suffix name="TpmAttestationGetCertificate"/>
+  <suffix name="TpmAttestationGetEnrollmentId"/>
+  <suffix name="TpmAttestationGetKeyPayload"/>
+  <suffix name="TpmAttestationGetPublicKey"/>
+  <suffix name="TpmAttestationRegisterKey"/>
+  <suffix name="TpmAttestationSetKeyPayload"/>
+  <suffix name="TpmAttestationSignEnterpriseChallenge"/>
+  <suffix name="TpmAttestationSignEnterpriseVaChallenge"/>
+  <suffix name="TpmAttestationSignSimpleChallenge"/>
+  <suffix name="TpmCanAttemptOwnership"/>
+  <suffix name="TpmClearStoredPassword"/>
+  <suffix name="TpmGetPassword"/>
+  <suffix name="TpmGetVersionStructured"/>
+  <suffix name="TpmIsAttestationEnrolled"/>
+  <suffix name="TpmIsAttestationPrepared"/>
+  <suffix name="TpmIsBeingOwned"/>
+  <suffix name="TpmIsEnabled"/>
+  <suffix name="TpmIsOwned"/>
+  <suffix name="TpmIsReady"/>
+  <suffix name="Unmount"/>
+  <suffix name="UpdateKeyEx"/>
+  <suffix name="VerifyBootLockbox"/>
+  <affected-histogram name="CryptohomeClient"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="CurrentTabState" separator="_">
   <suffix name="Active"
       label="For an active tab which is shown foreground in a browser window."/>
@@ -137000,7 +137152,6 @@
   <suffix name="IPH_IncognitoWindow" label="In product help incognito window."/>
   <suffix name="IPH_LongPressToolbarTip"
       label="In product help LongPress toolbar."/>
-  <suffix name="IPH_MediaDownload" label="In product help media download."/>
   <suffix name="IPH_NewIncognitoTabTip"
       label="In product help new incognito tab tip."/>
   <suffix name="IPH_NewTab" label="In product help new tab."/>
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py
index 4cf61ab5..c4af48d 100644
--- a/tools/perf/benchmarks/memory.py
+++ b/tools/perf/benchmarks/memory.py
@@ -52,7 +52,7 @@
   # has anomalous results. This option causes us to flush caches
   # each time before Chrome starts so we effect even the first page
   # - avoiding the bug.
-  options.clear_sytem_cache_for_browser_and_profile_on_start = True
+  options.flush_os_page_caches_on_start = True
 
 
 def DefaultShouldAddValueForMemoryMeasurement(name):
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index fac4bb0..4a5fcf8 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -155,7 +155,7 @@
     # has anomalous results. This option causes us to flush caches
     # each time before Chrome starts so we effect even the first story
     # - avoiding the bug.
-    options.clear_sytem_cache_for_browser_and_profile_on_start = True
+    options.flush_os_page_caches_on_start = True
 
   @classmethod
   def Name(cls):
diff --git a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
index 2816d42d..00e6916 100644
--- a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
+++ b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
@@ -66,11 +66,13 @@
     self._PerformAndroidVrSetup()
 
   def _PerformAndroidVrSetup(self):
-    self._InstallVrCore()
+    if not self._finder_options.disable_vrcore_install:
+      self._InstallVrCore()
     self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(),
                                        self._finder_options.shared_prefs_file))
     self._InstallNfcApk()
-    self._InstallKeyboardApk()
+    if not self._finder_options.disable_keyboard_install:
+      self._InstallKeyboardApk()
 
   def _InstallVrCore(self):
     """Installs the VrCore APK."""
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
index cff63084..b212fdf 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
@@ -37,6 +37,21 @@
         'screen leads to locking the phone, which makes Telemetry '
         'not produce valid results.')
     parser.add_option(
+        '--disable-vrcore-install',
+        action='store_true',
+        default=False,
+        help='Disables the automatic installation of VrCore during pre-test '
+             'setup. This is useful for local testing on Pixel devices that '
+             'haven\'t had VrCore removed as a system app.')
+    parser.add_option(
+        '--disable-keyboard-install',
+        action='store_true',
+        default=False,
+        help='Disables the automatic installation of the VR keybaord during '
+             'pre-test setup. This is useful for local testing if you want '
+             'to use whatever version is already installed on the device '
+             'instead of installing whatever is in the test APKs directory.')
+    parser.add_option(
         '--recording-wpr',
         action='store_true',
         default=False,
@@ -173,7 +188,7 @@
     return options
 
   def SetExtraBrowserOptions(self, options):
-    options.clear_sytem_cache_for_browser_and_profile_on_start = True
+    options.flush_os_page_caches_on_start = True
     options.AppendExtraBrowserArgs([
         '--enable-gpu-benchmarking',
         '--touch-events=enabled',
diff --git a/tools/perf/scripts_smoke_unittest.py b/tools/perf/scripts_smoke_unittest.py
index 824a71b..f776538c 100644
--- a/tools/perf/scripts_smoke_unittest.py
+++ b/tools/perf/scripts_smoke_unittest.py
@@ -13,16 +13,22 @@
 from telemetry import decorators
 from telemetry.testing import options_for_unittests
 
+RUNNER_SCRIPTS_DIR = os.path.join(os.path.dirname(__file__),
+                                  '..', '..', 'testing', 'scripts')
+sys.path.append(RUNNER_SCRIPTS_DIR)
+import run_performance_tests  # pylint: disable=wrong-import-position,import-error
+
 
 class ScriptsSmokeTest(unittest.TestCase):
 
   perf_dir = os.path.dirname(__file__)
 
-  def RunPerfScript(self, command):
+  def RunPerfScript(self, command, env=None):
     main_command = [sys.executable]
     args = main_command + command.split(' ')
     proc = subprocess.Popen(args, stdout=subprocess.PIPE,
-                            stderr=subprocess.STDOUT, cwd=self.perf_dir)
+                            stderr=subprocess.STDOUT, cwd=self.perf_dir,
+                            env=env)
     stdout = proc.communicate()[0]
     return_code = proc.returncode
     return return_code, stdout
@@ -59,7 +65,7 @@
     self.assertIn('kraken', stdout)
 
   @decorators.Disabled('chromeos')  # crbug.com/754913
-  def testRunTelemetryBenchmarkAsGoogletest(self):
+  def testRunPerformanceTestsTelemetry_end2end(self):
     options = options_for_unittests.GetCopy()
     browser_type = options.browser_type
     tempdir = tempfile.mkdtemp()
@@ -88,7 +94,140 @@
         test_repeats = test_results['num_failures_by_type']['PASS']
         self.assertEqual(
             test_repeats, 2, '--isolated-script-test-repeat=2 should work.')
+      with open(os.path.join(tempdir, benchmark, 'perf_results.json')) as f:
+        perf_results = json.load(f)
+        self.assertIsNotNone(
+            perf_results, 'json perf results should be populated: ' + stdout)
     except IOError as e:
       self.fail('json_test_results should be populated: ' + stdout + str(e))
     finally:
       shutil.rmtree(tempdir)
+
+  # Android: crbug.com/932301
+  # ChromeOS: crbug.com/754913
+  @decorators.Disabled('chromeos', 'android')
+  def testRunPerformanceTestsTelemetrySharded_end2end(self):
+    options = options_for_unittests.GetCopy()
+    browser_type = options.browser_type
+    tempdir = tempfile.mkdtemp()
+    env = os.environ.copy()
+    env['GTEST_SHARD_INDEX'] = '0'
+    env['GTEST_TOTAL_SHARDS'] = '2'
+    return_code, stdout = self.RunPerfScript(
+        '../../testing/scripts/run_performance_tests.py '
+        '../../tools/perf/run_benchmark '
+        '--test-shard-map-filename=smoke_test_benchmark_shard_map.json '
+        '--browser=%s '
+        '--run-ref-build '
+        '--isolated-script-test-repeat=2 '
+        '--isolated-script-test-also-run-disabled-tests '
+        '--isolated-script-test-output=%s' % (
+            browser_type,
+            os.path.join(tempdir, 'output.json')
+        ), env=env)
+    self.assertEquals(return_code, 0, stdout)
+    try:
+      expected_benchmark_folders = (
+          'dummy_benchmark.stable_benchmark_1',
+          'dummy_benchmark.stable_benchmark_1.reference')
+      for folder in expected_benchmark_folders:
+        with open(os.path.join(tempdir, folder, 'test_results.json')) as f:
+          test_results = json.load(f)
+          self.assertIsNotNone(
+              test_results, 'json test results should be populated: ' + stdout)
+          test_repeats = test_results['num_failures_by_type']['PASS']
+          self.assertEqual(
+              test_repeats, 2, '--isolated-script-test-repeat=2 should work.')
+        with open(os.path.join(tempdir, folder, 'perf_results.json')) as f:
+          perf_results = json.load(f)
+          self.assertIsNotNone(
+              perf_results, 'json perf results should be populated: ' + stdout)
+    except IOError as e:
+      self.fail('IOError: ' + stdout + str(e))
+    except KeyError as e:
+      self.fail('KeyError: ' + stdout + str(e))
+    finally:
+      shutil.rmtree(tempdir)
+
+
+  @decorators.Disabled('win')  # ".exe" is auto-added which breaks Windows.
+  def testRunPerformanceTestsGtest_end2end(self):
+    tempdir = tempfile.mkdtemp()
+    benchmark = 'dummy_gtest'
+    return_code, stdout = self.RunPerfScript(
+        '../../testing/scripts/run_performance_tests.py ' +
+        os.path.join('..', '..', 'tools', 'perf', 'testdata', 'dummy_gtest') +
+        ' --non-telemetry=true '
+        '--this-arg=passthrough '
+        '--gtest-benchmark-name dummy_gtest '
+        '--isolated-script-test-output=/x/y/z/output.json '
+        '--isolated-script-test-output=%s' % (
+            os.path.join(tempdir, 'output.json')
+        ))
+    self.assertEquals(return_code, 0, stdout)
+    try:
+      # By design, run_performance_tests.py does not output test results
+      # to the location passed in by --isolated-script-test-output. Instead
+      # it uses the directory of that file and puts stuff in its own
+      # subdirectories for the purposes of merging later.
+      with open(os.path.join(tempdir, benchmark, 'test_results.json')) as f:
+        test_results = json.load(f)
+        self.assertIsNotNone(
+            test_results, 'json_test_results should be populated: ' + stdout)
+      with open(os.path.join(tempdir, benchmark, 'perf_results.json')) as f:
+        perf_results = json.load(f)
+        self.assertIsNotNone(
+            perf_results, 'json perf results should be populated: ' + stdout)
+    except IOError as e:
+      self.fail('json_test_results should be populated: ' + stdout + str(e))
+    finally:
+      shutil.rmtree(tempdir)
+
+  def testRunPerformanceTestsTelemetryArgsParser(self):
+    options = run_performance_tests.parse_arguments([
+        '../../tools/perf/run_benchmark', '-v', '--browser=release_x64',
+        '--upload-results', '--run-ref-build',
+        '--test-shard-map-filename=win-10-perf_map.json',
+        '--assert-gpu-compositing',
+        r'--isolated-script-test-output=c:\a\b\c\output.json',
+        r'--isolated-script-test-perf-output=c:\a\b\c\perftest-output.json',
+        '--passthrough-arg=--a=b',
+    ])
+    self.assertIn('--assert-gpu-compositing', options.passthrough_args)
+    self.assertIn('--browser=release_x64', options.passthrough_args)
+    self.assertIn('-v', options.passthrough_args)
+    self.assertIn('--a=b', options.passthrough_args)
+    self.assertEqual(options.executable, '../../tools/perf/run_benchmark')
+    self.assertEqual(options.isolated_script_test_output,
+                     r'c:\a\b\c\output.json')
+
+  def testRunPerformanceTestsTelemetryCommandGenerator_ReferenceBrowserComeLast(self):
+    """This tests for crbug.com/928928."""
+    options = run_performance_tests.parse_arguments([
+        '../../tools/perf/run_benchmark', '--browser=release_x64',
+        '--run-ref-build',
+        '--test-shard-map-filename=win-10-perf_map.json',
+        r'--isolated-script-test-output=c:\a\b\c\output.json',
+    ])
+    self.assertIn('--browser=release_x64', options.passthrough_args)
+    command = run_performance_tests.TelemetryCommandGenerator(
+        'fake_benchmark_name', options, is_reference=True).generate(
+            'fake_output_dir')
+    original_browser_arg_index = command.index('--browser=release_x64')
+    reference_browser_arg_index = command.index('--browser=reference')
+    self.assertTrue(reference_browser_arg_index > original_browser_arg_index)
+
+  def testRunPerformanceTestsGtestArgsParser(self):
+     options = run_performance_tests.parse_arguments([
+        'media_perftests', '--non-telemetry=true', '--single-process-tests',
+        '--test-launcher-retry-limit=0',
+        '--isolated-script-test-filter=*::-*_unoptimized::*_unaligned::'
+        '*unoptimized_aligned',
+        '--gtest-benchmark-name', 'media_perftests',
+        '--isolated-script-test-output=/x/y/z/output.json',
+     ])
+     self.assertIn('--single-process-tests', options.passthrough_args)
+     self.assertIn('--test-launcher-retry-limit=0', options.passthrough_args)
+     self.assertEqual(options.executable, 'media_perftests')
+     self.assertEqual(options.isolated_script_test_output,
+                      r'/x/y/z/output.json')
diff --git a/tools/perf/testdata/dummy_gtest b/tools/perf/testdata/dummy_gtest
new file mode 100755
index 0000000..044ed7f
--- /dev/null
+++ b/tools/perf/testdata/dummy_gtest
@@ -0,0 +1,12 @@
+#!/usr/bin/env vpython
+# 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.
+
+"""This is a fake version of a non-Telemetry performance test (gtest_perf_test).
+
+It is used by ../scripts_smoke_unittest.py.
+"""
+
+# This is just a random line of output that can be converted into graph_json.
+print r"*RESULT clockless_video_playback_vp8: bear_silent.webm= 53.406108056578425 runs/s"
diff --git a/tools/vim/chromium.ycm_extra_conf.py b/tools/vim/chromium.ycm_extra_conf.py
index fb9c2b0a..ee0ad67 100644
--- a/tools/vim/chromium.ycm_extra_conf.py
+++ b/tools/vim/chromium.ycm_extra_conf.py
@@ -296,6 +296,13 @@
   # Chromium's includes are relative to that.
   additional_flags = ['-I' + os.path.join(chrome_root)]
 
+  # Fix missing system headers. For details, see
+  # <https://github.com/Valloric/YouCompleteMe/issues/303>
+  clang_root = os.path.join(
+    chrome_root, 'third_party/llvm-build/Release+Asserts')
+  additional_flags += ['-isystem', os.path.join(clang_root, 'include')]
+  additional_flags += ['-isystem', os.path.join(clang_root, 'include/c++/v1')]
+
   # Version of Clang used to compile Chromium can be newer then version of
   # libclang that YCM uses for completion. So it's possible that YCM's libclang
   # doesn't know about some used warning options, which causes compilation
diff --git a/tools/vim/tests/chromium.ycm_extra_conf_unittest.py b/tools/vim/tests/chromium.ycm_extra_conf_unittest.py
index 3662fee..cfecd70 100755
--- a/tools/vim/tests/chromium.ycm_extra_conf_unittest.py
+++ b/tools/vim/tests/chromium.ycm_extra_conf_unittest.py
@@ -20,6 +20,12 @@
 import tempfile
 import unittest
 
+_common_flags = [
+  '-I[SRC]',
+  '-isystem', '[SRC]/third_party/llvm-build/Release+Asserts/include',
+  '-isystem', '[SRC]/third_party/llvm-build/Release+Asserts/include/c++/v1',
+  '-Wno-unknown-warning-option'
+]
 
 def CreateFile(path, copy_from=None, format_with=None, make_executable=False):
   """Creates a file.
@@ -163,9 +169,8 @@
         self.ycm_extra_conf.GetClangOptionsFromNinjaForFilename(
             self.chrome_root, os.path.join(self.chrome_root, 'one.cpp'))
     self.assertEquals(
-        self.NormalizeStringsInList(clang_options), [
-            '-I[SRC]', '-Wno-unknown-warning-option', '-I[OUT]/a',
-            '-I[OUT]/tag-one'
+        self.NormalizeStringsInList(clang_options), _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-one'
         ])
 
   def testOutDirNames(self):
@@ -190,8 +195,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-one'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-one'
         ])
 
   def testGetFlagsForFileForUnknownCppFile(self):
@@ -203,8 +209,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-default'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-default'
         ])
 
   def testGetFlagsForFileForUnknownCppNotTestFile(self):
@@ -216,8 +223,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-default'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-default'
         ])
 
   testGetFlagsForFileForKnownObjcFile = TestLanguage('eight.m', 'objective-c')
@@ -241,8 +249,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-default'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-default'
         ])
 
   def testGetFlagsForFileForUnknownUnittestFile(self):
@@ -254,9 +263,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a',
-            '-I[OUT]/tag-default-test'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-default-test'
         ])
 
   def testGetFlagsForFileForUnknownBrowsertestFile2(self):
@@ -268,9 +277,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a',
-            '-I[OUT]/tag-default-test'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-default-test'
         ])
 
   def testGetFlagsForFileForKnownHeaderFileWithAssociatedCppFile(self):
@@ -282,8 +291,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-three'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-three'
         ])
 
   def testSourceFileWithNonClangOutputs(self):
@@ -309,8 +319,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-four'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-four'
         ])
 
   def testSourceFileWithOnlyNonClangOutputs(self):
@@ -322,8 +333,9 @@
     self.assertTrue('flags' in result)
     self.assertEquals(
         self.NormalizeStringsInList(result['flags']), [
-            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++', '-I[SRC]',
-            '-Wno-unknown-warning-option', '-I[OUT]/a', '-I[OUT]/tag-default'
+            '-DUSE_CLANG_COMPLETER', '-std=c++14', '-x', 'c++'
+        ] + _common_flags + [
+            '-I[OUT]/a', '-I[OUT]/tag-default'
         ])
 
   def testGetFlagsForSysrootAbsPath(self):
@@ -339,8 +351,7 @@
             '-std=c++14',
             '-x',
             'c++',
-            '-I[SRC]',
-            '-Wno-unknown-warning-option',
+        ] + _common_flags + [
             '-I[OUT]/a',
             '--sysroot=/usr/lib/sysroot-image',
             '-isysroot',
@@ -360,8 +371,7 @@
             '-std=c++14',
             '-x',
             'c++',
-            '-I[SRC]',
-            '-Wno-unknown-warning-option',
+        ] + _common_flags + [
             '-I[OUT]/a',
             '--sysroot=[SRC]/build/sysroot-image',
             '-isysroot',
@@ -379,8 +389,7 @@
             '-std=c++14',
             '-x',
             'c++',
-            '-I[SRC]',
-            '-Wno-unknown-warning-option',
+        ] + _common_flags + [
             '-I[OUT]/b',
             '-isystem[OUT]/a',
             '-isystem', '[SRC]/build/c',
@@ -398,8 +407,7 @@
             '-std=c++14',
             '-x',
             'c++',
-            '-I[SRC]',
-            '-Wno-unknown-warning-option',
+        ] + _common_flags + [
             '-I', '[OUT]/a',
             '-I', '[OUT]/tag-eleven'
         ])
diff --git a/ui/accessibility/ax_enum_util.cc b/ui/accessibility/ax_enum_util.cc
index c9f6a89..ede8a413 100644
--- a/ui/accessibility/ax_enum_util.cc
+++ b/ui/accessibility/ax_enum_util.cc
@@ -1483,6 +1483,8 @@
       return "previousFocusId";
     case ax::mojom::IntAttribute::kNextFocusId:
       return "nextFocusId";
+    case ax::mojom::IntAttribute::kImageAnnotationStatus:
+      return "imageAnnotationStatus";
   }
 
   return "";
@@ -1591,6 +1593,8 @@
     return ax::mojom::IntAttribute::kPreviousFocusId;
   if (0 == strcmp(int_attribute, "nextFocusId"))
     return ax::mojom::IntAttribute::kNextFocusId;
+  if (0 == strcmp(int_attribute, "imageAnnotationStatus"))
+    return ax::mojom::IntAttribute::kImageAnnotationStatus;
   return ax::mojom::IntAttribute::kNone;
 }
 
@@ -2477,4 +2481,49 @@
   return ax::mojom::TreeOrder::kNone;
 }
 
+const char* ToString(ax::mojom::ImageAnnotationStatus status) {
+  switch (status) {
+    case ax::mojom::ImageAnnotationStatus::kNone:
+      return "none";
+    case ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation:
+      return "ineligibleForAnnotation";
+    case ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation:
+      return "eligibleForAnnotation";
+    case ax::mojom::ImageAnnotationStatus::kAnnotationPending:
+      return "annotationPending";
+    case ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded:
+      return "annotationSucceeded";
+    case ax::mojom::ImageAnnotationStatus::kAnnotationEmpty:
+      return "annotationEmpty";
+    case ax::mojom::ImageAnnotationStatus::kAnnotationAdult:
+      return "annotationAdult";
+    case ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed:
+      return "annotationProcessFailed";
+  }
+
+  return "";
+}
+
+ax::mojom::ImageAnnotationStatus ParseImageAnnotationStatus(
+    const char* status) {
+  if (0 == strcmp(status, "none"))
+    return ax::mojom::ImageAnnotationStatus::kNone;
+  if (0 == strcmp(status, "ineligibleForAnnotation"))
+    return ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation;
+  if (0 == strcmp(status, "eligibleForAnnotation"))
+    return ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation;
+  if (0 == strcmp(status, "annotationPending"))
+    return ax::mojom::ImageAnnotationStatus::kAnnotationPending;
+  if (0 == strcmp(status, "annotationSucceeded"))
+    return ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded;
+  if (0 == strcmp(status, "annotationEmpty"))
+    return ax::mojom::ImageAnnotationStatus::kAnnotationEmpty;
+  if (0 == strcmp(status, "annotationAdult"))
+    return ax::mojom::ImageAnnotationStatus::kAnnotationAdult;
+  if (0 == strcmp(status, "annotationProcessFailed"))
+    return ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed;
+
+  return ax::mojom::ImageAnnotationStatus::kNone;
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/ax_enum_util.h b/ui/accessibility/ax_enum_util.h
index 91f6b5c..d558163a8 100644
--- a/ui/accessibility/ax_enum_util.h
+++ b/ui/accessibility/ax_enum_util.h
@@ -138,6 +138,11 @@
 AX_EXPORT const char* ToString(ax::mojom::TreeOrder tree_order);
 AX_EXPORT ax::mojom::TreeOrder ParseTreeOrder(const char* tree_order);
 
+// ax::mojom::ImageAnnotationStatus
+AX_EXPORT const char* ToString(ax::mojom::ImageAnnotationStatus status);
+AX_EXPORT ax::mojom::ImageAnnotationStatus ParseImageAnnotationStatus(
+    const char* status);
+
 }  // namespace ui
 
 #endif  // UI_ACCESSIBILITY_AX_ENUM_UTIL_H_
diff --git a/ui/accessibility/ax_enum_util_unittest.cc b/ui/accessibility/ax_enum_util_unittest.cc
index 754886e..4b248fc2 100644
--- a/ui/accessibility/ax_enum_util_unittest.cc
+++ b/ui/accessibility/ax_enum_util_unittest.cc
@@ -195,4 +195,9 @@
   TestEnumStringConversion<ax::mojom::TreeOrder>(ParseTreeOrder);
 }
 
+TEST(AXEnumUtilTest, ImageAnnotationStatus) {
+  TestEnumStringConversion<ax::mojom::ImageAnnotationStatus>(
+      ParseImageAnnotationStatus);
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/ax_enums.mojom b/ui/accessibility/ax_enums.mojom
index d736341..26546b2 100644
--- a/ui/accessibility/ax_enums.mojom
+++ b/ui/accessibility/ax_enums.mojom
@@ -452,7 +452,7 @@
   kFontFamily,
   kHtmlTag,
   // Stores an automatic image annotation if one is available. Only valid on
-  // ax::mojom::Role::kImage.
+  // ax::mojom::Role::kImage. See kImageAnnotationStatus, too.
   kImageAnnotation,
   kImageDataUrl,
   kInnerHtml,
@@ -573,6 +573,9 @@
    // Focus traversal in views and Android.
   kPreviousFocusId,
   kNextFocusId,
+
+   // Image annotation status, of type ImageAnnotationStatus.
+  kImageAnnotationStatus,
 };
 
 enum FloatAttribute {
@@ -894,3 +897,34 @@
   kUnknown,  // The Tree ID is unknown.
   kToken,    // Every other tree ID must have a valid unguessable token.
 };
+
+enum ImageAnnotationStatus {
+   // Not an image, or image annotation feature not enabled.
+  kNone,
+
+   // Not loaded yet, already labeled by the author, or not eligible
+   // due to size, type, etc.
+  kIneligibleForAnnotation,
+
+   // Eligible to be automatically annotated if the user requests it.
+  kEligibleForAnnotation,
+
+   // An annotation has been requested but has not been received yet.
+  kAnnotationPending,
+
+   // An annotation has been provided and kImageAnnotation contains the
+   // annotation text.
+  kAnnotationSucceeded,
+
+   // The annotation request was processed successfully, but it was not
+   // possible to come up with an annotation for this image.
+  kAnnotationEmpty,
+
+   // The image is classified as adult content and no annotation will
+   // be generated.
+  kAnnotationAdult,
+
+   // The annotation process failed, e.g. unable to contact the server,
+   // request timed out, etc.
+  kAnnotationProcessFailed,
+};
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 943ea1c..74ecc71 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -151,6 +151,7 @@
     case ax::mojom::IntAttribute::kAriaCellColumnIndex:
     case ax::mojom::IntAttribute::kAriaRowCount:
     case ax::mojom::IntAttribute::kAriaCellRowIndex:
+    case ax::mojom::IntAttribute::kImageAnnotationStatus:
       return false;
   }
 
@@ -752,6 +753,21 @@
   }
 }
 
+ax::mojom::ImageAnnotationStatus AXNodeData::GetImageAnnotationStatus() const {
+  return static_cast<ax::mojom::ImageAnnotationStatus>(
+      GetIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus));
+}
+
+void AXNodeData::SetImageAnnotationStatus(
+    ax::mojom::ImageAnnotationStatus status) {
+  if (HasIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus))
+    RemoveIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus);
+  if (status != ax::mojom::ImageAnnotationStatus::kNone) {
+    AddIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus,
+                    static_cast<int32_t>(status));
+  }
+}
+
 ax::mojom::Restriction AXNodeData::GetRestriction() const {
   return static_cast<ax::mojom::Restriction>(
       GetIntAttribute(ax::mojom::IntAttribute::kRestriction));
@@ -1100,6 +1116,11 @@
       case ax::mojom::IntAttribute::kPreviousFocusId:
         result += " previous_focus_id=" + value;
         break;
+      case ax::mojom::IntAttribute::kImageAnnotationStatus:
+        result += std::string(" image_annotation_status=") +
+                  ui::ToString(static_cast<ax::mojom::ImageAnnotationStatus>(
+                      int_attribute.second));
+        break;
       case ax::mojom::IntAttribute::kNone:
         break;
     }
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h
index 3a26596..fbbadb75 100644
--- a/ui/accessibility/ax_node_data.h
+++ b/ui/accessibility/ax_node_data.h
@@ -173,6 +173,8 @@
   void SetRestriction(ax::mojom::Restriction restriction);
   ax::mojom::TextDirection GetTextDirection() const;
   void SetTextDirection(ax::mojom::TextDirection text_direction);
+  ax::mojom::ImageAnnotationStatus GetImageAnnotationStatus() const;
+  void SetImageAnnotationStatus(ax::mojom::ImageAnnotationStatus status);
 
   // Return a string representation of this data, for debugging.
   virtual std::string ToString() const;
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 9b37614..ba8e8392 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -391,6 +391,15 @@
   return value;
 }
 
+base::string16 AXPlatformNodeBase::GetRoleDescription() const {
+  if (GetData().GetImageAnnotationStatus() ==
+      ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation) {
+    return GetDelegate()->GetLocalizedRoleDescriptionForUnlabeledImage();
+  }
+
+  return GetString16Attribute(ax::mojom::StringAttribute::kRoleDescription);
+}
+
 AXPlatformNodeBase* AXPlatformNodeBase::GetSelectionContainer() const {
   if (!delegate_)
     return nullptr;
@@ -671,8 +680,13 @@
     AddAttributeToList("autocomplete", "list", attributes);
   }
 
-  AddAttributeToList(ax::mojom::StringAttribute::kRoleDescription,
-                     "roledescription", attributes);
+  base::string16 role_description = GetRoleDescription();
+  if (!role_description.empty() ||
+      HasStringAttribute(ax::mojom::StringAttribute::kRoleDescription)) {
+    AddAttributeToList("roledescription", base::UTF16ToUTF8(role_description),
+                       attributes);
+  }
+
   AddAttributeToList(ax::mojom::StringAttribute::kKeyShortcuts, "keyshortcuts",
                      attributes);
 
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index d3a83f39..0b2b491 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -230,6 +230,10 @@
   // text found in any embedded object.
   std::string GetInnerText() const;
 
+  // Get the role description from the node data or from the image annotation
+  // status.
+  base::string16 GetRoleDescription() const;
+
   // Cast a gfx::NativeViewAccessible to an AXPlatformNodeBase if it is one,
   // or return NULL if it's not an instance of this class.
   static AXPlatformNodeBase* FromNativeViewAccessible(
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index 6f3ad02..3cc239d2 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -179,6 +179,15 @@
   virtual bool AccessibilityPerformAction(const AXActionData& data) = 0;
 
   //
+  // Localized strings.
+  //
+
+  virtual base::string16 GetLocalizedRoleDescriptionForUnlabeledImage()
+      const = 0;
+  virtual base::string16 GetLocalizedStringForImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus status) const = 0;
+
+  //
   // Testing.
   //
 
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index d4501b2..4fe9726 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -170,6 +170,18 @@
   return false;
 }
 
+base::string16
+AXPlatformNodeDelegateBase::GetLocalizedStringForImageAnnotationStatus(
+    ax::mojom::ImageAnnotationStatus status) const {
+  return base::string16();
+}
+
+base::string16
+AXPlatformNodeDelegateBase::GetLocalizedRoleDescriptionForUnlabeledImage()
+    const {
+  return base::string16();
+}
+
 bool AXPlatformNodeDelegateBase::ShouldIgnoreHoveredStateForTesting() {
   return true;
 }
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h
index 93d15b5..726dfc0 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -157,6 +157,14 @@
   bool AccessibilityPerformAction(const AXActionData& data) override;
 
   //
+  // Localized strings.
+  //
+
+  base::string16 GetLocalizedStringForImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus status) const override;
+  base::string16 GetLocalizedRoleDescriptionForUnlabeledImage() const override;
+
+  //
   // Testing.
   //
 
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index d893e15..9f847b9 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -184,6 +184,18 @@
 // cursor keys are used to scroll a webpage.
 constexpr float kSmallScrollIncrement = 40.0f;
 
+void AppendTextToString(base::string16 extra_text, base::string16* string) {
+  if (extra_text.empty())
+    return;
+
+  if (string->empty()) {
+    *string = extra_text;
+    return;
+  }
+
+  *string += base::string16(L". ") + extra_text;
+}
+
 }  // namespace
 
 void AXPlatformNodeWin::AddAttributeToList(const char* name,
@@ -797,18 +809,47 @@
       ax::mojom::StringAttribute::kKeyShortcuts, acc_key);
 }
 
-IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name) {
+IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name_bstr) {
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ACC_NAME);
   AXPlatformNodeWin* target;
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, name, target);
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, name_bstr, target);
 
   for (IAccessible2UsageObserver& observer :
        GetIAccessible2UsageObserverList()) {
     observer.OnAccNameCalled();
   }
 
-  return target->GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName,
-                                          name);
+  bool has_name = target->HasStringAttribute(ax::mojom::StringAttribute::kName);
+  base::string16 name =
+      target->GetString16Attribute(ax::mojom::StringAttribute::kName);
+  auto status = GetData().GetImageAnnotationStatus();
+  switch (status) {
+    case ax::mojom::ImageAnnotationStatus::kNone:
+    case ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation:
+      break;
+
+    case ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation:
+    case ax::mojom::ImageAnnotationStatus::kAnnotationPending:
+    case ax::mojom::ImageAnnotationStatus::kAnnotationEmpty:
+    case ax::mojom::ImageAnnotationStatus::kAnnotationAdult:
+    case ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed:
+      AppendTextToString(
+          GetDelegate()->GetLocalizedStringForImageAnnotationStatus(status),
+          &name);
+      break;
+
+    case ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded:
+      AppendTextToString(
+          GetString16Attribute(ax::mojom::StringAttribute::kImageAnnotation),
+          &name);
+      break;
+  }
+
+  if (name.empty() && !has_name)
+    return S_FALSE;
+
+  *name_bstr = SysAllocString(name.c_str());
+  return S_OK;
 }
 
 IFACEMETHODIMP AXPlatformNodeWin::get_accParent(IDispatch** disp_parent) {
@@ -1258,8 +1299,9 @@
   COM_OBJECT_VALIDATE_1_ARG(localized_extended_role);
   AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
 
-  return GetStringAttributeAsBstr(ax::mojom::StringAttribute::kRoleDescription,
-                                  localized_extended_role);
+  base::string16 role_description = GetRoleDescription();
+  *localized_extended_role = SysAllocString(role_description.c_str());
+  return S_OK;
 }
 
 //
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 6b35cc7..2736b8d 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -2387,6 +2387,173 @@
   EXPECT_STREQ(L"extended role", role);
 }
 
+TEST_F(AXPlatformNodeWinTest, TestUnlabeledImageRoleDescription) {
+  AXNodeData root;
+  root.id = 1;
+  root.SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation);
+  Init(root);
+
+  ComPtr<IAccessible> root_obj(GetRootIAccessible());
+  ComPtr<IAccessible2> iaccessible2 = ToIAccessible2(root_obj);
+  ScopedBstr role_description;
+  EXPECT_EQ(S_OK, iaccessible2->get_localizedExtendedRole(
+                      role_description.Receive()));
+  EXPECT_STREQ(L"Unlabeled image", role_description);
+}
+
+TEST_F(AXPlatformNodeWinTest, TestUnlabeledImageAttributes) {
+  AXNodeData root;
+  root.id = 1;
+  root.SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation);
+  Init(root);
+
+  ComPtr<IAccessible> root_obj(GetRootIAccessible());
+  ComPtr<IAccessible2> iaccessible2 = ToIAccessible2(root_obj);
+
+  ScopedBstr attributes_bstr;
+  EXPECT_EQ(S_OK, iaccessible2->get_attributes(attributes_bstr.Receive()));
+  base::string16 attributes(attributes_bstr);
+
+  std::vector<base::string16> attribute_vector = base::SplitString(
+      attributes, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+  bool found = false;
+  for (base::string16 attribute : attribute_vector) {
+    if (attribute == L"roledescription:Unlabeled image")
+      found = true;
+  }
+  EXPECT_TRUE(found);
+}
+
+TEST_F(AXPlatformNodeWinTest, TestAnnotatedImageName) {
+  std::vector<const wchar_t*> expected_names;
+
+  AXTreeUpdate tree;
+  tree.root_id = 1;
+  tree.nodes.resize(10);
+  tree.nodes[0].id = 1;
+  tree.nodes[0].child_ids = {2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+  // If the status is EligibleForAnnotation and there's no existing label,
+  // the name should be the discoverability string.
+  tree.nodes[1].id = 2;
+  tree.nodes[1].role = ax::mojom::Role::kImage;
+  tree.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[1].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation);
+  expected_names.push_back(
+      L"To get missing image descriptions, open the context menu.");
+
+  // If the status is EligibleForAnnotation, the discoverability string
+  // should be appended to the existing name.
+  tree.nodes[2].id = 3;
+  tree.nodes[2].role = ax::mojom::Role::kImage;
+  tree.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[2].SetName("ExistingLabel");
+  tree.nodes[2].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation);
+  expected_names.push_back(
+      L"ExistingLabel. To get missing image descriptions, open the context "
+      L"menu.");
+
+  // If the status is IneligibleForAnnotation, nothing should be appended.
+  tree.nodes[3].id = 4;
+  tree.nodes[3].role = ax::mojom::Role::kImage;
+  tree.nodes[3].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[3].SetName("ExistingLabel");
+  tree.nodes[3].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation);
+  expected_names.push_back(L"ExistingLabel");
+
+  // If the status is AnnotationPending, pending text should be appended
+  // to the name.
+  tree.nodes[4].id = 5;
+  tree.nodes[4].role = ax::mojom::Role::kImage;
+  tree.nodes[4].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[4].SetName("ExistingLabel");
+  tree.nodes[4].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kAnnotationPending);
+  expected_names.push_back(L"ExistingLabel. Getting description...");
+
+  // If the status is AnnotationSucceeded, and there's no annotation,
+  // nothing should be appended. (Ideally this shouldn't happen.)
+  tree.nodes[5].id = 6;
+  tree.nodes[5].role = ax::mojom::Role::kImage;
+  tree.nodes[5].SetName("ExistingLabel");
+  tree.nodes[5].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded);
+  expected_names.push_back(L"ExistingLabel");
+
+  // If the status is AnnotationSucceeded, the annotation should be appended
+  // to the existing label.
+  tree.nodes[6].id = 7;
+  tree.nodes[6].role = ax::mojom::Role::kImage;
+  tree.nodes[6].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[6].SetName("ExistingLabel");
+  tree.nodes[6].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded);
+  expected_names.push_back(L"ExistingLabel. Annotation");
+
+  // If the status is AnnotationEmpty, failure text should be appended
+  // to the name.
+  tree.nodes[7].id = 8;
+  tree.nodes[7].role = ax::mojom::Role::kImage;
+  tree.nodes[7].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[7].SetName("ExistingLabel");
+  tree.nodes[7].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kAnnotationEmpty);
+  expected_names.push_back(L"ExistingLabel. No description is available.");
+
+  // If the status is AnnotationAdult, appropriate text should be appended
+  // to the name.
+  tree.nodes[8].id = 9;
+  tree.nodes[8].role = ax::mojom::Role::kImage;
+  tree.nodes[8].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[8].SetName("ExistingLabel");
+  tree.nodes[8].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kAnnotationAdult);
+  expected_names.push_back(L"ExistingLabel. Appears to be adult content.");
+
+  // If the status is AnnotationProcessFailed, appropriate text should be
+  // appended to the name.
+  tree.nodes[9].id = 10;
+  tree.nodes[9].role = ax::mojom::Role::kImage;
+  tree.nodes[9].AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
+                                   "Annotation");
+  tree.nodes[9].SetName("ExistingLabel");
+  tree.nodes[9].SetImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed);
+  expected_names.push_back(L"ExistingLabel. Unable to get a description.");
+
+  // We should have one expected name per child of the root.
+  ASSERT_EQ(expected_names.size(), tree.nodes[0].child_ids.size());
+  int child_count = static_cast<int>(expected_names.size());
+
+  Init(tree);
+
+  ComPtr<IAccessible> root_obj(GetRootIAccessible());
+
+  for (int child_index = 0; child_index < child_count; child_index++) {
+    ComPtr<IDispatch> child_dispatch;
+    ASSERT_HRESULT_SUCCEEDED(root_obj->get_accChild(
+        ScopedVariant(child_index + 1), &child_dispatch));
+    ComPtr<IAccessible> child;
+    ASSERT_HRESULT_SUCCEEDED(child_dispatch.As(&child));
+
+    ScopedBstr name;
+    EXPECT_EQ(S_OK, child->get_accName(SELF, name.Receive()));
+    EXPECT_STREQ(expected_names[child_index], name);
+  }
+}
+
 TEST_F(AXPlatformNodeWinTest, TestIAccessibleTextGetNCharacters) {
   AXNodeData root;
   root.id = 0;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 108add630..ae328c9 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -7,6 +7,7 @@
 #include <unordered_map>
 
 #include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_table_info.h"
 #include "ui/accessibility/ax_tree_observer.h"
@@ -367,6 +368,35 @@
   return true;
 }
 
+base::string16 TestAXNodeWrapper::GetLocalizedRoleDescriptionForUnlabeledImage()
+    const {
+  return base::ASCIIToUTF16("Unlabeled image");
+}
+
+base::string16 TestAXNodeWrapper::GetLocalizedStringForImageAnnotationStatus(
+    ax::mojom::ImageAnnotationStatus status) const {
+  switch (status) {
+    case ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation:
+      return base::ASCIIToUTF16(
+          "To get missing image descriptions, open the context menu.");
+    case ax::mojom::ImageAnnotationStatus::kAnnotationPending:
+      return base::ASCIIToUTF16("Getting description...");
+    case ax::mojom::ImageAnnotationStatus::kAnnotationEmpty:
+      return base::ASCIIToUTF16("No description is available.");
+    case ax::mojom::ImageAnnotationStatus::kAnnotationAdult:
+      return base::ASCIIToUTF16("Appears to be adult content.");
+    case ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed:
+      return base::ASCIIToUTF16("Unable to get a description.");
+    case ax::mojom::ImageAnnotationStatus::kNone:
+    case ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation:
+    case ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded:
+      return base::string16();
+  }
+
+  NOTREACHED();
+  return base::string16();
+}
+
 bool TestAXNodeWrapper::ShouldIgnoreHoveredStateForTesting() {
   return true;
 }
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h
index 4513537c..9993b5d 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -76,6 +76,9 @@
   int32_t CellIndexToId(int32_t cell_index) const override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
   bool AccessibilityPerformAction(const AXActionData& data) override;
+  base::string16 GetLocalizedRoleDescriptionForUnlabeledImage() const override;
+  base::string16 GetLocalizedStringForImageAnnotationStatus(
+      ax::mojom::ImageAnnotationStatus status) const override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   const ui::AXUniqueId& GetUniqueId() const override;
   std::set<AXPlatformNode*> GetReverseRelations(
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 3036ff3..9f57e04e 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -983,7 +983,8 @@
   std::string json;
   debug_info->AppendAsTraceFormat(&json);
   base::JSONReader json_reader;
-  std::unique_ptr<base::Value> debug_info_value(json_reader.ReadToValue(json));
+  std::unique_ptr<base::Value> debug_info_value(
+      json_reader.ReadToValueDeprecated(json));
   EXPECT_TRUE(debug_info_value);
   EXPECT_TRUE(debug_info_value->is_dict());
   base::DictionaryValue* dictionary = 0;
diff --git a/ui/display/manager/json_converter_unittest.cc b/ui/display/manager/json_converter_unittest.cc
index 071f3cc..4554c1e4 100644
--- a/ui/display/manager/json_converter_unittest.cc
+++ b/ui/display/manager/json_converter_unittest.cc
@@ -49,8 +49,9 @@
       "}";
   int error_code = 0, error_line, error_column;
   std::string error_msg;
-  std::unique_ptr<base::Value> read_value(base::JSONReader::ReadAndReturnError(
-      data, 0, &error_code, &error_msg, &error_line, &error_column));
+  std::unique_ptr<base::Value> read_value(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          data, 0, &error_code, &error_msg, &error_line, &error_column));
   ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":"
                            << error_column;
   EXPECT_TRUE(value.Equals(read_value.get()));
@@ -72,8 +73,9 @@
       "}";
   int error_code = 0, error_line, error_column;
   std::string error_msg;
-  std::unique_ptr<base::Value> read_value(base::JSONReader::ReadAndReturnError(
-      data, 0, &error_code, &error_msg, &error_line, &error_column));
+  std::unique_ptr<base::Value> read_value(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          data, 0, &error_code, &error_msg, &error_line, &error_column));
   ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":"
                            << error_column;
 
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index d19b990..183e75d 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -1253,7 +1253,7 @@
     return false;
   }
 
-  if (util.isNativeEntry(entry)) {
+  if (!util.isFakeEntry(entry)) {
     return !this.volumeManager_.getVolumeInfo(entry);
   }
 
@@ -1262,6 +1262,11 @@
     if (volume.fakeEntries[rootType]) {
       return true;
     }
+    // The removable root is selected and one of its child partitions has been
+    // unmounted.
+    if (volume.prefixEntry === entry) {
+      return true;
+    }
   }
   return false;
 };
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index c24f2b0c..3a606d5e 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1215,8 +1215,7 @@
   FileManager.prototype.setupCrostini_ = function() {
     chrome.fileManagerPrivate.isCrostiniEnabled((crostiniEnabled) => {
       // Check for 'crostini-files' feature.
-      this.crostini_.setEnabled(
-          crostiniEnabled && loadTimeData.getBoolean('CROSTINI_FILES_ENABLED'));
+      this.crostini_.setEnabled(crostiniEnabled);
 
       // Setup Linux files fake root.
       this.directoryTree.dataModel.linuxFilesItem = crostiniEnabled ?
diff --git a/ui/file_manager/file_manager/test/js/strings.js b/ui/file_manager/file_manager/test/js/strings.js
index 476815c2..66b69b5 100644
--- a/ui/file_manager/file_manager/test/js/strings.js
+++ b/ui/file_manager/file_manager/test/js/strings.js
@@ -9,7 +9,6 @@
 
 // Extend with additional fields not found in grdp files.
 Object.setPrototypeOf(loadTimeData.data_, {
-  'CROSTINI_FILES_ENABLED': true,
   'DRIVE_FS_ENABLED': false,
   'GOOGLE_DRIVE_REDEEM_URL': 'http://www.google.com/intl/en/chrome/devices' +
       '/goodies.html?utm_source=filesapp&utm_medium=banner&utm_campaign=gsg',
diff --git a/ui/file_manager/integration_tests/file_manager/context_menu.js b/ui/file_manager/integration_tests/file_manager/context_menu.js
index 0665e25..b853eb0 100644
--- a/ui/file_manager/integration_tests/file_manager/context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/context_menu.js
@@ -686,7 +686,8 @@
   const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
 
   // Mount removable volumes.
-  await sendTestMessage({name: 'mountFakePartitions'});
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
+  await sendTestMessage({name: 'mountFakeUsb'});
 
   // Wait for removable volume to appear in the directory tree.
   const removable = await remoteCall.waitForElement(appId, query);
@@ -709,14 +710,14 @@
  * root with child partitions.
  */
 testcase.checkRemovableRootContextMenu = async function() {
-  return checkUnmountRootsContextMenu('PARTITION_DRIVE_LABEL');
+  return checkUnmountRootsContextMenu('Drive Label');
 };
 
 /**
  * Checks that the unmount command is shown in the context menu for a USB.
  */
 testcase.checkUsbContextMenu = async function() {
-  return checkUnmountRootsContextMenu('singleUSB');
+  return checkUnmountRootsContextMenu('fake-usb');
 };
 
 /**
@@ -735,7 +736,7 @@
   const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
 
   // Mount removable volumes.
-  await sendTestMessage({name: 'mountFakePartitions'});
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
 
   // Wait for partition-1 to appear in the directory tree.
   const removable = await remoteCall.waitForElement(appId, partitionQuery);
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.js b/ui/file_manager/integration_tests/file_manager/file_display.js
index 96c84a8..db322fb 100644
--- a/ui/file_manager/integration_tests/file_manager/file_display.js
+++ b/ui/file_manager/integration_tests/file_manager/file_display.js
@@ -186,8 +186,14 @@
   // Open Files app on local downloads.
   const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
 
-  // Mount USB volume.
-  await sendTestMessage({name: 'mountFakePartitions'});
+  // Mount USB device containing partitions.
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
+  // Mount unpartitioned USB device.
+  await sendTestMessage({name: 'mountFakeUsb'});
+
+  // Wait for removable root to appear in the directory tree.
+  const removableRoot = await remoteCall.waitForElement(
+      appId, '#directory-tree [entry-label="Drive Label"]');
 
   // Wait for removable partition-1 to appear in the directory tree.
   const partitionOne = await remoteCall.waitForElement(
@@ -201,28 +207,24 @@
   chrome.test.assertEq(
       'removable', partitionTwo.attributes['volume-type-for-testing']);
 
-  // Wait for removable volume to appear in the directory tree.
-  const singleUSB = await remoteCall.waitForElement(
-      appId, '#directory-tree [entry-label="singleUSB"]');
-  chrome.test.assertEq(
-      'removable', singleUSB.attributes['volume-type-for-testing']);
-
-  // Wait for removable root to appear in the directory tree.
-  const removableRoot = await remoteCall.waitForElement(
-      appId, '#directory-tree [entry-label="PARTITION_DRIVE_LABEL"]');
-
   // Check partitions are children of the root label.
   const childEntriesQuery =
-      ['[entry-label="PARTITION_DRIVE_LABEL"] .tree-children .tree-item'];
+      ['[entry-label="Drive Label"] .tree-children .tree-item'];
   const childEntries = await remoteCall.callRemoteTestUtil(
       'queryAllElements', appId, childEntriesQuery);
   const childEntryLabels =
       childEntries.map(child => child.attributes['entry-label']);
   chrome.test.assertEq(['partition-1', 'partition-2'], childEntryLabels);
 
-  // Check single USB does not have partitions as tree children.
+  // Wait for USB to appear in the directory tree.
+  const fakeUsb = await remoteCall.waitForElement(
+      appId, '#directory-tree [entry-label="fake-usb"]');
+  chrome.test.assertEq(
+      'removable', fakeUsb.attributes['volume-type-for-testing']);
+
+  // Check unpartitioned USB does not have partitions as tree children.
   const itemEntriesQuery =
-      ['[entry-label="singleUSB"] .tree-children .tree-item'];
+      ['[entry-label="fake-usb"] .tree-children .tree-item'];
   const itemEntries = await remoteCall.callRemoteTestUtil(
       'queryAllElements', appId, itemEntriesQuery);
   chrome.test.assertEq(1, itemEntries.length);
@@ -241,7 +243,7 @@
   const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
 
   // Mount removable partitions.
-  await sendTestMessage({name: 'mountFakePartitions'});
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
 
   // Wait for removable group to appear in the directory tree.
   await remoteCall.waitForElement(appId, removableGroup);
@@ -253,7 +255,6 @@
   // Wait for removable partitions to appear in the file table.
   const partitionOne = await remoteCall.waitForElement(
       appId, '#file-list [file-name="partition-1"] .type');
-  console.log(JSON.stringify(partitionOne));
   chrome.test.assertEq('ext4', partitionOne.text);
 
   const partitionTwo = await remoteCall.waitForElement(
@@ -611,3 +612,96 @@
   await remoteCall.waitForFiles(
       appId, expectedRows, {ignoreLastModifiedTime: true});
 };
+
+/**
+ * Navigates to a removable volume, then unmounts it. Check to see whether
+ * Files App switches away to the default Downloads directory.
+ *
+ * @param {string} removableDirectory The removable directory to be inside
+ *    before unmounting the USB.
+ */
+async function unmountRemovableVolume(removableDirectory) {
+  const removableRootQuery = '#directory-tree [root-type-icon="removable"]';
+
+  // Open Files app on Downloads containing ENTRIES.photos.
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.photos], []);
+
+  // Mount a device containing two partitions.
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
+
+  // Wait for the removable root to appear in the directory tree.
+  await remoteCall.waitForElement(appId, removableRootQuery);
+
+  // Navigate to the removable root directory.
+  await remoteCall.callRemoteTestUtil(
+      'fakeMouseClick', appId, [removableRootQuery]);
+
+  // Wait for the navigation to complete.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Drive Label');
+
+  // Wait for partition entries to appear in the directory.
+  await remoteCall.waitForElement(
+      appId, '#file-list [file-name="partition-1"]');
+  await remoteCall.waitForElement(
+      appId, '#file-list [file-name="partition-2"]');
+
+  if (removableDirectory === 'partition-1' ||
+      removableDirectory === 'partition-2') {
+    const partitionQuery = `#file-list [file-name="${removableDirectory}"]`;
+    const partitionFiles = [ENTRIES.hello.getExpectedRow()];
+    await remoteCall.callRemoteTestUtil(
+        'fakeMouseDoubleClick', appId, [partitionQuery]);
+    await remoteCall.waitUntilCurrentDirectoryIsChanged(
+        appId, `/Drive Label/${removableDirectory}`);
+    await remoteCall.waitForFiles(
+        appId, partitionFiles, {ignoreLastModifiedTime: true});
+  }
+
+  // Unmount partitioned device.
+  await sendTestMessage({name: 'unmountPartitions'});
+
+  // We should navigate to Downloads or MyFiles.
+  // TODO(crbug.com/880130): Remove this conditional.
+  let defaultFolder = '/My files/Downloads';
+  let expectedRows = [ENTRIES.photos.getExpectedRow()];
+  if (RootPath.DOWNLOADS_PATH === '/Downloads') {
+    defaultFolder = '/My files';
+    expectedRows = [
+      ['Play files', '--', 'Folder'],
+      ['Downloads', '--', 'Folder'],
+      ['Linux files', '--', 'Folder'],
+    ];
+  }
+
+  // Ensure MyFiles or Downloads has loaded.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, defaultFolder);
+
+  // And contains the expected files.
+  await remoteCall.waitForFiles(
+      appId, expectedRows, {ignoreLastModifiedTime: true});
+}
+
+/**
+ * Tests Files app switches away from a removable device root after the USB is
+ * unmounted.
+ */
+testcase.fileDisplayUnmountRemovableRoot = function() {
+  return unmountRemovableVolume('Drive Label');
+};
+
+/**
+ * Tests Files app switches away from a partition inside the USB after the USB
+ * is unmounted.
+ */
+testcase.fileDisplayUnmountFirstPartition = function() {
+  return unmountRemovableVolume('partition-1');
+};
+
+/**
+ * Tests Files app switches away from a partition inside the USB after the USB
+ * is unmounted. Partition-1 will be ejected first.
+ */
+testcase.fileDisplayUnmountLastPartition = function() {
+  return unmountRemovableVolume('partition-2');
+};
diff --git a/ui/file_manager/integration_tests/file_manager/quick_view.js b/ui/file_manager/integration_tests/file_manager/quick_view.js
index d1135981..59c0508a 100644
--- a/ui/file_manager/integration_tests/file_manager/quick_view.js
+++ b/ui/file_manager/integration_tests/file_manager/quick_view.js
@@ -166,8 +166,8 @@
   const appId =
       await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.photos], []);
 
-  // Mount USB volume.
-  await sendTestMessage({name: 'mountFakePartitions'});
+  // Mount USB device containing partitions.
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
 
   // Wait for 2 removable partitions to appear in the directory tree.
   await repeatUntil(async () => {
diff --git a/ui/file_manager/integration_tests/file_manager/tab_index.js b/ui/file_manager/integration_tests/file_manager/tab_index.js
index d04847c..b732d76 100644
--- a/ui/file_manager/integration_tests/file_manager/tab_index.js
+++ b/ui/file_manager/integration_tests/file_manager/tab_index.js
@@ -105,8 +105,8 @@
       appId, '#breadcrumb-path-0', ['background-color']);
 
   // Press the tab key.
-  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
-      'fakeKeyDown', appId, ['body', 'Tab', false, false, false]));
+  const result = await sendTestMessage({name: 'dispatchTabKey'});
+  chrome.test.assertEq(result, 'tabKeyDispatched', 'Tab key dispatch failure');
 
   // Get background color for breadcrumb with focus.
   const focused = await remoteCall.waitForElementStyles(
@@ -213,10 +213,9 @@
       chrome.test.assertTrue(
           await remoteCall.checkNextTabFocus(appId, className), className);
     }
-
-    // Closes the window by pressing Enter.
-    await remoteCall.callRemoteTestUtil(
-        'fakeKeyDown', appId, ['#file-list', 'Enter', false, false, false]);
+    // Closes the window by pressing Escape.
+    chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
+        'fakeKeyDown', appId, ['#file-list', 'Escape', false, false, false]));
   };
 
   await openAndWaitForClosingDialog(
diff --git a/ui/file_manager/integration_tests/remote_call.js b/ui/file_manager/integration_tests/remote_call.js
index e2b8353..f4902be1 100644
--- a/ui/file_manager/integration_tests/remote_call.js
+++ b/ui/file_manager/integration_tests/remote_call.js
@@ -453,23 +453,21 @@
  */
 RemoteCallFilesApp.prototype.checkNextTabFocus =
     async function(windowId, elementId) {
-  const result = await remoteCall.callRemoteTestUtil(
-      'fakeKeyDown', windowId, ['body', 'Tab', false, false, false]);
-  chrome.test.assertTrue(result);
-  const element =
-      await remoteCall.callRemoteTestUtil('getActiveElement', windowId, []);
-  if (!element || !element.attributes['id']) {
-    return false;
-  }
+  const result = await sendTestMessage({name: 'dispatchTabKey'});
+  chrome.test.assertEq(result, 'tabKeyDispatched', 'Tab key dispatch failure');
 
-  if (element.attributes['id'] === elementId) {
-    return true;
-  } else {
-    console.error(
-        'The ID of the element should be "' + elementId + '", but "' +
-        element.attributes['id'] + '"');
-    return false;
-  }
+  var caller = getCaller();
+  return repeatUntil(async () => {
+    var element =
+        await remoteCall.callRemoteTestUtil('getActiveElement', windowId, []);
+    if (element && element.attributes['id'] === elementId) {
+      return true;
+    }
+    return pending(
+        caller,
+        'Waiting for active element with id: "' + elementId +
+            '", but current is: "' + element.attributes['id'] + '"');
+  });
 };
 
 /**
diff --git a/ui/file_manager/video_player/js/BUILD.gn b/ui/file_manager/video_player/js/BUILD.gn
index 1090e8a..496ba8c 100644
--- a/ui/file_manager/video_player/js/BUILD.gn
+++ b/ui/file_manager/video_player/js/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 
-js_type_check("closure_compile") {
+js_type_check("closure_compile_module") {
   deps = [
     ":background",
     ":closure_compile_externs",
@@ -13,6 +13,7 @@
     ":mouse_inactivity_watcher",
     ":video_player",
     ":video_player_metrics",
+    ":video_player_native_controls",
   ]
 }
 
@@ -51,6 +52,11 @@
 }
 
 js_library("video_player_native_controls") {
+  deps = [
+    "//ui/file_manager/base/js:app_util",
+    "//ui/webui/resources/js:load_time_data",
+    "//ui/webui/resources/js:util",
+  ]
 }
 
 js_library("video_player") {
@@ -78,3 +84,10 @@
     "../../file_manager/common/js:metrics_base",
   ]
 }
+
+group("closure_compile") {
+  testonly = true
+  deps = [
+    ":closure_compile_module",
+  ]
+}
diff --git a/ui/file_manager/video_player/js/video_player_native_controls.js b/ui/file_manager/video_player/js/video_player_native_controls.js
index a96e1fe..4043b2ca 100644
--- a/ui/file_manager/video_player/js/video_player_native_controls.js
+++ b/ui/file_manager/video_player/js/video_player_native_controls.js
@@ -3,357 +3,393 @@
 // found in the LICENSE file.
 
 /**
- * Video player with native controls
- *
- * @constructor
- * @struct
+ * Video player with chrome's native controls.
  */
-function NativeControlsVideoPlayer() {
-  this.videos_ = null;
-  this.currentPos_ = 0;
-  this.videoElement_ = null;
+class NativeControlsVideoPlayer {
+  constructor() {
+    /**
+     * List of open videos.
+     * @private {Array<!FileEntry>}
+     */
+    this.videos_ = null;
+
+    /**
+     * Index of current playing video.
+     * @private {number}
+     */
+    this.currentPos_ = 0;
+
+    /**
+     * HTML video element that contains the video player.
+     * @private {HTMLVideoElement}
+     */
+    this.videoElement_ = null;
+  }
+
+  /**
+   * Initializes the video player window. This method must be called after DOM
+   * initialization.
+   * @param {!Array<!FileEntry>} videos List of videos.
+   */
+  prepare(videos) {
+    this.videos_ = videos;
+
+    // TODO: Move these setting to html and css file when
+    // we are confident to remove the feature flag
+    this.videoElement_ =
+        assertInstanceof(document.createElement('video'), HTMLVideoElement);
+    this.videoElement_.controls = true;
+    this.videoElement_.controlsList = 'nodownload';
+    this.videoElement_.style.pointerEvents = 'auto';
+    getRequiredElement('video-container').appendChild(this.videoElement_);
+
+    // TODO: remove the element in html when remove the feature flag
+    getRequiredElement('controls-wrapper').style.display = 'none';
+    getRequiredElement('spinner-container').style.display = 'none';
+    getRequiredElement('error-wrapper').style.display = 'none';
+    getRequiredElement('thumbnail').style.display = 'none';
+    getRequiredElement('cast-container').style.display = 'none';
+
+    this.videoElement_.addEventListener('pause', this.onPause_.bind(this));
+
+    this.preparePlayList_();
+    this.addKeyControls_();
+  }
+
+  /**
+   * Attach arrow box for previous/next track to document and set
+   * 'multiple' attribute if user opens more than 1 videos.
+   *
+   * @private
+   */
+  preparePlayList_() {
+    const videoPlayerElement =
+        assertInstanceof(getRequiredElement('video-player'), HTMLDivElement);
+    if (this.videos_.length > 1) {
+      videoPlayerElement.setAttribute('multiple', true);
+    } else {
+      videoPlayerElement.removeAttribute('multiple');
+    }
+
+    const arrowRight = assertInstanceof(
+        queryRequiredElement('.arrow-box .arrow.right'), HTMLDivElement);
+    arrowRight.addEventListener(
+        'click', this.advance_.bind(this, true /* next track */));
+    const arrowLeft = assertInstanceof(
+        queryRequiredElement('.arrow-box .arrow.left'), HTMLDivElement);
+    arrowLeft.addEventListener(
+        'click', this.advance_.bind(this, false /* previous track */));
+  }
+
+  /**
+   * Add keyboard controls to document.
+   *
+   * @private
+   */
+  addKeyControls_() {
+    document.addEventListener('keydown', (/** KeyboardEvent */ event) => {
+      const key =
+          (event.ctrlKey && event.shiftKey ? 'Ctrl+Shift+' : '') + event.key;
+      switch (key) {
+          // Handle debug shortcut keys.
+        case 'Ctrl+Shift+I':
+          chrome.fileManagerPrivate.openInspector('normal');
+          break;
+        case 'Ctrl+Shift+J':
+          chrome.fileManagerPrivate.openInspector('console');
+          break;
+        case 'Ctrl+Shift+C':
+          chrome.fileManagerPrivate.openInspector('element');
+          break;
+        case 'Ctrl+Shift+B':
+          chrome.fileManagerPrivate.openInspector('background');
+          break;
+
+        case 'k':
+        case 'MediaPlayPause':
+          this.togglePlayState_();
+          break;
+        case 'MediaTrackNext':
+          this.advance_(true /* next track */);
+          break;
+        case 'MediaTrackPrevious':
+          this.advance_(false /* previous track */);
+          break;
+        case 'l':
+          this.skip_(true /* forward */);
+          break;
+        case 'j':
+          this.skip_(false /* backward */);
+          break;
+        case 'BrowserBack':
+          chrome.app.window.current().close();
+          break;
+        case 'MediaStop':
+          // TODO: Define "Stop" behavior.
+          break;
+      }
+    });
+
+    getRequiredElement('video-container')
+        .addEventListener('click', (/** MouseEvent */ event) => {
+          // Turn on loop mode when ctrl+click while the video is playing.
+          // If the video is paused, ignore ctrl and play the video.
+          if (event.ctrlKey && !this.videoElement_.paused) {
+            this.setLoopedModeWithFeedback_(true);
+            event.preventDefault();
+          }
+        });
+  }
+
+  /**
+   * Skips forward/backward.
+   * @param {boolean} forward Whether to skip forward or backward.
+   * @private
+   */
+  skip_(forward) {
+    let secondsToSkip = Math.min(
+        NativeControlsVideoPlayer.PROGRESS_MAX_SECONDS_TO_SKIP,
+        this.videoElement_.duration *
+            NativeControlsVideoPlayer.PROGRESS_MAX_RATIO_TO_SKIP);
+
+    if (!forward) {
+      secondsToSkip *= -1;
+    }
+
+    this.videoElement_.currentTime = Math.max(
+        Math.min(
+            this.videoElement_.currentTime + secondsToSkip,
+            this.videoElement_.duration),
+        0);
+  }
+
+  /**
+   * Toggle play/pause.
+   *
+   * @private
+   */
+  togglePlayState_() {
+    if (this.videoElement_.paused) {
+      this.videoElement_.play();
+    } else {
+      this.videoElement_.pause();
+    }
+  }
+
+  /**
+   * Set the looped mode with feedback.
+   *
+   * @param {boolean} on Whether enabled or not.
+   * @private
+   */
+  setLoopedModeWithFeedback_(on) {
+    this.videoElement_.loop = on;
+    if (on) {
+      this.showNotification_('VIDEO_PLAYER_LOOPED_MODE');
+    }
+  }
+
+  /**
+   * Briefly show a text notification at top left corner.
+   *
+   * @param {string} identifier String identifier.
+   * @private
+   */
+  showNotification_(identifier) {
+    getRequiredElement('toast-content').textContent =
+        loadTimeData.getString(identifier);
+    getRequiredElement('toast').show();
+  }
+
+  /**
+   * Plays the first video.
+   */
+  playFirstVideo() {
+    this.currentPos_ = 0;
+    this.reloadCurrentVideo_(this.onFirstVideoReady_.bind(this));
+  }
+
+  /**
+   * Called when the first video is ready after starting to load.
+   * Make the video player app window the same dimension as the video source
+   * Restrict the app window inside the screen.
+   *
+   * @private
+   */
+  onFirstVideoReady_() {
+    const videoWidth = this.videoElement_.videoWidth;
+    const videoHeight = this.videoElement_.videoHeight;
+
+    const aspect = videoWidth / videoHeight;
+    let newWidth = videoWidth;
+    let newHeight = videoHeight;
+
+    const shrinkX = newWidth / window.screen.availWidth;
+    const shrinkY = newHeight / window.screen.availHeight;
+    if (shrinkX > 1 || shrinkY > 1) {
+      if (shrinkY > shrinkX) {
+        newHeight = newHeight / shrinkY;
+        newWidth = newHeight * aspect;
+      } else {
+        newWidth = newWidth / shrinkX;
+        newHeight = newWidth / aspect;
+      }
+    }
+
+    let oldLeft = window.screenX;
+    let oldTop = window.screenY;
+    const oldWidth = window.innerWidth;
+    const oldHeight = window.innerHeight;
+
+    if (!oldWidth && !oldHeight) {
+      oldLeft = window.screen.availWidth / 2;
+      oldTop = window.screen.availHeight / 2;
+    }
+
+    let appWindow = chrome.app.window.current();
+    appWindow.innerBounds.width = Math.round(newWidth);
+    appWindow.innerBounds.height = Math.round(newHeight);
+    appWindow.outerBounds.left =
+        Math.max(0, Math.round(oldLeft - (newWidth - oldWidth) / 2));
+    appWindow.outerBounds.top =
+        Math.max(0, Math.round(oldTop - (newHeight - oldHeight) / 2));
+    appWindow.show();
+
+    this.videoElement_.focus();
+    this.videoElement_.play();
+  }
+
+  /**
+   * Advance to next video when the current one ends.
+   * Not using 'ended' event because dragging the timeline
+   * thumb to the end when seeking will trigger 'ended' event.
+   *
+   * @private
+   */
+  onPause_() {
+    this.videoElement_.loop = false;
+    if (this.videoElement_.currentTime == this.videoElement_.duration) {
+      this.advance_(true);
+    }
+  }
+
+  /**
+   * Advances to the next (or previous) track.
+   *
+   * @param {boolean} direction True to the next, false to the previous.
+   * @private
+   */
+  advance_(direction) {
+    const newPos = this.currentPos_ + (direction ? 1 : -1);
+    if (newPos < 0 || newPos >= this.videos_.length) {
+      return;
+    }
+
+    this.currentPos_ = newPos;
+    this.reloadCurrentVideo_(() => {
+      this.videoElement_.play();
+    });
+  }
+
+  /**
+   * Reloads the current video.
+   *
+   * @param {function()=} opt_callback Completion callback.
+   * @private
+   */
+  reloadCurrentVideo_(opt_callback) {
+    const videoPlayerElement =
+        assertInstanceof(getRequiredElement('video-player'), HTMLDivElement);
+    if (this.currentPos_ == (this.videos_.length - 1)) {
+      videoPlayerElement.setAttribute('last-video', true);
+    } else {
+      videoPlayerElement.removeAttribute('last-video');
+    }
+
+    if (this.currentPos_ === 0) {
+      videoPlayerElement.setAttribute('first-video', true);
+    } else {
+      videoPlayerElement.removeAttribute('first-video');
+    }
+
+    const currentVideo = this.videos_[this.currentPos_];
+    this.loadVideo_(currentVideo, opt_callback);
+  }
+
+  /**
+   * Loads the video file.
+   * @param {!FileEntry} video Entry of the video to be played.
+   * @param {function()=} opt_callback Completion callback.
+   * @private
+   */
+  async loadVideo_(video, opt_callback) {
+    document.title = video.name;
+    const videoUrl = video.toURL();
+
+    if (opt_callback) {
+      this.videoElement_.addEventListener(
+          'loadedmetadata', opt_callback, {once: true});
+    }
+
+    this.videoElement_.src = videoUrl;
+
+    const subtitleUrl = await this.searchSubtitle_(videoUrl);
+    if (subtitleUrl) {
+      const track =
+          assertInstanceof(document.createElement('track'), HTMLTrackElement);
+      track.src = subtitleUrl;
+      track.kind = 'subtitles';
+      track.default = true;
+      this.videoElement_.appendChild(track);
+    }
+  }
+
+  /**
+   * Search subtitle file corresponding to a video.
+   * @param {string} url a url of a video.
+   * @return {Promise} a Promise returns url of subtitle file, or an empty
+   *     string.
+   */
+  async searchSubtitle_(url) {
+    const resolveLocalFileSystemWithExtension = (extension) => {
+      const subtitleUrl = this.getSubtitleUrl_(url, extension);
+      return new Promise(
+          window.webkitResolveLocalFileSystemURL.bind(null, subtitleUrl));
+    };
+
+    try {
+      const subtitle = await resolveLocalFileSystemWithExtension('.vtt');
+      return subtitle.toURL();
+    } catch (error) {
+      // TODO: figure out if there could be any error other than
+      // file not found or not accessible. If not, remove this log.
+      console.error(error);
+      return '';
+    }
+  }
+
+  /**
+   * Get the subtitle url.
+   *
+   * @private
+   * @param {string} srcUrl Source url of the video file.
+   * @param {string} extension Extension of the subtitle we are looking for.
+   * @return {string} Subtitle url.
+   */
+  getSubtitleUrl_(srcUrl, extension) {
+    return srcUrl.replace(/\.[^\.]+$/, extension);
+  }
 }
 
 /**
- * Initializes the video player window. This method must be called after DOM
- * initialization.
- * @param {!Array<!FileEntry>} videos List of videos.
- */
-NativeControlsVideoPlayer.prototype.prepare = function(videos) {
-  this.videos_ = videos;
-
-  // TODO: Move these setting to html and css file when
-  // we are confident to remove the feature flag
-  this.videoElement_ = document.createElement('video');
-  this.videoElement_.controls = true;
-  this.videoElement_.controlsList = 'nodownload';
-  this.videoElement_.style.pointerEvents = 'auto';
-  getRequiredElement('video-container').appendChild(this.videoElement_);
-
-  // TODO: remove the element in html when remove the feature flag
-  getRequiredElement('controls-wrapper').style.display = 'none';
-  getRequiredElement('spinner-container').style.display = 'none';
-  getRequiredElement('error-wrapper').style.display = 'none';
-  getRequiredElement('thumbnail').style.display = 'none';
-  getRequiredElement('cast-container').style.display = 'none';
-
-  this.videoElement_.addEventListener('pause', this.onPause_.bind(this));
-
-  this.preparePlayList_();
-  this.addKeyControls_();
-};
-
-/**
  * 10 seconds should be skipped when J/L key is pressed.
+ * @const {number}
  */
 NativeControlsVideoPlayer.PROGRESS_MAX_SECONDS_TO_SKIP = 10;
 
 /**
  * 20% of duration should be skipped when the video is too short to skip 10
  * seconds.
+ * @const {number}
  */
 NativeControlsVideoPlayer.PROGRESS_MAX_RATIO_TO_SKIP = 0.2;
-
-/**
- * Attach arrow box for previous/next track to document and set
- * 'multiple' attribute if user opens more than 1 videos.
- */
-NativeControlsVideoPlayer.prototype.preparePlayList_ = function() {
-  let videoPlayerElement = getRequiredElement('video-player');
-  if (this.videos_.length > 1) {
-    videoPlayerElement.setAttribute('multiple', true);
-  } else {
-    videoPlayerElement.removeAttribute('multiple');
-  }
-
-  let arrowRight = queryRequiredElement('.arrow-box .arrow.right');
-  arrowRight.addEventListener(
-      'click', this.advance_.wrap(this, true /* next track */));
-  let arrowLeft = queryRequiredElement('.arrow-box .arrow.left');
-  arrowLeft.addEventListener(
-      'click', this.advance_.wrap(this, false /* previous track */));
-};
-
-/**
- * Add keyboard controls to document.
- */
-NativeControlsVideoPlayer.prototype.addKeyControls_ = function() {
-  document.addEventListener('keydown', function(e) {
-    switch (util.getKeyModifiers(e) + e.key) {
-      // Handle debug shortcut keys.
-      case 'Ctrl-Shift-I':  // Ctrl+Shift+I
-        chrome.fileManagerPrivate.openInspector('normal');
-        break;
-      case 'Ctrl-Shift-J':  // Ctrl+Shift+J
-        chrome.fileManagerPrivate.openInspector('console');
-        break;
-      case 'Ctrl-Shift-C':  // Ctrl+Shift+C
-        chrome.fileManagerPrivate.openInspector('element');
-        break;
-      case 'Ctrl-Shift-B':  // Ctrl+Shift+B
-        chrome.fileManagerPrivate.openInspector('background');
-        break;
-
-      case 'k':
-      case 'MediaPlayPause':
-        this.togglePlayState_();
-        break;
-      case 'Escape':
-        util.toggleFullScreen(
-            chrome.app.window.current(),
-            false);  // Leave the full screen mode.
-        break;
-      case 'MediaTrackNext':
-        this.advance_(true /* next track */);
-        break;
-      case 'MediaTrackPrevious':
-        this.advance_(false /* previous track */);
-        break;
-      case 'l':
-        this.skip_(true /* forward */);
-        break;
-      case 'j':
-        this.skip_(false /* backward */);
-        break;
-      case 'BrowserBack':
-        chrome.app.window.current().close();
-        break;
-      case 'MediaStop':
-        // TODO: Define "Stop" behavior.
-        break;
-    }
-  }.wrap(this));
-
-  getRequiredElement('video-container')
-      .addEventListener('click', (/** MouseEvent */ event) => {
-        // Turn on loop mode when ctrl+click while the video is playing.
-        // If the video is paused, ignore ctrl and play the video.
-        if (event.ctrlKey && !this.videoElement_.paused) {
-          this.setLoopedModeWithFeedback_(true);
-          event.preventDefault();
-        }
-      });
-};
-
-/**
- * Skips forward/backward.
- * @param {boolean} forward Whether to skip forward or backward.
- * @private
- */
-NativeControlsVideoPlayer.prototype.skip_ = function(forward) {
-  let secondsToSkip = Math.min(
-      NativeControlsVideoPlayer.PROGRESS_MAX_SECONDS_TO_SKIP,
-      this.videoElement_.duration *
-          NativeControlsVideoPlayer.PROGRESS_MAX_RATIO_TO_SKIP);
-
-  if (!forward) {
-    secondsToSkip *= -1;
-  }
-
-  this.videoElement_.currentTime = Math.max(
-      Math.min(
-          this.videoElement_.currentTime + secondsToSkip,
-          this.videoElement_.duration),
-      0);
-};
-
-/**
- * Toggle play/pause.
- */
-NativeControlsVideoPlayer.prototype.togglePlayState_ = function() {
-  if (this.videoElement_.paused) {
-    this.videoElement_.play();
-  } else {
-    this.videoElement_.pause();
-  }
-};
-
-/**
- * Set the looped mode with feedback.
- *
- * @param {boolean} on Whether enabled or not.
- * @private
- */
-NativeControlsVideoPlayer.prototype.setLoopedModeWithFeedback_ = function(on) {
-  this.videoElement_.loop = on;
-  if (on) {
-    this.showNotification_('VIDEO_PLAYER_LOOPED_MODE');
-  }
-};
-
-/**
- * Briefly show a text notification at top left corner.
- *
- * @param {string} identifier String identifier.
- * @private
- */
-NativeControlsVideoPlayer.prototype.showNotification_ = function(identifier) {
-  getRequiredElement('toast-content').textContent = str(identifier);
-  getRequiredElement('toast').show();
-};
-
-/**
- * Plays the first video.
- */
-NativeControlsVideoPlayer.prototype.playFirstVideo = function() {
-  this.currentPos_ = 0;
-  this.reloadCurrentVideo_(this.onFirstVideoReady_.wrap(this));
-};
-
-/**
- * Called when the first video is ready after starting to load.
- * Make the video player app window the same dimension as the video source
- * Restrict the app window inside the screen.
- *
- * @private
- */
-NativeControlsVideoPlayer.prototype.onFirstVideoReady_ = function() {
-  let videoWidth = this.videoElement_.videoWidth;
-  let videoHeight = this.videoElement_.videoHeight;
-
-  let aspect = videoWidth / videoHeight;
-  let newWidth = videoWidth;
-  let newHeight = videoHeight;
-
-  let shrinkX = newWidth / window.screen.availWidth;
-  let shrinkY = newHeight / window.screen.availHeight;
-  if (shrinkX > 1 || shrinkY > 1) {
-    if (shrinkY > shrinkX) {
-      newHeight = newHeight / shrinkY;
-      newWidth = newHeight * aspect;
-    } else {
-      newWidth = newWidth / shrinkX;
-      newHeight = newWidth / aspect;
-    }
-  }
-
-  let oldLeft = window.screenX;
-  let oldTop = window.screenY;
-  let oldWidth = window.innerWidth;
-  let oldHeight = window.innerHeight;
-
-  if (!oldWidth && !oldHeight) {
-    oldLeft = window.screen.availWidth / 2;
-    oldTop = window.screen.availHeight / 2;
-  }
-
-  let appWindow = chrome.app.window.current();
-  appWindow.innerBounds.width = Math.round(newWidth);
-  appWindow.innerBounds.height = Math.round(newHeight);
-  appWindow.outerBounds.left =
-      Math.max(0, Math.round(oldLeft - (newWidth - oldWidth) / 2));
-  appWindow.outerBounds.top =
-      Math.max(0, Math.round(oldTop - (newHeight - oldHeight) / 2));
-  appWindow.show();
-
-  this.videoElement_.focus();
-  this.videoElement_.play();
-};
-
-/**
- * Advance to next video when the current one ends.
- * Not using 'ended' event because dragging the timeline
- * thumb to the end when seeking will trigger 'ended' event.
- *
- * @private
- */
-NativeControlsVideoPlayer.prototype.onPause_ = function() {
-  this.videoElement_.loop = false;
-  if (this.videoElement_.currentTime == this.videoElement_.duration) {
-    this.advance_(true);
-  }
-};
-
-/**
- * Advances to the next (or previous) track.
- *
- * @param {boolean} direction True to the next, false to the previous.
- * @private
- */
-NativeControlsVideoPlayer.prototype.advance_ = function(direction) {
-  let newPos = this.currentPos_ + (direction ? 1 : -1);
-  if (newPos < 0 || newPos >= this.videos_.length) {
-    return;
-  }
-
-  this.currentPos_ = newPos;
-  this.reloadCurrentVideo_(function() {
-    this.videoElement_.play();
-  }.wrap(this));
-};
-
-/**
- * Reloads the current video.
- *
- * @param {function()=} opt_callback Completion callback.
- */
-NativeControlsVideoPlayer.prototype.reloadCurrentVideo_ = function(
-    opt_callback) {
-  let videoPlayerElement = getRequiredElement('video-player');
-  if (this.currentPos_ == (this.videos_.length - 1)) {
-    videoPlayerElement.setAttribute('last-video', true);
-  } else {
-    videoPlayerElement.removeAttribute('last-video');
-  }
-
-  if (this.currentPos_ === 0) {
-    videoPlayerElement.setAttribute('first-video', true);
-  } else {
-    videoPlayerElement.removeAttribute('first-video');
-  }
-
-  let currentVideo = this.videos_[this.currentPos_];
-  this.loadVideo_(currentVideo, opt_callback);
-};
-
-/**
- * Loads the video file.
- * @param {!FileEntry} video Entry of the video to be played.
- * @param {function()=} opt_callback Completion callback.
- * @private
- */
-NativeControlsVideoPlayer.prototype.loadVideo_ =
-    async function(video, opt_callback) {
-  document.title = video.name;
-  const videoUrl = video.toURL();
-
-  if (opt_callback) {
-    this.videoElement_.addEventListener(
-        'loadedmetadata', opt_callback, {once: true});
-  }
-
-  this.videoElement_.src = videoUrl;
-
-  const subtitleUrl = await this.searchSubtitle_(videoUrl);
-  if (subtitleUrl) {
-    const track =
-        assertInstanceof(document.createElement('track'), HTMLTrackElement);
-    track.src = subtitleUrl;
-    track.kind = 'subtitles';
-    track.default = true;
-    this.videoElement_.appendChild(track);
-  }
-};
-
-/**
- * Search subtitle file corresponding to a video.
- * @param {string} url a url of a video.
- * @return {Promise} a Promise returns url of subtitle file, or an empty string.
- */
-NativeControlsVideoPlayer.prototype.searchSubtitle_ = async function(url) {
-  const baseUrl = util.splitExtension(url)[0];
-  const resolveLocalFileSystemWithExtension = function(extension) {
-    return new Promise(
-        window.webkitResolveLocalFileSystemURL.bind(null, baseUrl + extension));
-  };
-
-  try {
-    const subtitle = await resolveLocalFileSystemWithExtension('.vtt');
-    return subtitle.toURL();
-  } catch (error) {
-    // TODO: figure out if there could be any error other than
-    // file not found or not accessible. If not, remove this log.
-    console.error(error);
-    return '';
-  }
-};
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index d7eced05..b1c03fd 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -1638,6 +1638,12 @@
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
 { 'return_type': 'void',
+ 'versions' : [{'name': 'glRenderbufferStorageMultisampleAdvancedAMD',
+                'extensions': ['GL_AMD_framebuffer_multisample_advanced'] ,
+                'explicit_only': True}],
+  'arguments': 'GLenum target, GLsizei samples, GLsizei storageSamples, '
+               'GLenum internalformat,GLsizei width, GLsizei height', },
+{ 'return_type': 'void',
  'versions' : [{'name': 'glRenderbufferStorageMultisampleEXT',
                 'extensions': ['GL_EXT_multisampled_render_to_texture'],
                 'explicit_only': True},
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index 35d6e1a..80ba856 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -1116,6 +1116,12 @@
                                         GLenum internalformat,
                                         GLsizei width,
                                         GLsizei height) override;
+void glRenderbufferStorageMultisampleAdvancedAMDFn(GLenum target,
+                                                   GLsizei samples,
+                                                   GLsizei storageSamples,
+                                                   GLenum internalformat,
+                                                   GLsizei width,
+                                                   GLsizei height) override;
 void glRenderbufferStorageMultisampleEXTFn(GLenum target,
                                            GLsizei samples,
                                            GLenum internalformat,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 7c10353..6f84c5d 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -279,6 +279,8 @@
 
 void DriverGL::InitializeDynamicBindings(const GLVersionInfo* ver,
                                          const gfx::ExtensionSet& extensions) {
+  ext.b_GL_AMD_framebuffer_multisample_advanced =
+      gfx::HasExtension(extensions, "GL_AMD_framebuffer_multisample_advanced");
   ext.b_GL_ANGLE_framebuffer_blit =
       gfx::HasExtension(extensions, "GL_ANGLE_framebuffer_blit");
   ext.b_GL_ANGLE_framebuffer_multisample =
@@ -2245,6 +2247,12 @@
             GetGLProcAddress("glRenderbufferStorageMultisampleEXT"));
   }
 
+  if (ext.b_GL_AMD_framebuffer_multisample_advanced) {
+    fn.glRenderbufferStorageMultisampleAdvancedAMDFn =
+        reinterpret_cast<glRenderbufferStorageMultisampleAdvancedAMDProc>(
+            GetGLProcAddress("glRenderbufferStorageMultisampleAdvancedAMD"));
+  }
+
   if (ext.b_GL_EXT_multisampled_render_to_texture) {
     fn.glRenderbufferStorageMultisampleEXTFn =
         reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
@@ -4991,6 +4999,17 @@
                                                  internalformat, width, height);
 }
 
+void GLApiBase::glRenderbufferStorageMultisampleAdvancedAMDFn(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  driver_->fn.glRenderbufferStorageMultisampleAdvancedAMDFn(
+      target, samples, storageSamples, internalformat, width, height);
+}
+
 void GLApiBase::glRenderbufferStorageMultisampleEXTFn(GLenum target,
                                                       GLsizei samples,
                                                       GLenum internalformat,
@@ -8477,6 +8496,19 @@
                                               width, height);
 }
 
+void TraceGLApi::glRenderbufferStorageMultisampleAdvancedAMDFn(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  TRACE_EVENT_BINARY_EFFICIENT0(
+      "gpu", "TraceGLAPI::glRenderbufferStorageMultisampleAdvancedAMD")
+  gl_api_->glRenderbufferStorageMultisampleAdvancedAMDFn(
+      target, samples, storageSamples, internalformat, width, height);
+}
+
 void TraceGLApi::glRenderbufferStorageMultisampleEXTFn(GLenum target,
                                                        GLsizei samples,
                                                        GLenum internalformat,
@@ -12944,6 +12976,22 @@
                                               width, height);
 }
 
+void DebugGLApi::glRenderbufferStorageMultisampleAdvancedAMDFn(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  GL_SERVICE_LOG("glRenderbufferStorageMultisampleAdvancedAMD"
+                 << "(" << GLEnums::GetStringEnum(target) << ", " << samples
+                 << ", " << storageSamples << ", "
+                 << GLEnums::GetStringEnum(internalformat) << ", " << width
+                 << ", " << height << ")");
+  gl_api_->glRenderbufferStorageMultisampleAdvancedAMDFn(
+      target, samples, storageSamples, internalformat, width, height);
+}
+
 void DebugGLApi::glRenderbufferStorageMultisampleEXTFn(GLenum target,
                                                        GLsizei samples,
                                                        GLenum internalformat,
@@ -16419,6 +16467,16 @@
   NoContextHelper("glRenderbufferStorageMultisample");
 }
 
+void NoContextGLApi::glRenderbufferStorageMultisampleAdvancedAMDFn(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  NoContextHelper("glRenderbufferStorageMultisampleAdvancedAMD");
+}
+
 void NoContextGLApi::glRenderbufferStorageMultisampleEXTFn(
     GLenum target,
     GLsizei samples,
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index ae8ec77b7..79a7465 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -1303,6 +1303,13 @@
     GLenum internalformat,
     GLsizei width,
     GLsizei height);
+typedef void(GL_BINDING_CALL* glRenderbufferStorageMultisampleAdvancedAMDProc)(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height);
 typedef void(GL_BINDING_CALL* glRenderbufferStorageMultisampleEXTProc)(
     GLenum target,
     GLsizei samples,
@@ -1777,6 +1784,7 @@
                                                          const GLint* box);
 
 struct ExtensionsGL {
+  bool b_GL_AMD_framebuffer_multisample_advanced;
   bool b_GL_ANGLE_framebuffer_blit;
   bool b_GL_ANGLE_framebuffer_multisample;
   bool b_GL_ANGLE_instanced_arrays;
@@ -2214,6 +2222,8 @@
   glReleaseShaderCompilerProc glReleaseShaderCompilerFn;
   glRenderbufferStorageEXTProc glRenderbufferStorageEXTFn;
   glRenderbufferStorageMultisampleProc glRenderbufferStorageMultisampleFn;
+  glRenderbufferStorageMultisampleAdvancedAMDProc
+      glRenderbufferStorageMultisampleAdvancedAMDFn;
   glRenderbufferStorageMultisampleEXTProc glRenderbufferStorageMultisampleEXTFn;
   glRequestExtensionANGLEProc glRequestExtensionANGLEFn;
   glResumeTransformFeedbackProc glResumeTransformFeedbackFn;
@@ -3489,6 +3499,13 @@
                                                   GLenum internalformat,
                                                   GLsizei width,
                                                   GLsizei height) = 0;
+  virtual void glRenderbufferStorageMultisampleAdvancedAMDFn(
+      GLenum target,
+      GLsizei samples,
+      GLsizei storageSamples,
+      GLenum internalformat,
+      GLsizei width,
+      GLsizei height) = 0;
   virtual void glRenderbufferStorageMultisampleEXTFn(GLenum target,
                                                      GLsizei samples,
                                                      GLenum internalformat,
@@ -4421,6 +4438,8 @@
   ::gl::g_current_gl_context->glRenderbufferStorageEXTFn
 #define glRenderbufferStorageMultisample \
   ::gl::g_current_gl_context->glRenderbufferStorageMultisampleFn
+#define glRenderbufferStorageMultisampleAdvancedAMD \
+  ::gl::g_current_gl_context->glRenderbufferStorageMultisampleAdvancedAMDFn
 #define glRenderbufferStorageMultisampleEXT \
   ::gl::g_current_gl_context->glRenderbufferStorageMultisampleEXTFn
 #define glRequestExtensionANGLE \
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index 3f011b2..b56817f 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -3656,6 +3656,19 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glRenderbufferStorageMultisampleAdvancedAMD(
+    GLenum target,
+    GLsizei samples,
+    GLsizei storageSamples,
+    GLenum internalformat,
+    GLsizei width,
+    GLsizei height) {
+  MakeGlMockFunctionUnique("glRenderbufferStorageMultisampleAdvancedAMD");
+  interface_->RenderbufferStorageMultisampleAdvancedAMD(
+      target, samples, storageSamples, internalformat, width, height);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glRenderbufferStorageMultisampleEXT(GLenum target,
                                                           GLsizei samples,
                                                           GLenum internalformat,
@@ -5894,6 +5907,9 @@
   if (strcmp(name, "glRenderbufferStorageMultisampleANGLE") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glRenderbufferStorageMultisampleANGLE);
+  if (strcmp(name, "glRenderbufferStorageMultisampleAdvancedAMD") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glRenderbufferStorageMultisampleAdvancedAMD);
   if (strcmp(name, "glRenderbufferStorageMultisampleEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glRenderbufferStorageMultisampleEXT);
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index 1ebfffcf..de9e8ea 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -1563,6 +1563,13 @@
                                            GLsizei width,
                                            GLsizei height);
 static void GL_BINDING_CALL
+Mock_glRenderbufferStorageMultisampleAdvancedAMD(GLenum target,
+                                                 GLsizei samples,
+                                                 GLsizei storageSamples,
+                                                 GLenum internalformat,
+                                                 GLsizei width,
+                                                 GLsizei height);
+static void GL_BINDING_CALL
 Mock_glRenderbufferStorageMultisampleEXT(GLenum target,
                                          GLsizei samples,
                                          GLenum internalformat,
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index a0dcae6..a016fdf 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -1100,6 +1100,13 @@
                   GLenum internalformat,
                   GLsizei width,
                   GLsizei height));
+MOCK_METHOD6(RenderbufferStorageMultisampleAdvancedAMD,
+             void(GLenum target,
+                  GLsizei samples,
+                  GLsizei storageSamples,
+                  GLenum internalformat,
+                  GLsizei width,
+                  GLsizei height));
 MOCK_METHOD5(RenderbufferStorageMultisampleEXT,
              void(GLenum target,
                   GLsizei samples,
diff --git a/ui/gl/gl_stub_autogen_gl.h b/ui/gl/gl_stub_autogen_gl.h
index 769f9bfa..83e0ce1 100644
--- a/ui/gl/gl_stub_autogen_gl.h
+++ b/ui/gl/gl_stub_autogen_gl.h
@@ -1129,6 +1129,12 @@
                                         GLenum internalformat,
                                         GLsizei width,
                                         GLsizei height) override {}
+void glRenderbufferStorageMultisampleAdvancedAMDFn(GLenum target,
+                                                   GLsizei samples,
+                                                   GLsizei storageSamples,
+                                                   GLenum internalformat,
+                                                   GLsizei width,
+                                                   GLsizei height) override {}
 void glRenderbufferStorageMultisampleEXTFn(GLenum target,
                                            GLsizei samples,
                                            GLenum internalformat,
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index b5025f3..fbb5106 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -1021,8 +1021,7 @@
     for (auto* item : action_buttons_)
       delete item;
     action_buttons_.clear();
-    if (buttons.empty())
-      actions_row_->SetVisible(false);
+    actions_row_->SetVisible(expanded_ && !buttons.empty());
   }
 
   DCHECK_EQ(this, actions_row_->parent());
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
index bccfaad..dad0e37 100644
--- a/ui/message_center/views/notification_view_md_unittest.cc
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -461,13 +461,24 @@
 
 TEST_F(NotificationViewMDTest, UpdateButtonsStateTest) {
   std::unique_ptr<Notification> notification = CreateSimpleNotification();
-  notification->set_buttons(CreateButtons(2));
   notification_view()->CreateOrUpdateViews(*notification);
   widget()->Show();
 
-  // Action buttons are hidden by collapsed state.
-  if (!notification_view()->expanded_)
-    notification_view()->ToggleExpanded();
+  // When collapsed, new buttons are not shown.
+  EXPECT_FALSE(notification_view()->expanded_);
+  notification->set_buttons(CreateButtons(2));
+  notification_view()->CreateOrUpdateViews(*notification);
+  EXPECT_FALSE(notification_view()->actions_row_->visible());
+
+  // Adding buttons when expanded makes action buttons visible.
+  // Reset back to zero buttons first.
+  notification->set_buttons(CreateButtons(0));
+  notification_view()->CreateOrUpdateViews(*notification);
+  // Expand, and add buttons.
+  notification_view()->ToggleExpanded();
+  EXPECT_TRUE(notification_view()->expanded_);
+  notification->set_buttons(CreateButtons(2));
+  notification_view()->CreateOrUpdateViews(*notification);
   EXPECT_TRUE(notification_view()->actions_row_->visible());
 
   EXPECT_EQ(views::Button::STATE_NORMAL,
diff --git a/ui/native_theme/caption_style.cc b/ui/native_theme/caption_style.cc
index 4a94a07..a7c9155 100644
--- a/ui/native_theme/caption_style.cc
+++ b/ui/native_theme/caption_style.cc
@@ -16,7 +16,7 @@
 // static
 CaptionStyle CaptionStyle::FromSpec(const std::string& spec) {
   CaptionStyle style;
-  std::unique_ptr<base::Value> dict = base::JSONReader::Read(spec);
+  std::unique_ptr<base::Value> dict = base::JSONReader::ReadDeprecated(spec);
 
   if (!dict || !dict->is_dict())
     return style;
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc
index bb0f179..6d55fbd2 100644
--- a/ui/views/animation/ink_drop_host_view.cc
+++ b/ui/views/animation/ink_drop_host_view.cc
@@ -113,8 +113,32 @@
   DISALLOW_COPY_AND_ASSIGN(InkDropEventHandler);
 };
 
+class InkDropHostView::InkDropViewObserver : public ViewObserver {
+ public:
+  explicit InkDropViewObserver(InkDropHostView* parent) : parent_(parent) {
+    parent_->AddObserver(this);
+  }
+  ~InkDropViewObserver() override { parent_->RemoveObserver(this); }
+  // ViewObserver:
+  void OnViewFocused(View* observed_view) override {
+    DCHECK_EQ(parent_, observed_view);
+    parent_->GetInkDrop()->SetFocused(true);
+  }
+
+  void OnViewBlurred(View* observed_view) override {
+    DCHECK_EQ(parent_, observed_view);
+    parent_->GetInkDrop()->SetFocused(false);
+  }
+
+ private:
+  InkDropHostView* const parent_;
+
+  DISALLOW_COPY_AND_ASSIGN(InkDropViewObserver);
+};
+
 InkDropHostView::InkDropHostView()
-    : ink_drop_event_handler_(std::make_unique<InkDropEventHandler>(this)) {}
+    : ink_drop_event_handler_(std::make_unique<InkDropEventHandler>(this)),
+      ink_drop_view_observer_(std::make_unique<InkDropViewObserver>(this)) {}
 
 InkDropHostView::~InkDropHostView() {
   // TODO(bruthig): Improve InkDropImpl to be safer about calling back to
@@ -227,16 +251,6 @@
   }
 }
 
-void InkDropHostView::OnFocus() {
-  views::View::OnFocus();
-  GetInkDrop()->SetFocused(true);
-}
-
-void InkDropHostView::OnBlur() {
-  views::View::OnBlur();
-  GetInkDrop()->SetFocused(false);
-}
-
 std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() {
   auto ink_drop = std::make_unique<InkDropImpl>(this, size());
   ink_drop->SetAutoHighlightMode(
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h
index b137d7f..4e20d53 100644
--- a/ui/views/animation/ink_drop_host_view.h
+++ b/ui/views/animation/ink_drop_host_view.h
@@ -131,8 +131,6 @@
       const ViewHierarchyChangedDetails& details) override;
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   void VisibilityChanged(View* starting_from, bool is_visible) override;
-  void OnFocus() override;
-  void OnBlur() override;
 
   // Returns an InkDropImpl suitable for use with a square ink drop.
   // TODO(pbos): Rename to CreateDefaultSquareInkDropImpl.
@@ -190,6 +188,7 @@
 
  private:
   class InkDropEventHandler;
+  class InkDropViewObserver;
   friend class test::InkDropHostViewTestApi;
 
   // The last user Event to trigger an ink drop ripple animation.
@@ -205,6 +204,9 @@
   // destroyed |ink_drop_| during destruction.
   const std::unique_ptr<InkDropEventHandler> ink_drop_event_handler_;
 
+  // Used to observe changes to the host through the ViewObserver API.
+  const std::unique_ptr<InkDropViewObserver> ink_drop_view_observer_;
+
   float ink_drop_visible_opacity_ = 0.175f;
 
   // TODO(pbos): Audit call sites to make sure highlight opacity is either