diff --git a/AUTHORS b/AUTHORS
index 4aa4985..2cf360e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -961,6 +961,7 @@
 Rajesh Mahindra <rmahindra@uber.com>
 Yuan-Pin Yu <yjames@uber.com>
 Vinoth Chandar <vinoth@uber.com>
+Zheng Xu <zxu@kobo.com>
 
 ACCESS CO., LTD. <*@access-company.com>
 Akamai Inc. <*@akamai.com>
@@ -992,6 +993,8 @@
 NVIDIA Corporation <*@nvidia.com>
 Opera Software ASA <*@opera.com>
 Optical Tone Ltd <*@opticaltone.com>
+Rakuten Kobo Inc. <*@kobo.com>
+Rakuten Kobo Inc. <*@rakuten.com>
 Seznam.cz, a.s. <*@firma.seznam.cz>
 Spotify AB <*@spotify.com>
 Tableau Software <*@tableau.com>
diff --git a/BUILD.gn b/BUILD.gn
index 8a54f3b7..036f1213 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -752,11 +752,13 @@
   # TODO(https://crbug.com/731217): This can't practically be in //v8 without
   # duplicating all the Fuchsia running infrastructure there.
   fuchsia_package("d8_fuchsia_pkg") {
+    testonly = true
     binary = "//v8:d8"
     package_name_override = "d8"
   }
 
   fuchsia_package_runner("d8_fuchsia") {
+    testonly = true
     package = ":d8_fuchsia_pkg"
     package_name_override = "d8"
   }
diff --git a/DEPS b/DEPS
index 30600a4..64670fe 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,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': 'e70aed7066c6870d60e39e84b53d037a28ee1204',
+  'skia_revision': 'b8e125281d50bf8f73086f02fccd328bab30ece6',
   # 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': '6ba24e678a0508e3b6c745a9a436ae96a78d1c15',
+  'v8_revision': '800d2a53713d2efa6ab7094709b745ed40606ad4',
   # 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.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '5c86fd4c5110a99606316721786f1ba9bf0d855a',
+  'pdfium_revision': '987416db22712d0b5c666be08a148946ce4b9bdb',
   # 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.
@@ -165,7 +165,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': '134ee369521c676229d0c4c38a96fb54a5ab4967',
+  'catapult_revision': 'd64f0324b3984c26c798bc6953234f99a20b145f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -213,7 +213,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.
-  'spv_tools_revision': '324be76b9c4c09a2d6d819082773781b7cf88650',
+  'spv_tools_revision': '0f4c772ee29010c9d09fb61b3ec633e662ae98ad',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -584,7 +584,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'eb5e205de2f376e4a69512b96aa358fe25a32c5d',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '6d7245a03cbbe4e16b198891ee43be203a6633ba',
       'condition': 'checkout_linux',
   },
 
@@ -1098,7 +1098,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7ca87fb1d3da3b3d2060886e8c58e726d74c8219',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '640106e1ce35699e463fb5070f4aba2fea4beaff',
+    Var('webrtc_git') + '/src.git' + '@' + 'afc3eb1a7347970577d0e09a36484ef8af8f7756',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1129,7 +1129,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@55c4417fbeca10e2cf0be10b97d77cb85e7402f6',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@02581c24f71d706a41a355ad85a2818082562d02',
     'condition': 'checkout_src_internal',
   },
 
@@ -1652,6 +1652,17 @@
       'dep_type': 'cipd',
   },
 
+  'src/third_party/android_deps/libs/com_google_code_findbugs_jsr305': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_code_findbugs_jsr305',
+              'version': 'version:1.3.9-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
   'src/third_party/android_deps/libs/com_google_dagger_dagger': {
       'packages': [
           {
@@ -1686,15 +1697,26 @@
   },
 
   'src/third_party/android_deps/libs/com_google_dagger_dagger_spi': {
-        'packages': [
-            {
-                'package': 'chromium/third_party/android_deps/libs/com_google_dagger_dagger_spi',
-                'version': 'version:2.17-cr0',
-            },
-        ],
-        'condition': 'checkout_android',
-        'dep_type': 'cipd',
-    },
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_dagger_dagger_spi',
+              'version': 'version:2.17-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations',
+              'version': 'version:2.1.3-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
 
   'src/third_party/android_deps/libs/com_google_errorprone_javac_shaded': {
       'packages': [
@@ -1722,7 +1744,18 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_guava_guava',
-              'version': 'version:25.0-cr0',
+              'version': 'version:25.0-jre-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations',
+              'version': 'version:1.1-cr0',
           },
       ],
       'condition': 'checkout_android',
@@ -1752,15 +1785,37 @@
   },
 
   'src/third_party/android_deps/libs/javax_inject_javax_inject': {
-        'packages': [
-            {
-                'package': 'chromium/third_party/android_deps/libs/javax_inject_javax_inject',
-                'version': 'version:1-cr0',
-            },
-        ],
-        'condition': 'checkout_android',
-        'dep_type': 'cipd',
-    },
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/javax_inject_javax_inject',
+              'version': 'version:1-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/libs/org_checkerframework_checker_compat_qual': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/org_checkerframework_checker_compat_qual',
+              'version': 'version:2.3.0-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations',
+              'version': 'version:1.14-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
 
   # === ANDROID_DEPS Generated Code End ===
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 7903a35..808f8df 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -2411,6 +2411,17 @@
         mWebContents.evaluateJavaScript(script, jsCallback);
     }
 
+    public void evaluateJavaScriptForTests(String script, final Callback<String> callback) {
+        if (TRACE) Log.i(TAG, "%s evaluateJavascriptForTests=%s", this, script);
+        if (isDestroyedOrNoOperation(NO_WARN)) return;
+        JavaScriptCallback jsCallback = null;
+        if (callback != null) {
+            jsCallback = jsonResult -> callback.onResult(jsonResult);
+        }
+
+        mWebContents.evaluateJavaScriptForTests(script, jsCallback);
+    }
+
     public void postMessageToFrame(
             String frameName, String message, String targetOrigin, MessagePort[] sentPorts) {
         if (isDestroyedOrNoOperation(WARN)) return;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwActivityTestRule.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwActivityTestRule.java
index b330503..314ebe7 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwActivityTestRule.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwActivityTestRule.java
@@ -526,7 +526,7 @@
         TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper =
                 parentAwContentsClient.getOnCreateWindowHelper();
         int currentCallCount = onCreateWindowHelper.getCallCount();
-        parentAwContents.evaluateJavaScript(triggerScript, null);
+        parentAwContents.evaluateJavaScriptForTests(triggerScript, null);
         onCreateWindowHelper.waitForCallback(
                 currentCallCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
     }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
index 1de6089..66000c7 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
@@ -430,7 +430,7 @@
             AwSettings awSettings = awContents.getSettings();
             awSettings.setJavaScriptEnabled(true);
             awContents.addJavascriptInterface(new JavaScriptObject(callback), "bridge");
-            awContents.evaluateJavaScript("window.bridge.run();", null);
+            awContents.evaluateJavaScriptForTests("window.bridge.run();", null);
         });
         callback.waitForCallback(0, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
     }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java
index 3a0e683..466af56a 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java
@@ -76,7 +76,7 @@
                 mActivityTestRule.executeJavaScriptAndWaitForResult(
                         awContents, mContentsClient, "typeof test.destroy"));
         int currentCallCount = client2.getOnPageFinishedHelper().getCallCount();
-        awContents.evaluateJavaScript("test.destroy()", null);
+        awContents.evaluateJavaScriptForTests("test.destroy()", null);
 
         client2.getOnPageFinishedHelper().waitForCallback(currentCallCount);
     }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/GeolocationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/GeolocationTest.java
index 5266e82..9a69a2f9 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/GeolocationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/GeolocationTest.java
@@ -156,11 +156,11 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "https://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_getCurrentPosition();", null);
 
         AwActivityTestRule.pollInstrumentationThread(() -> getPositionCountFromJS() == 1);
 
-        mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_getCurrentPosition();", null);
         AwActivityTestRule.pollInstrumentationThread(() -> getPositionCountFromJS() == 2);
     }
 
@@ -177,7 +177,7 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "https://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_watchPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_watchPosition();", null);
 
         AwActivityTestRule.pollInstrumentationThread(() -> getPositionCountFromJS() > 1);
     }
@@ -192,7 +192,7 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "https://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_watchPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_watchPosition();", null);
 
         AwActivityTestRule.pollInstrumentationThread(() -> getPositionCountFromJS() > 1);
 
@@ -229,7 +229,7 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "https://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_watchPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_watchPosition();", null);
 
         Assert.assertEquals(0, getPositionCountFromJS());
 
@@ -268,7 +268,7 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "https://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_getCurrentPosition();", null);
 
         AwActivityTestRule.pollInstrumentationThread(new Callable<Boolean>() {
             @Override
@@ -290,7 +290,7 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "http://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_getCurrentPosition();", null);
 
         AwActivityTestRule.pollInstrumentationThread(new Callable<Boolean>() {
             @Override
@@ -310,7 +310,7 @@
                 mContentsClient.getOnPageFinishedHelper(), RAW_HTML, "text/html", false,
                 "http://google.com/", ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
 
-        mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null);
+        mAwContents.evaluateJavaScriptForTests("initiate_getCurrentPosition();", null);
 
         AwActivityTestRule.pollInstrumentationThread(() -> getPositionCountFromJS() > 0);
     }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java b/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
index a7809cc..abb91fba 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
@@ -43,7 +43,7 @@
         }, WAIT_TIMEOUT_MS, CHECK_INTERVAL);
 
         instrumentation.runOnMainSync(
-                () -> awContents.evaluateJavaScript(
+                () -> awContents.getWebContents().evaluateJavaScriptForTests(
                         "var evObj = new MouseEvent('click', {bubbles: true});"
                                 + "document.getElementById('" + linkId + "').dispatchEvent(evObj);"
                                 + "console.log('element with id [" + linkId + "] clicked');",
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index e39c043..1e240ea 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -116,7 +116,6 @@
     "//android_webview:common",
     "//components/heap_profiling:test_support",
     "//components/minidump_uploader",
-    "//content/public/test/android:content_native_test_support",
   ]
   configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
   configs += [ "//build/config/android:hide_all_but_jni" ]
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index d8a0a94..fe79d801 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -1642,4 +1642,33 @@
   EXPECT_TRUE(test_helper.GetBackdropWindow());
 }
 
+// Tests that app list is not active when switching to tablet mode if an active
+// window exists.
+TEST_F(AppListPresenterDelegateHomeLauncherTest,
+       NotActivateAppListWindowWhenActiveWindowExists) {
+  // No window is active.
+  EXPECT_EQ(nullptr, wm::GetActiveWindow());
+
+  // Show app list in tablet mode. It should become active.
+  EnableTabletMode(true);
+  GetAppListTestHelper()->CheckVisibility(true);
+  EXPECT_EQ(GetAppListView()->GetWidget()->GetNativeWindow(),
+            wm::GetActiveWindow());
+
+  // End tablet mode.
+  EnableTabletMode(false);
+  GetAppListTestHelper()->CheckVisibility(false);
+  EXPECT_EQ(nullptr, wm::GetActiveWindow());
+
+  // Activate a window.
+  std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
+  wm::GetWindowState(window.get())->Activate();
+  EXPECT_EQ(window.get(), wm::GetActiveWindow());
+
+  // Show app list in tablet mode. It should not be active.
+  EnableTabletMode(true);
+  GetAppListTestHelper()->CheckVisibility(true);
+  EXPECT_EQ(window.get(), wm::GetActiveWindow());
+}
+
 }  // namespace ash
diff --git a/ash/app_list/views/app_list_main_view.cc b/ash/app_list/views/app_list_main_view.cc
index 15bce53..d30747f6 100644
--- a/ash/app_list/views/app_list_main_view.cc
+++ b/ash/app_list/views/app_list_main_view.cc
@@ -29,6 +29,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/strings/string_util.h"
 #include "chromeos/chromeos_switches.h"
+#include "ui/aura/window.h"
 #include "ui/chromeos/search_box/search_box_view_base.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/views/border.h"
@@ -37,6 +38,7 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/public/activation_client.h"
 
 namespace app_list {
 
@@ -88,7 +90,16 @@
 }
 
 void AppListMainView::ShowAppListWhenReady() {
-  GetWidget()->Show();
+  // After switching to tablet mode, other app windows may be active. Show the
+  // app list without activating it to avoid breaking other windows' state.
+  const aura::Window* active_window =
+      wm::GetActivationClient(
+          app_list_view_->GetWidget()->GetNativeView()->GetRootWindow())
+          ->GetActiveWindow();
+  if (app_list_view_->IsHomeLauncherEnabledInTabletMode() && active_window)
+    GetWidget()->ShowInactive();
+  else
+    GetWidget()->Show();
 }
 
 void AppListMainView::ResetForShow() {
diff --git a/ash/app_list/views/folder_background_view.cc b/ash/app_list/views/folder_background_view.cc
index 1368483..373afb7 100644
--- a/ash/app_list/views/folder_background_view.cc
+++ b/ash/app_list/views/folder_background_view.cc
@@ -10,7 +10,9 @@
 namespace app_list {
 
 FolderBackgroundView::FolderBackgroundView(AppListFolderView* folder_view)
-    : folder_view_(folder_view) {}
+    : folder_view_(folder_view) {
+  SetPaintToLayer();
+}
 
 FolderBackgroundView::~FolderBackgroundView() = default;
 
diff --git a/ash/public/cpp/resources/unscaled_resources/camera_logo_192.png b/ash/public/cpp/resources/unscaled_resources/camera_logo_192.png
index e5ce51e..c5603807 100644
--- a/ash/public/cpp/resources/unscaled_resources/camera_logo_192.png
+++ b/ash/public/cpp/resources/unscaled_resources/camera_logo_192.png
Binary files differ
diff --git a/ash/public/cpp/resources/unscaled_resources/discover_app_logo_192.png b/ash/public/cpp/resources/unscaled_resources/discover_app_logo_192.png
index 2be47235..6d690c34 100644
--- a/ash/public/cpp/resources/unscaled_resources/discover_app_logo_192.png
+++ b/ash/public/cpp/resources/unscaled_resources/discover_app_logo_192.png
Binary files differ
diff --git a/ash/public/cpp/resources/unscaled_resources/settings_logo_192.png b/ash/public/cpp/resources/unscaled_resources/settings_logo_192.png
index be98c3ce..bd3521a 100644
--- a/ash/public/cpp/resources/unscaled_resources/settings_logo_192.png
+++ b/ash/public/cpp/resources/unscaled_resources/settings_logo_192.png
Binary files differ
diff --git a/ash/public/cpp/resources/unscaled_resources/shortcut_viewer_logo_192.png b/ash/public/cpp/resources/unscaled_resources/shortcut_viewer_logo_192.png
index d38af0c..301341f 100644
--- a/ash/public/cpp/resources/unscaled_resources/shortcut_viewer_logo_192.png
+++ b/ash/public/cpp/resources/unscaled_resources/shortcut_viewer_logo_192.png
Binary files differ
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 7e594a2..82f4fa61 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -733,9 +733,11 @@
   generic_allocator.root()->Free(ptr3);
   generic_allocator.root()->Free(ptr4);
 
+#if DCHECK_IS_ON()
   // |PartitionPage::Free| must poison the slot's contents with |kFreedByte|.
   EXPECT_EQ(kFreedByte,
             *(reinterpret_cast<unsigned char*>(new_ptr) + (size - 1)));
+#endif
 
   // Can we allocate a massive (512MB) size?
   // Allocate 512MB, but +1, to test for cookie writing alignment issues.
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 2182b8c..3b15b2d 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -209,13 +209,9 @@
   PartitionCookieCheckValue(ptr);
   PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + slot_size -
                             kCookieSize);
-#endif
 
-  // Perhaps surprisingly, this does not measurably regress performance. See
-  // https://crbug.com/680657 for history. We formerly did this in
-  // |PartitionFree|, and in `DCHECK_IS_ON()` builds we redundantly did it
-  // here, too. Now we only do it here, unconditionally.
   memset(ptr, kFreedByte, slot_size);
+#endif
 
   DCHECK(this->num_allocated_slots);
   // TODO(palmer): See if we can afford to make this a CHECK.
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java
index e13fbbf..7448286 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java
@@ -9,6 +9,7 @@
 import android.app.job.JobScheduler;
 import android.content.ClipData;
 import android.graphics.Bitmap;
+import android.media.MediaCodec.CryptoInfo;
 import android.os.Build;
 import android.view.PointerIcon;
 import android.view.View;
@@ -58,4 +59,9 @@
     public static PointerIcon createPointerIcon(Bitmap bitmap, float width, float height) {
         return PointerIcon.create(bitmap, width, height);
     }
+
+    /** See {@link CryptoInfo#setPattern(Pattern)}. */
+    public static void setCryptoInfoPattern(CryptoInfo cryptoInfo, int encrypt, int skip) {
+        cryptoInfo.setPattern(new CryptoInfo.Pattern(encrypt, skip));
+    }
 }
diff --git a/base/memory/platform_shared_memory_region.h b/base/memory/platform_shared_memory_region.h
index a1ae8bb1b..1bf09e9 100644
--- a/base/memory/platform_shared_memory_region.h
+++ b/base/memory/platform_shared_memory_region.h
@@ -92,6 +92,22 @@
     kMaxValue = kUnsafe
   };
 
+  // Errors that can occur during Shared Memory construction.
+  // These match tools/metrics/histograms/enums.xml.
+  // This enum is append-only.
+  enum class CreateError {
+    SUCCESS = 0,
+    SIZE_ZERO = 1,
+    SIZE_TOO_LARGE = 2,
+    INITIALIZE_ACL_FAILURE = 3,
+    INITIALIZE_SECURITY_DESC_FAILURE = 4,
+    SET_SECURITY_DESC_FAILURE = 5,
+    CREATE_FILE_MAPPING_FAILURE = 6,
+    REDUCE_PERMISSIONS_FAILURE = 7,
+    ALREADY_EXISTS = 8,
+    kMaxValue = ALREADY_EXISTS
+  };
+
 // Platform-specific shared memory type used by this class.
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   using PlatformHandle = mach_port_t;
diff --git a/base/memory/platform_shared_memory_region_mac.cc b/base/memory/platform_shared_memory_region_mac.cc
index 227b5e76..764de306 100644
--- a/base/memory/platform_shared_memory_region_mac.cc
+++ b/base/memory/platform_shared_memory_region_mac.cc
@@ -8,6 +8,8 @@
 
 #include "base/mac/mach_logging.h"
 #include "base/mac/scoped_mach_vm.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/numerics/checked_math.h"
 #include "build/build_config.h"
 
@@ -18,6 +20,17 @@
 namespace base {
 namespace subtle {
 
+namespace {
+
+void LogCreateError(PlatformSharedMemoryRegion::CreateError error,
+                    kern_return_t mac_error) {
+  UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error);
+  if (mac_error != KERN_SUCCESS)
+    UmaHistogramSparse("SharedMemory.CreateMacError", mac_error);
+}
+
+}  // namespace
+
 // static
 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
     mac::ScopedMachSendRight handle,
@@ -176,11 +189,15 @@
 // static
 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
                                                               size_t size) {
-  if (size == 0)
+  if (size == 0) {
+    LogCreateError(CreateError::SIZE_ZERO, KERN_SUCCESS);
     return {};
+  }
 
-  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    LogCreateError(CreateError::SIZE_TOO_LARGE, KERN_SUCCESS);
     return {};
+  }
 
   CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
                                      "lead to this region being non-modifiable";
@@ -193,11 +210,14 @@
       MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE,
       named_right.receive(),
       MACH_PORT_NULL);  // Parent handle.
+  if (kr != KERN_SUCCESS)
+    LogCreateError(CreateError::CREATE_FILE_MAPPING_FAILURE, kr);
   // Crash as soon as shm allocation fails to debug the issue
   // https://crbug.com/872237.
   MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_make_memory_entry_64";
   DCHECK_GE(vm_size, size);
 
+  LogCreateError(CreateError::SUCCESS, KERN_SUCCESS);
   return PlatformSharedMemoryRegion(std::move(named_right), mode, size,
                                     UnguessableToken::Create());
 }
diff --git a/base/memory/platform_shared_memory_region_unittest.cc b/base/memory/platform_shared_memory_region_unittest.cc
index d04428f..2bedb75 100644
--- a/base/memory/platform_shared_memory_region_unittest.cc
+++ b/base/memory/platform_shared_memory_region_unittest.cc
@@ -235,7 +235,9 @@
                      return region.start == reinterpret_cast<uintptr_t>(addr);
                    });
   ASSERT_TRUE(it != regions.end());
-  EXPECT_EQ(it->permissions, base::debug::MappedMemoryRegion::READ);
+  // PROT_READ may imply PROT_EXEC on some architectures, so just check that
+  // permissions don't contain PROT_WRITE bit.
+  EXPECT_FALSE(it->permissions & base::debug::MappedMemoryRegion::WRITE);
 #elif defined(OS_WIN)
   MEMORY_BASIC_INFORMATION memory_info;
   size_t result = VirtualQueryEx(GetCurrentProcess(), addr, &memory_info,
@@ -271,7 +273,7 @@
 }
 
 // Tests that protection bits are set correctly for read-only region.
-TEST_F(PlatformSharedMemoryRegionTest, DISABLED_MappingProtectionSetCorrectly) {
+TEST_F(PlatformSharedMemoryRegionTest, MappingProtectionSetCorrectly) {
   PlatformSharedMemoryRegion region =
       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
   ASSERT_TRUE(region.IsValid());
diff --git a/base/memory/platform_shared_memory_region_win.cc b/base/memory/platform_shared_memory_region_win.cc
index 5eec9c7..c300101 100644
--- a/base/memory/platform_shared_memory_region_win.cc
+++ b/base/memory/platform_shared_memory_region_win.cc
@@ -23,27 +23,10 @@
 
 namespace {
 
-// Errors that can occur during Shared Memory construction.
-// These match tools/metrics/histograms/histograms.xml.
-// This enum is append-only.
-enum CreateError {
-  SUCCESS = 0,
-  SIZE_ZERO = 1,
-  SIZE_TOO_LARGE = 2,
-  INITIALIZE_ACL_FAILURE = 3,
-  INITIALIZE_SECURITY_DESC_FAILURE = 4,
-  SET_SECURITY_DESC_FAILURE = 5,
-  CREATE_FILE_MAPPING_FAILURE = 6,
-  REDUCE_PERMISSIONS_FAILURE = 7,
-  ALREADY_EXISTS = 8,
-  CREATE_ERROR_LAST = ALREADY_EXISTS
-};
-
 // Emits UMA metrics about encountered errors. Pass zero (0) for |winerror|
 // if there is no associated Windows error.
-void LogError(CreateError error, DWORD winerror) {
-  UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error,
-                            CREATE_ERROR_LAST + 1);
+void LogError(PlatformSharedMemoryRegion::CreateError error, DWORD winerror) {
+  UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error);
   static_assert(ERROR_SUCCESS == 0, "Windows error code changed!");
   if (winerror != ERROR_SUCCESS)
     UmaHistogramSparse("SharedMemory.CreateWinError", winerror);
@@ -112,7 +95,9 @@
   HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
                                static_cast<DWORD>(rounded_size), name);
   if (!h) {
-    LogError(CREATE_FILE_MAPPING_FAILURE, GetLastError());
+    LogError(
+        PlatformSharedMemoryRegion::CreateError::CREATE_FILE_MAPPING_FAILURE,
+        GetLastError());
     return nullptr;
   }
 
@@ -125,7 +110,9 @@
   DCHECK(rv);
 
   if (!success) {
-    LogError(REDUCE_PERMISSIONS_FAILURE, GetLastError());
+    LogError(
+        PlatformSharedMemoryRegion::CreateError::REDUCE_PERMISSIONS_FAILURE,
+        GetLastError());
     return nullptr;
   }
 
@@ -272,13 +259,13 @@
   // per mapping on average.
   static const size_t kSectionSize = 65536;
   if (size == 0) {
-    LogError(SIZE_ZERO, 0);
+    LogError(CreateError::SIZE_ZERO, 0);
     return {};
   }
 
   size_t rounded_size = bits::Align(size, kSectionSize);
   if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
-    LogError(SIZE_TOO_LARGE, 0);
+    LogError(CreateError::SIZE_TOO_LARGE, 0);
     return {};
   }
 
@@ -289,15 +276,15 @@
   ACL dacl;
   SECURITY_DESCRIPTOR sd;
   if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
-    LogError(INITIALIZE_ACL_FAILURE, GetLastError());
+    LogError(CreateError::INITIALIZE_ACL_FAILURE, GetLastError());
     return {};
   }
   if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
-    LogError(INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
+    LogError(CreateError::INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
     return {};
   }
   if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
-    LogError(SET_SECURITY_DESC_FAILURE, GetLastError());
+    LogError(CreateError::SET_SECURITY_DESC_FAILURE, GetLastError());
     return {};
   }
 
@@ -327,10 +314,11 @@
   win::ScopedHandle scoped_h(h);
   // Check if the shared memory pre-exists.
   if (GetLastError() == ERROR_ALREADY_EXISTS) {
-    LogError(ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
+    LogError(CreateError::ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
     return {};
   }
 
+  LogError(CreateError::SUCCESS, ERROR_SUCCESS);
   return PlatformSharedMemoryRegion(std::move(scoped_h), mode, size,
                                     UnguessableToken::Create());
 }
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 2ea1f88..9352fdd3c 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -157,6 +157,8 @@
 
 HistogramBase* Histogram::Factory::Build() {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
+  const bool found = (histogram != nullptr);
+  debug::Alias(&found);
   if (!histogram) {
     // TODO(gayane): |HashMetricName()| is called again in Histogram
     // constructor. Refactor code to avoid the additional call.
@@ -240,6 +242,37 @@
                        static_cast<Sample>(HashMetricName(name_)));
     DLOG(ERROR) << "Histogram " << name_
                 << " has mismatched construction arguments";
+
+// crbug.com/836238: Temporarily create crashes for this condition in order
+// to find out why it is happening for many metrics that are hard-coded and
+// thus should never have a mismatch.
+// TODO(bcwhite): Revert this once some crashes have been collected.
+#if defined(OS_WIN)  // Only Windows has a debugger that makes this useful.
+    // Create local copies of the parameters to be sure they'll be available
+    // in the crash dump for the debugger to see.
+    const Histogram* h = static_cast<Histogram*>(histogram);
+    Sample hash_32 = static_cast<Sample>(HashMetricName(name_));
+    debug::Alias(&hash_32);
+    DEBUG_ALIAS_FOR_CSTR(new_name, name_.c_str(), 100);
+    HistogramType new_type = histogram_type_;
+    Sample new_min = minimum_;
+    Sample new_max = maximum_;
+    uint32_t new_count = bucket_count_;
+    debug::Alias(&new_type);
+    debug::Alias(&new_min);
+    debug::Alias(&new_max);
+    debug::Alias(&new_count);
+    DEBUG_ALIAS_FOR_CSTR(old_name, h->histogram_name(), 100);
+    HistogramType old_type = h->GetHistogramType();
+    Sample old_min = h->declared_min();
+    Sample old_max = h->declared_max();
+    uint32_t old_count = h->bucket_count();
+    debug::Alias(&old_type);
+    debug::Alias(&old_min);
+    debug::Alias(&old_max);
+    debug::Alias(&old_count);
+    CHECK(false) << name_;
+#endif
     return DummyHistogram::GetInstance();
   }
   return histogram;
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index e516acb..f142298 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -653,6 +653,7 @@
   EXPECT_FALSE(iter.SkipBytes(1));
 }
 
+#if 0  // TODO(crbug.com/836238): Temporarily disabled for field crash test.
 TEST_P(HistogramTest, BadConstruction) {
   HistogramBase* histogram = Histogram::FactoryGet(
       "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
@@ -678,6 +679,7 @@
       "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags);
   EXPECT_EQ(DummyHistogram::GetInstance(), bad_histogram);
 }
+#endif
 
 TEST_P(HistogramTest, FactoryTime) {
   const int kTestCreateCount = 1 << 14;  // Must be power-of-2.
diff --git a/base/metrics/single_sample_metrics_unittest.cc b/base/metrics/single_sample_metrics_unittest.cc
index d4d5913..cca7514 100644
--- a/base/metrics/single_sample_metrics_unittest.cc
+++ b/base/metrics/single_sample_metrics_unittest.cc
@@ -81,6 +81,7 @@
   // Verify only the last sample sent to SetSample() is recorded.
   tester.ExpectUniqueSample(kMetricName, kLastSample, 1);
 
+#if 0  // TODO(crbug.com/836238): Temporarily disabled for field crash test.
   // Verify construction implicitly by requesting a histogram with the same
   // parameters; this test relies on the fact that histogram objects are unique
   // per name. Different parameters will result in a Dummy histogram returned.
@@ -90,6 +91,7 @@
   EXPECT_NE(DummyHistogram::GetInstance(),
             Histogram::FactoryGet(kMetricName, kMin, kMax, kBucketCount,
                                   HistogramBase::kUmaTargetedHistogramFlag));
+#endif
 }
 
 TEST_F(SingleSampleMetricsTest, MultipleMetricsAreDistinct) {
diff --git a/base/task/sequence_manager/sequence_manager.h b/base/task/sequence_manager/sequence_manager.h
index 20e9a704..3d91c26b 100644
--- a/base/task/sequence_manager/sequence_manager.h
+++ b/base/task/sequence_manager/sequence_manager.h
@@ -58,6 +58,12 @@
   // performs this initialization automatically.
   virtual void BindToCurrentThread() = 0;
 
+  // Finishes the initialization for a SequenceManager created via
+  // CreateUnboundSequenceManager(nullptr). Must not be called in any other
+  // circumstances. Note it's assumed |message_loop| outlives the
+  // SequenceManager.
+  virtual void BindToMessageLoop(MessageLoop* message_loop) = 0;
+
   // Initializes the SequenceManager on the bound thread. Should only be called
   // once and only after the ThreadController's dependencies were initialized.
   // Note that CreateSequenceManagerOnCurrentThread() performs this
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc
index 792f6094..810200d 100644
--- a/base/task/sequence_manager/sequence_manager_impl.cc
+++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -148,6 +148,12 @@
           message_loop, DefaultTickClock::GetInstance())));
 }
 
+void SequenceManagerImpl::BindToMessageLoop(MessageLoop* message_loop) {
+  controller_->SetMessageLoop(message_loop);
+  BindToCurrentThread();
+  CompleteInitializationOnBoundThread();
+}
+
 void SequenceManagerImpl::BindToCurrentThread() {
   associated_thread_->BindToCurrentThread();
 }
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h
index 0ee7b78..7b3a68f4 100644
--- a/base/task/sequence_manager/sequence_manager_impl.h
+++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -98,6 +98,7 @@
 
   // SequenceManager implementation:
   void BindToCurrentThread() override;
+  void BindToMessageLoop(MessageLoop* message_loop) override;
   void CompleteInitializationOnBoundThread() override;
   void SetObserver(Observer* observer) override;
   void AddTaskObserver(MessageLoop::TaskObserver* task_observer) override;
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
index 9ccac1eb..094aa5f 100644
--- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc
+++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -3343,6 +3343,31 @@
   thread.Stop();
 }
 
+TEST_P(SequenceManagerTestWithCustomInitialization,
+       SequenceManagerCreatedBeforeMessageLoop) {
+  std::unique_ptr<SequenceManager> manager =
+      CreateUnboundSequenceManager(nullptr);
+  scoped_refptr<TaskQueue> default_task_queue =
+      manager->CreateTaskQueue<TestTaskQueue>(TaskQueue::Spec("default"));
+  EXPECT_THAT(default_task_queue.get(), testing::NotNull());
+
+  std::unique_ptr<MessageLoop> message_loop(new MessageLoop());
+  manager->BindToMessageLoop(message_loop.get());
+
+  // Check that task posting works.
+  std::vector<EnqueueOrder> run_order;
+  default_task_queue->PostTask(FROM_HERE, BindOnce(&TestTask, 1, &run_order));
+  default_task_queue->PostTask(FROM_HERE, BindOnce(&TestTask, 2, &run_order));
+  default_task_queue->PostTask(FROM_HERE, BindOnce(&TestTask, 3, &run_order));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_THAT(run_order, ElementsAre(1u, 2u, 3u));
+
+  // We must release the SequenceManager before the MessageLoop because
+  // SequenceManager assumes the MessageLoop outlives it.
+  manager.reset();
+}
+
 }  // namespace sequence_manager_impl_unittest
 }  // namespace internal
 }  // namespace sequence_manager
diff --git a/base/task/sequence_manager/thread_controller.h b/base/task/sequence_manager/thread_controller.h
index be31660..5827288 100644
--- a/base/task/sequence_manager/thread_controller.h
+++ b/base/task/sequence_manager/thread_controller.h
@@ -13,6 +13,7 @@
 
 namespace base {
 
+class MessageLoop;
 class TickClock;
 struct PendingTask;
 
@@ -67,6 +68,10 @@
   // Has no effect on some platforms.
   virtual void SetTimerSlack(TimerSlack timer_slack) = 0;
 
+  // Completes delayed initialization of a ThreadControllers created with a null
+  // MessageLoop. May only be called once.
+  virtual void SetMessageLoop(MessageLoop* message_loop) = 0;
+
   // TODO(altimin): Get rid of the methods below.
   // These methods exist due to current integration of SequenceManager
   // with MessageLoop.
diff --git a/base/task/sequence_manager/thread_controller_impl.cc b/base/task/sequence_manager/thread_controller_impl.cc
index 7039471..bf696184 100644
--- a/base/task/sequence_manager/thread_controller_impl.cc
+++ b/base/task/sequence_manager/thread_controller_impl.cc
@@ -51,7 +51,8 @@
     MessageLoop* message_loop,
     const TickClock* time_source) {
   return WrapUnique(new ThreadControllerImpl(
-      message_loop, message_loop->task_runner(), time_source));
+      message_loop, message_loop ? message_loop->task_runner() : nullptr,
+      time_source));
 }
 
 void ThreadControllerImpl::SetSequencedTaskSource(
@@ -136,6 +137,9 @@
 
 void ThreadControllerImpl::SetDefaultTaskRunner(
     scoped_refptr<SingleThreadTaskRunner> task_runner) {
+#if DCHECK_IS_ON()
+  default_task_runner_set_ = true;
+#endif
   if (!message_loop_)
     return;
   message_loop_->SetTaskRunner(task_runner);
@@ -147,6 +151,17 @@
   message_loop_->SetTaskRunner(message_loop_task_runner_);
 }
 
+void ThreadControllerImpl::SetMessageLoop(MessageLoop* message_loop) {
+  DCHECK(!message_loop_);
+  DCHECK(message_loop);
+#if DCHECK_IS_ON()
+  DCHECK(!default_task_runner_set_) << "This would undo SetDefaultTaskRunner";
+#endif
+  message_loop_ = message_loop;
+  task_runner_ = message_loop->task_runner();
+  message_loop_task_runner_ = message_loop->task_runner();
+}
+
 void ThreadControllerImpl::WillQueueTask(PendingTask* pending_task) {
   task_annotator_.WillQueueTask("SequenceManager::PostTask", pending_task);
 }
diff --git a/base/task/sequence_manager/thread_controller_impl.h b/base/task/sequence_manager/thread_controller_impl.h
index efa771a3..88ed620 100644
--- a/base/task/sequence_manager/thread_controller_impl.h
+++ b/base/task/sequence_manager/thread_controller_impl.h
@@ -40,6 +40,7 @@
   void SetWorkBatchSize(int work_batch_size) override;
   void WillQueueTask(PendingTask* pending_task) override;
   void ScheduleWork() override;
+  void SetMessageLoop(MessageLoop* message_loop) override;
   void SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) override;
   void SetSequencedTaskSource(SequencedTaskSource* sequence) override;
   void SetTimerSlack(TimerSlack timer_slack) override;
@@ -124,6 +125,10 @@
   SequencedTaskSource* sequence_ = nullptr;  // Not owned.
   debug::TaskAnnotator task_annotator_;
 
+#if DCHECK_IS_ON()
+  bool default_task_runner_set_ = false;
+#endif
+
   WeakPtrFactory<ThreadControllerImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadControllerImpl);
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
index 9483a8d..a488602 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
@@ -43,6 +43,12 @@
   main_thread_only().task_source = task_source;
 }
 
+void ThreadControllerWithMessagePumpImpl::SetMessageLoop(
+    MessageLoop* message_loop) {
+  NOTREACHED()
+      << "ThreadControllerWithMessagePumpImpl doesn't support MessageLoops";
+}
+
 void ThreadControllerWithMessagePumpImpl::SetWorkBatchSize(
     int work_batch_size) {
   DCHECK_GE(work_batch_size, 1);
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
index d69c21f..ea5fcfc 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
@@ -34,6 +34,7 @@
 
   // ThreadController implementation:
   void SetSequencedTaskSource(SequencedTaskSource* task_source) override;
+  void SetMessageLoop(MessageLoop* message_loop) override;
   void SetWorkBatchSize(int work_batch_size) override;
   void WillQueueTask(PendingTask* pending_task) override;
   void ScheduleWork() override;
diff --git a/base/task/task_scheduler/delayed_task_manager.cc b/base/task/task_scheduler/delayed_task_manager.cc
index 76d62e5..2738698 100644
--- a/base/task/task_scheduler/delayed_task_manager.cc
+++ b/base/task/task_scheduler/delayed_task_manager.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/task/post_task.h"
 #include "base/task/task_scheduler/task.h"
 #include "base/task_runner.h"
 
@@ -16,7 +17,10 @@
 
 DelayedTaskManager::DelayedTaskManager(
     std::unique_ptr<const TickClock> tick_clock)
-    : tick_clock_(std::move(tick_clock)) {
+    : process_ripe_tasks_closure_(
+          BindRepeating(&DelayedTaskManager::ProcessRipeTasks,
+                        Unretained(this))),
+      tick_clock_(std::move(tick_clock)) {
   DCHECK(tick_clock_);
 }
 
@@ -26,26 +30,18 @@
     scoped_refptr<TaskRunner> service_thread_task_runner) {
   DCHECK(service_thread_task_runner);
 
-  decltype(tasks_added_before_start_) tasks_added_before_start;
-
+  TimeTicks next_delayed_task_run_time;
   {
-    AutoSchedulerLock auto_lock(lock_);
+    AutoSchedulerLock auto_lock(queue_lock_);
     DCHECK(!service_thread_task_runner_);
-    DCHECK(!started_.IsSet());
     service_thread_task_runner_ = std::move(service_thread_task_runner);
-    tasks_added_before_start = std::move(tasks_added_before_start_);
-    // |service_thread_task_runner_| must not change after |started_| is set
-    // (cf. comment above |lock_| in header file).
-    started_.Set();
+    if (delayed_task_queue_.empty()) {
+      return;
+    }
+    next_delayed_task_run_time = GetNextDelayedTaskRunTimeLockRequired();
+    process_ripe_tasks_time_queue_.push(next_delayed_task_run_time);
   }
-
-  const TimeTicks now = tick_clock_->NowTicks();
-  for (auto& task_and_callback : tasks_added_before_start) {
-    const TimeDelta delay =
-        std::max(TimeDelta(), task_and_callback.first.delayed_run_time - now);
-    AddDelayedTaskNow(std::move(task_and_callback.first), delay,
-                      std::move(task_and_callback.second));
-  }
+  ScheduleProcessRipeTasksOnServiceThread(next_delayed_task_run_time);
 }
 
 void DelayedTaskManager::AddDelayedTask(
@@ -53,42 +49,97 @@
     PostTaskNowCallback post_task_now_callback) {
   DCHECK(task.task);
 
-  const TimeDelta delay = task.delay;
-  DCHECK(!delay.is_zero());
-
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
   // for details.
   CHECK(task.task);
 
-  // If |started_| is set, the DelayedTaskManager is in a stable state and
-  // AddDelayedTaskNow() can be called without synchronization. Otherwise, it is
-  // necessary to acquire |lock_| and recheck.
-  if (started_.IsSet()) {
-    AddDelayedTaskNow(std::move(task), delay,
-                      std::move(post_task_now_callback));
-  } else {
-    AutoSchedulerLock auto_lock(lock_);
-    if (started_.IsSet()) {
-      AddDelayedTaskNow(std::move(task), delay,
-                        std::move(post_task_now_callback));
-    } else {
-      tasks_added_before_start_.push_back(
-          {std::move(task), std::move(post_task_now_callback)});
+  TimeTicks next_delayed_task_run_time;
+  {
+    AutoSchedulerLock auto_lock(queue_lock_);
+    TimeTicks previous_next_delayed_task_run_time =
+        GetNextDelayedTaskRunTimeLockRequired();
+    delayed_task_queue_.push(
+        {std::move(task), std::move(post_task_now_callback)});
+    next_delayed_task_run_time = GetNextDelayedTaskRunTimeLockRequired();
+    // Not started yet.
+    if (service_thread_task_runner_ == nullptr) {
+      return;
     }
+    // ProcessRipeTasks() callback already scheduled before or at |task|'s
+    // scheduled run time.
+    if (GetNextProcessRipeTaskTimeLockRequired() <=
+        next_delayed_task_run_time) {
+      return;
+    }
+    DCHECK_LT(next_delayed_task_run_time, previous_next_delayed_task_run_time);
+    process_ripe_tasks_time_queue_.push(next_delayed_task_run_time);
+  }
+  ScheduleProcessRipeTasksOnServiceThread(next_delayed_task_run_time);
+}
+
+void DelayedTaskManager::ProcessRipeTasks() {
+  std::vector<DelayedTask> ripe_delayed_tasks;
+  TimeTicks next_delayed_task_run_time;
+  bool schedule_process_ripe_tasks = false;
+
+  {
+    AutoSchedulerLock auto_lock(queue_lock_);
+    const TimeTicks now = tick_clock_->NowTicks();
+    while (GetNextDelayedTaskRunTimeLockRequired() <= now) {
+      // The const_cast on top is okay since the DelayedTask is
+      // transactionnaly being popped from |delayed_task_queue_| right after
+      // and the move doesn't alter the sort order (a requirement for the
+      // Windows STL's consistency debug-checks for
+      // std::priority_queue::top()).
+      ripe_delayed_tasks.push_back(
+          std::move(const_cast<DelayedTask&>(delayed_task_queue_.top())));
+      delayed_task_queue_.pop();
+    }
+    while (GetNextProcessRipeTaskTimeLockRequired() <= now) {
+      process_ripe_tasks_time_queue_.pop();
+    }
+    if (!delayed_task_queue_.empty()) {
+      next_delayed_task_run_time = GetNextDelayedTaskRunTimeLockRequired();
+      // ProcessRipeTasks() callback already scheduled before or at the next
+      // task's scheduled run time.
+      if (next_delayed_task_run_time <
+          GetNextProcessRipeTaskTimeLockRequired()) {
+        schedule_process_ripe_tasks = true;
+        process_ripe_tasks_time_queue_.push(next_delayed_task_run_time);
+      }
+    }
+  }
+
+  if (schedule_process_ripe_tasks) {
+    ScheduleProcessRipeTasksOnServiceThread(next_delayed_task_run_time);
+  }
+
+  for (auto& delayed_task : ripe_delayed_tasks) {
+    std::move(delayed_task.second).Run(std::move(delayed_task.first));
   }
 }
 
-void DelayedTaskManager::AddDelayedTaskNow(
-    Task task,
-    TimeDelta delay,
-    PostTaskNowCallback post_task_now_callback) {
-  DCHECK(task.task);
-  DCHECK(started_.IsSet());
-  // TODO(fdoray): Use |task->delayed_run_time| on the service thread
-  // MessageLoop rather than recomputing it from |delay|.
+const TimeTicks DelayedTaskManager::GetNextDelayedTaskRunTimeLockRequired() {
+  queue_lock_.AssertAcquired();
+  return delayed_task_queue_.empty()
+             ? TimeTicks::Max()
+             : delayed_task_queue_.top().first.delayed_run_time;
+}
+
+const TimeTicks DelayedTaskManager::GetNextProcessRipeTaskTimeLockRequired() {
+  queue_lock_.AssertAcquired();
+  return process_ripe_tasks_time_queue_.empty()
+             ? TimeTicks::Max()
+             : process_ripe_tasks_time_queue_.top();
+}
+
+void DelayedTaskManager::ScheduleProcessRipeTasksOnServiceThread(
+    TimeTicks next_delayed_task_run_time) {
+  DCHECK(!next_delayed_task_run_time.is_null());
+  const TimeTicks now = tick_clock_->NowTicks();
+  TimeDelta delay = std::max(TimeDelta(), next_delayed_task_run_time - now);
   service_thread_task_runner_->PostDelayedTask(
-      FROM_HERE, BindOnce(std::move(post_task_now_callback), std::move(task)),
-      delay);
+      FROM_HERE, process_ripe_tasks_closure_, delay);
 }
 
 }  // namespace internal
diff --git a/base/task/task_scheduler/delayed_task_manager.h b/base/task/task_scheduler/delayed_task_manager.h
index 23015a3..4e791a5 100644
--- a/base/task/task_scheduler/delayed_task_manager.h
+++ b/base/task/task_scheduler/delayed_task_manager.h
@@ -6,6 +6,7 @@
 #define BASE_TASK_TASK_SCHEDULER_DELAYED_TASK_MANAGER_H_
 
 #include <memory>
+#include <queue>
 #include <utility>
 #include <vector>
 
@@ -16,6 +17,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/atomic_flag.h"
 #include "base/task/task_scheduler/scheduler_lock.h"
+#include "base/task/task_scheduler/task.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/tick_clock.h"
 
@@ -47,29 +49,56 @@
   void Start(scoped_refptr<TaskRunner> service_thread_task_runner);
 
   // Schedules a call to |post_task_now_callback| with |task| as argument when
-  // |task| is ripe for execution and Start() has been called.
+  // |task| is ripe for execution.
   void AddDelayedTask(Task task, PostTaskNowCallback post_task_now_callback);
 
  private:
-  // Schedules a call to |post_task_now_callback| with |task| as argument when
-  // |delay| expires. Start() must have been called before this.
-  void AddDelayedTaskNow(Task task,
-                         TimeDelta delay,
-                         PostTaskNowCallback post_task_now_callback);
+  using DelayedTask = std::pair<Task, PostTaskNowCallback>;
+
+  // Pop and post all the ripe tasks in the delayed task queue.
+  void ProcessRipeTasks();
+
+  // Return the run time of the delayed task that needs to be processed the
+  // soonest.
+  const TimeTicks GetNextDelayedTaskRunTimeLockRequired();
+
+  // Return the run time of the soonest scheduled `ProcessRipeTasks` call.
+  const TimeTicks GetNextProcessRipeTaskTimeLockRequired();
+
+  // Schedule the ProcessRipeTasks method on the service thread to be executed
+  // in the given |next_delayed_task_run_time|.
+  void ScheduleProcessRipeTasksOnServiceThread(
+      TimeTicks next_delayed_task_run_time);
+
+  const RepeatingClosure process_ripe_tasks_closure_;
 
   const std::unique_ptr<const TickClock> tick_clock_;
 
-  AtomicFlag started_;
-
-  // Synchronizes access to all members below before |started_| is set. Once
-  // |started_| is set:
-  // - |service_thread_task_runner| doest not change, so it can be read without
-  //   holding the lock.
-  // - |tasks_added_before_start_| isn't accessed anymore.
-  SchedulerLock lock_;
-
   scoped_refptr<TaskRunner> service_thread_task_runner_;
-  std::vector<std::pair<Task, PostTaskNowCallback>> tasks_added_before_start_;
+
+  struct TaskDelayedRuntimeComparator {
+    inline bool operator()(const DelayedTask& lhs,
+                           const DelayedTask& rhs) const {
+      return lhs.first.delayed_run_time > rhs.first.delayed_run_time;
+    }
+  };
+
+  std::priority_queue<DelayedTask,
+                      std::vector<DelayedTask>,
+                      TaskDelayedRuntimeComparator>
+      delayed_task_queue_;
+
+  std::
+      priority_queue<TimeTicks, std::vector<TimeTicks>, std::greater<TimeTicks>>
+          process_ripe_tasks_time_queue_;
+
+  // Synchronizes access to |delayed_task_queue_|,
+  // |process_ripe_task_time_queue_| and the setting of
+  // |service_thread_task_runner|. Once |service_thread_task_runner_| is set,
+  // it is never modified. It is therefore safe to access
+  // |service_thread_task_runner_| without synchronization once it is observed
+  // that it is non-null.
+  SchedulerLock queue_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(DelayedTaskManager);
 };
diff --git a/base/task/task_scheduler/delayed_task_manager_unittest.cc b/base/task/task_scheduler/delayed_task_manager_unittest.cc
index cb9ac1e..4f1b6a9 100644
--- a/base/task/task_scheduler/delayed_task_manager_unittest.cc
+++ b/base/task/task_scheduler/delayed_task_manager_unittest.cc
@@ -34,21 +34,27 @@
   std::move(task.task).Run();
 }
 
+Task ConstructMockedTask(testing::StrictMock<MockTask>& mock_task,
+                         TimeTicks now,
+                         TimeDelta delay) {
+  Task task = Task(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task)),
+                   TaskTraits(), delay);
+  // The constructor of Task computes |delayed_run_time| by adding |delay| to
+  // the real time. Recompute it by adding |delay| to the given |now| (usually
+  // mock time).
+  task.delayed_run_time = now + delay;
+  return task;
+}
+
 class TaskSchedulerDelayedTaskManagerTest : public testing::Test {
  protected:
   TaskSchedulerDelayedTaskManagerTest()
       : delayed_task_manager_(
             service_thread_task_runner_->DeprecatedGetMockTickClock()),
-        task_(FROM_HERE,
-              BindOnce(&MockTask::Run, Unretained(&mock_task_)),
-              TaskTraits(),
-              kLongDelay) {
-    // The constructor of Task computes |delayed_run_time| by adding |delay| to
-    // the real time. Recompute it by adding |delay| to the mock time.
-    task_.delayed_run_time =
-        service_thread_task_runner_->GetMockTickClock()->NowTicks() +
-        kLongDelay;
-  }
+        task_(ConstructMockedTask(
+            mock_task_,
+            service_thread_task_runner_->GetMockTickClock()->NowTicks(),
+            kLongDelay)) {}
   ~TaskSchedulerDelayedTaskManagerTest() override = default;
 
   const scoped_refptr<TestMockTimeTaskRunner> service_thread_task_runner_ =
@@ -146,16 +152,19 @@
   delayed_task_manager_.Start(service_thread_task_runner_);
 
   testing::StrictMock<MockTask> mock_task_a;
-  Task task_a(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_a)),
-              TaskTraits(), TimeDelta::FromHours(1));
+  Task task_a = ConstructMockedTask(
+      mock_task_a, service_thread_task_runner_->GetMockTickClock()->NowTicks(),
+      TimeDelta::FromHours(1));
 
   testing::StrictMock<MockTask> mock_task_b;
-  Task task_b(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_b)),
-              TaskTraits(), TimeDelta::FromHours(2));
+  Task task_b = ConstructMockedTask(
+      mock_task_b, service_thread_task_runner_->GetMockTickClock()->NowTicks(),
+      TimeDelta::FromHours(2));
 
   testing::StrictMock<MockTask> mock_task_c;
-  Task task_c(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_c)),
-              TaskTraits(), TimeDelta::FromHours(1));
+  Task task_c = ConstructMockedTask(
+      mock_task_c, service_thread_task_runner_->GetMockTickClock()->NowTicks(),
+      TimeDelta::FromHours(1));
 
   // Send tasks to the DelayedTaskManager.
   delayed_task_manager_.AddDelayedTask(std::move(task_a), BindOnce(&RunTask));
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.cc b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
index ceafcba..8a4534ad 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
@@ -95,9 +95,9 @@
   // incremented if this returns true.
   bool MustIncrementMaxTasksLockRequired();
 
-  bool is_running_background_task_lock_required() const {
+  bool is_running_best_effort_task_lock_required() const {
     outer_->lock_.AssertAcquired();
-    return is_running_background_task_;
+    return is_running_best_effort_task_;
   }
 
  private:
@@ -142,7 +142,7 @@
   // Writes are made from the worker thread and are protected by
   // |outer_->lock_|. Reads are made from any thread, they are protected by
   // |outer_->lock_| when made outside of the worker thread.
-  bool is_running_background_task_ = false;
+  bool is_running_best_effort_task_ = false;
 
 #if defined(OS_WIN)
   std::unique_ptr<win::ScopedWindowsThreadEnvironment> win_thread_environment_;
@@ -216,7 +216,7 @@
 
 void SchedulerWorkerPoolImpl::Start(
     const SchedulerWorkerPoolParams& params,
-    int max_background_tasks,
+    int max_best_effort_tasks,
     scoped_refptr<TaskRunner> service_thread_task_runner,
     SchedulerWorkerObserver* scheduler_worker_observer,
     WorkerEnvironment worker_environment) {
@@ -228,7 +228,7 @@
   DCHECK_GE(max_tasks_, 1U);
   initial_max_tasks_ = max_tasks_;
   DCHECK_LE(initial_max_tasks_, kMaxNumberOfWorkers);
-  max_background_tasks_ = max_background_tasks;
+  max_best_effort_tasks_ = max_best_effort_tasks;
   suggested_reclaim_time_ = params.suggested_reclaim_time();
   backward_compatibility_ = params.backward_compatibility();
   worker_environment_ = worker_environment;
@@ -438,7 +438,7 @@
     SchedulerWorker* worker) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
   DCHECK(!is_running_task_);
-  DCHECK(!is_running_background_task_);
+  DCHECK(!is_running_best_effort_task_);
 
   {
     AutoSchedulerLock auto_lock(outer_->lock_);
@@ -495,14 +495,14 @@
       return nullptr;
     }
 
-    // Enforce that no more than |max_background_tasks_| run concurrently.
+    // Enforce that no more than |max_best_effort_tasks_| run concurrently.
     const TaskPriority priority = transaction->PeekSortKey().priority();
     if (priority == TaskPriority::BEST_EFFORT) {
       AutoSchedulerLock auto_lock(outer_->lock_);
-      if (outer_->num_running_background_tasks_ <
-          outer_->max_background_tasks_) {
-        ++outer_->num_running_background_tasks_;
-        is_running_background_task_ = true;
+      if (outer_->num_running_best_effort_tasks_ <
+          outer_->max_best_effort_tasks_) {
+        ++outer_->num_running_best_effort_tasks_;
+        is_running_best_effort_task_ = true;
       } else {
         OnWorkerBecomesIdleLockRequired(worker);
         return nullptr;
@@ -531,10 +531,10 @@
 
   is_running_task_ = false;
 
-  if (is_running_background_task_) {
+  if (is_running_best_effort_task_) {
     AutoSchedulerLock auto_lock(outer_->lock_);
-    --outer_->num_running_background_tasks_;
-    is_running_background_task_ = false;
+    --outer_->num_running_best_effort_tasks_;
+    is_running_best_effort_task_ = false;
   }
 
   ++num_tasks_since_last_wait_;
@@ -694,8 +694,8 @@
     if (!may_block_start_time_.is_null()) {
       may_block_start_time_ = TimeTicks();
       --outer_->num_pending_may_block_workers_;
-      if (is_running_background_task_)
-        --outer_->num_pending_background_may_block_workers_;
+      if (is_running_best_effort_task_)
+        --outer_->num_pending_best_effort_may_block_workers_;
     }
   }
 
@@ -711,12 +711,12 @@
 
   AutoSchedulerLock auto_lock(outer_->lock_);
   if (incremented_max_tasks_since_blocked_) {
-    outer_->DecrementMaxTasksLockRequired(is_running_background_task_);
+    outer_->DecrementMaxTasksLockRequired(is_running_best_effort_task_);
   } else {
     DCHECK(!may_block_start_time_.is_null());
     --outer_->num_pending_may_block_workers_;
-    if (is_running_background_task_)
-      --outer_->num_pending_background_may_block_workers_;
+    if (is_running_best_effort_task_)
+      --outer_->num_pending_best_effort_may_block_workers_;
   }
 
   incremented_max_tasks_since_blocked_ = false;
@@ -733,8 +733,8 @@
     DCHECK(may_block_start_time_.is_null());
     may_block_start_time_ = TimeTicks::Now();
     ++outer_->num_pending_may_block_workers_;
-    if (is_running_background_task_)
-      ++outer_->num_pending_background_may_block_workers_;
+    if (is_running_best_effort_task_)
+      ++outer_->num_pending_best_effort_may_block_workers_;
   }
   outer_->ScheduleAdjustMaxTasksIfNeeded();
 }
@@ -751,7 +751,7 @@
     DCHECK(!incremented_max_tasks_since_blocked_);
     DCHECK(may_block_start_time_.is_null());
     incremented_max_tasks_since_blocked_ = true;
-    outer_->IncrementMaxTasksLockRequired(is_running_background_task_);
+    outer_->IncrementMaxTasksLockRequired(is_running_best_effort_task_);
 
     // If the number of workers was less than the old max tasks, PostTask
     // would've handled creating extra workers during WakeUpOneWorker.
@@ -790,8 +790,8 @@
     // doesn't have to decrement the number of pending MAY_BLOCK workers.
     may_block_start_time_ = TimeTicks();
     --outer_->num_pending_may_block_workers_;
-    if (is_running_background_task_)
-      --outer_->num_pending_background_may_block_workers_;
+    if (is_running_best_effort_task_)
+      --outer_->num_pending_best_effort_may_block_workers_;
 
     return true;
   }
@@ -932,7 +932,7 @@
         static_cast<SchedulerWorkerDelegateImpl*>(worker->delegate());
     if (delegate->MustIncrementMaxTasksLockRequired()) {
       IncrementMaxTasksLockRequired(
-          delegate->is_running_background_task_lock_required());
+          delegate->is_running_best_effort_task_lock_required());
     }
   }
 
@@ -999,17 +999,17 @@
 bool SchedulerWorkerPoolImpl::ShouldPeriodicallyAdjustMaxTasksLockRequired() {
   lock_.AssertAcquired();
 
-  // The maximum number of background tasks that can run concurrently must be
-  // adjusted periodically when (1) the number of background tasks that are
+  // The maximum number of best-effort tasks that can run concurrently must be
+  // adjusted periodically when (1) the number of best-effort tasks that are
   // currently running is equal to it and (2) there are workers running
-  // background tasks within the scope of a MAY_BLOCK ScopedBlockingCall but
-  // haven't cause a max background tasks increment yet.
-  // - When (1) is false: A newly posted background task will be allowed to run
-  //   normally. There is no hurry to increase max background tasks.
+  // best-effort tasks within the scope of a MAY_BLOCK ScopedBlockingCall but
+  // haven't cause a max best-effort tasks increment yet.
+  // - When (1) is false: A newly posted best-effort task will be allowed to run
+  //   normally. There is no hurry to increase max best-effort tasks.
   // - When (2) is false: AdjustMaxTasks() wouldn't affect
-  //   |max_background_tasks_|.
-  if (num_running_background_tasks_ >= max_background_tasks_ &&
-      num_pending_background_may_block_workers_ > 0) {
+  //   |max_best_effort_tasks_|.
+  if (num_running_best_effort_tasks_ >= max_best_effort_tasks_ &&
+      num_pending_best_effort_may_block_workers_ > 0) {
     return true;
   }
 
@@ -1028,19 +1028,19 @@
 }
 
 void SchedulerWorkerPoolImpl::DecrementMaxTasksLockRequired(
-    bool is_running_background_task) {
+    bool is_running_best_effort_task) {
   lock_.AssertAcquired();
   --max_tasks_;
-  if (is_running_background_task)
-    --max_background_tasks_;
+  if (is_running_best_effort_task)
+    --max_best_effort_tasks_;
 }
 
 void SchedulerWorkerPoolImpl::IncrementMaxTasksLockRequired(
-    bool is_running_background_task) {
+    bool is_running_best_effort_task) {
   lock_.AssertAcquired();
   ++max_tasks_;
-  if (is_running_background_task)
-    ++max_background_tasks_;
+  if (is_running_best_effort_task)
+    ++max_best_effort_tasks_;
 }
 
 }  // namespace internal
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.h b/base/task/task_scheduler/scheduler_worker_pool_impl.h
index ef9edb1..53cd0992 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.h
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.h
@@ -76,7 +76,7 @@
                           DelayedTaskManager* delayed_task_manager);
 
   // Creates workers following the |params| specification, allowing existing and
-  // future tasks to run. The pool will run at most |max_background_tasks|
+  // future tasks to run. The pool will run at most |max_best_effort_tasks|
   // unblocked TaskPriority::BEST_EFFORT tasks concurrently. Uses
   // |service_thread_task_runner| to monitor for blocked threads in the pool. If
   // specified, |scheduler_worker_observer| will be notified when a worker
@@ -85,7 +85,7 @@
   // |worker_environment| specifies any requested environment to execute the
   // tasks. Can only be called once. CHECKs on failure.
   void Start(const SchedulerWorkerPoolParams& params,
-             int max_background_tasks,
+             int max_best_effort_tasks,
              scoped_refptr<TaskRunner> service_thread_task_runner,
              SchedulerWorkerObserver* scheduler_worker_observer,
              WorkerEnvironment worker_environment);
@@ -221,10 +221,10 @@
   bool ShouldPeriodicallyAdjustMaxTasksLockRequired();
 
   // Increments/decrements the number of tasks that can run in this pool.
-  // |is_running_background_task| indicates whether the worker causing the
+  // |is_running_best_effort_task| indicates whether the worker causing the
   // change is currently running a TaskPriority::BEST_EFFORT task.
-  void DecrementMaxTasksLockRequired(bool is_running_background_task);
-  void IncrementMaxTasksLockRequired(bool is_running_background_task);
+  void DecrementMaxTasksLockRequired(bool is_running_best_effort_task);
+  void IncrementMaxTasksLockRequired(bool is_running_best_effort_task);
 
   const std::string pool_label_;
   const ThreadPriority priority_hint_;
@@ -238,10 +238,11 @@
 
   SchedulerBackwardCompatibility backward_compatibility_;
 
-  // Synchronizes accesses to |workers_|, |max_tasks_|, |max_background_tasks_|,
-  // |num_running_background_tasks_|, |num_pending_may_block_workers_|,
-  // |idle_workers_stack_|, |idle_workers_stack_cv_for_testing_|,
-  // |num_wake_ups_before_start_|, |cleanup_timestamps_|, |polling_max_tasks_|,
+  // Synchronizes accesses to |workers_|, |max_tasks_|,
+  // |max_best_effort_tasks_|, |num_running_best_effort_tasks_|,
+  // |num_pending_may_block_workers_|, |idle_workers_stack_|,
+  // |idle_workers_stack_cv_for_testing_|, |num_wake_ups_before_start_|,
+  // |cleanup_timestamps_|, |polling_max_tasks_|,
   // |worker_cleanup_disallowed_for_testing_|,
   // |num_workers_cleaned_up_for_testing_|,
   // |SchedulerWorkerDelegateImpl::is_on_idle_workers_stack_|,
@@ -262,12 +263,12 @@
   // Initial value of |max_tasks_| as set in Start().
   size_t initial_max_tasks_ = 0;
 
-  // The maximum number of background tasks that can run concurrently in this
+  // The maximum number of best-effort tasks that can run concurrently in this
   // pool.
-  int max_background_tasks_ = 0;
+  int max_best_effort_tasks_ = 0;
 
-  // The number of background tasks that are currently running in this pool.
-  int num_running_background_tasks_ = 0;
+  // The number of best-effort tasks that are currently running in this pool.
+  int num_running_best_effort_tasks_ = 0;
 
   // Number of workers that are within the scope of a MAY_BLOCK
   // ScopedBlockingCall but haven't caused a max task increase yet.
@@ -276,7 +277,7 @@
   // Number of workers that are running a TaskPriority::BEST_EFFORT task and are
   // within the scope of a MAY_BLOCK ScopedBlockingCall but haven't caused a max
   // task increase yet.
-  int num_pending_background_may_block_workers_ = 0;
+  int num_pending_best_effort_may_block_workers_ = 0;
 
   // Environment to be initialized per worker.
   WorkerEnvironment worker_environment_ = WorkerEnvironment::NONE;
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc b/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
index abff634..32c2b25 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
@@ -1504,13 +1504,13 @@
   task_tracker_.FlushForTesting();
 }
 
-// Verify that the maximum number of background tasks that can run concurrently
+// Verify that the maximum number of best-effort tasks that can run concurrently
 // is honored.
-TEST_F(TaskSchedulerWorkerPoolImplStartInBodyTest, MaxBackgroundTasks) {
-  constexpr int kMaxBackgroundTasks = kMaxTasks / 2;
+TEST_F(TaskSchedulerWorkerPoolImplStartInBodyTest, MaxBestEffortTasks) {
+  constexpr int kMaxBestEffortTasks = kMaxTasks / 2;
   worker_pool_->Start(
       SchedulerWorkerPoolParams(kMaxTasks, base::TimeDelta::Max()),
-      kMaxBackgroundTasks, service_thread_.task_runner(), nullptr,
+      kMaxBestEffortTasks, service_thread_.task_runner(), nullptr,
       SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
   const scoped_refptr<TaskRunner> foreground_runner =
       worker_pool_->CreateTaskRunnerWithTraits({MayBlock()});
@@ -1518,30 +1518,30 @@
       worker_pool_->CreateTaskRunnerWithTraits(
           {TaskPriority::BEST_EFFORT, MayBlock()});
 
-  // It should be possible to have |kMaxBackgroundTasks|
+  // It should be possible to have |kMaxBestEffortTasks|
   // TaskPriority::BEST_EFFORT tasks running concurrently.
-  WaitableEvent background_tasks_running;
-  WaitableEvent unblock_background_tasks;
-  RepeatingClosure background_tasks_running_barrier = BarrierClosure(
-      kMaxBackgroundTasks,
-      BindOnce(&WaitableEvent::Signal, Unretained(&background_tasks_running)));
+  WaitableEvent best_effort_tasks_running;
+  WaitableEvent unblock_best_effort_tasks;
+  RepeatingClosure best_effort_tasks_running_barrier = BarrierClosure(
+      kMaxBestEffortTasks,
+      BindOnce(&WaitableEvent::Signal, Unretained(&best_effort_tasks_running)));
 
-  for (int i = 0; i < kMaxBackgroundTasks; ++i) {
+  for (int i = 0; i < kMaxBestEffortTasks; ++i) {
     background_runner->PostTask(
         FROM_HERE, base::BindLambdaForTesting([&]() {
-          background_tasks_running_barrier.Run();
-          WaitWithoutBlockingObserver(&unblock_background_tasks);
+          best_effort_tasks_running_barrier.Run();
+          WaitWithoutBlockingObserver(&unblock_best_effort_tasks);
         }));
   }
-  background_tasks_running.Wait();
+  best_effort_tasks_running.Wait();
 
   // No more TaskPriority::BEST_EFFORT task should run.
-  AtomicFlag extra_background_task_can_run;
-  WaitableEvent extra_background_task_running;
+  AtomicFlag extra_best_effort_task_can_run;
+  WaitableEvent extra_best_effort_task_running;
   background_runner->PostTask(
       FROM_HERE, base::BindLambdaForTesting([&]() {
-        EXPECT_TRUE(extra_background_task_can_run.IsSet());
-        extra_background_task_running.Signal();
+        EXPECT_TRUE(extra_best_effort_task_can_run.IsSet());
+        extra_best_effort_task_running.Signal();
       }));
 
   // An extra foreground task should be able to run.
@@ -1553,9 +1553,9 @@
 
   // Completion of the TaskPriority::BEST_EFFORT tasks should allow the extra
   // TaskPriority::BEST_EFFORT task to run.
-  extra_background_task_can_run.Set();
-  unblock_background_tasks.Signal();
-  extra_background_task_running.Wait();
+  extra_best_effort_task_can_run.Set();
+  unblock_best_effort_tasks.Signal();
+  extra_best_effort_task_running.Wait();
 
   // Tear down.
   task_tracker_.FlushForTesting();
@@ -1563,19 +1563,19 @@
 
 namespace {
 
-class TaskSchedulerWorkerPoolBlockingCallAndMaxBackgroundTasksTest
+class TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest
     : public TaskSchedulerWorkerPoolImplTestBase,
       public testing::TestWithParam<BlockingType> {
  public:
-  static constexpr int kMaxBackgroundTasks = kMaxTasks / 2;
+  static constexpr int kMaxBestEffortTasks = kMaxTasks / 2;
 
-  TaskSchedulerWorkerPoolBlockingCallAndMaxBackgroundTasksTest() = default;
+  TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest() = default;
 
   void SetUp() override {
     CreateWorkerPool();
     worker_pool_->Start(
         SchedulerWorkerPoolParams(kMaxTasks, base::TimeDelta::Max()),
-        kMaxBackgroundTasks, service_thread_.task_runner(), nullptr,
+        kMaxBestEffortTasks, service_thread_.task_runner(), nullptr,
         SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
   }
 
@@ -1585,68 +1585,68 @@
 
  private:
   DISALLOW_COPY_AND_ASSIGN(
-      TaskSchedulerWorkerPoolBlockingCallAndMaxBackgroundTasksTest);
+      TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest);
 };
 
 }  // namespace
 
-TEST_P(TaskSchedulerWorkerPoolBlockingCallAndMaxBackgroundTasksTest,
-       BlockingCallAndMaxBackgroundTasksTest) {
+TEST_P(TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest,
+       BlockingCallAndMaxBestEffortTasksTest) {
   const scoped_refptr<TaskRunner> background_runner =
       worker_pool_->CreateTaskRunnerWithTraits(
           {TaskPriority::BEST_EFFORT, MayBlock()});
 
-  // Post |kMaxBackgroundTasks| TaskPriority::BEST_EFFORT tasks that block in a
+  // Post |kMaxBestEffortTasks| TaskPriority::BEST_EFFORT tasks that block in a
   // ScopedBlockingCall.
-  WaitableEvent blocking_background_tasks_running;
-  WaitableEvent unblock_blocking_background_tasks;
-  RepeatingClosure blocking_background_tasks_running_barrier =
-      BarrierClosure(kMaxBackgroundTasks,
+  WaitableEvent blocking_best_effort_tasks_running;
+  WaitableEvent unblock_blocking_best_effort_tasks;
+  RepeatingClosure blocking_best_effort_tasks_running_barrier =
+      BarrierClosure(kMaxBestEffortTasks,
                      BindOnce(&WaitableEvent::Signal,
-                              Unretained(&blocking_background_tasks_running)));
-  for (int i = 0; i < kMaxBackgroundTasks; ++i) {
+                              Unretained(&blocking_best_effort_tasks_running)));
+  for (int i = 0; i < kMaxBestEffortTasks; ++i) {
     background_runner->PostTask(
         FROM_HERE, base::BindLambdaForTesting([&]() {
-          blocking_background_tasks_running_barrier.Run();
+          blocking_best_effort_tasks_running_barrier.Run();
           ScopedBlockingCall scoped_blocking_call(GetParam());
-          WaitWithoutBlockingObserver(&unblock_blocking_background_tasks);
+          WaitWithoutBlockingObserver(&unblock_blocking_best_effort_tasks);
         }));
   }
-  blocking_background_tasks_running.Wait();
+  blocking_best_effort_tasks_running.Wait();
 
-  // Post an extra |kMaxBackgroundTasks| TaskPriority::BEST_EFFORT tasks. They
+  // Post an extra |kMaxBestEffortTasks| TaskPriority::BEST_EFFORT tasks. They
   // should be able to run, because the existing TaskPriority::BEST_EFFORT tasks
   // are blocked within a ScopedBlockingCall.
   //
   // Note: We block the tasks until they have all started running to make sure
-  // that it is possible to run an extra |kMaxBackgroundTasks| concurrently.
-  WaitableEvent background_tasks_running;
-  WaitableEvent unblock_background_tasks;
-  RepeatingClosure background_tasks_running_barrier = BarrierClosure(
-      kMaxBackgroundTasks,
-      BindOnce(&WaitableEvent::Signal, Unretained(&background_tasks_running)));
-  for (int i = 0; i < kMaxBackgroundTasks; ++i) {
+  // that it is possible to run an extra |kMaxBestEffortTasks| concurrently.
+  WaitableEvent best_effort_tasks_running;
+  WaitableEvent unblock_best_effort_tasks;
+  RepeatingClosure best_effort_tasks_running_barrier = BarrierClosure(
+      kMaxBestEffortTasks,
+      BindOnce(&WaitableEvent::Signal, Unretained(&best_effort_tasks_running)));
+  for (int i = 0; i < kMaxBestEffortTasks; ++i) {
     background_runner->PostTask(
         FROM_HERE, base::BindLambdaForTesting([&]() {
-          background_tasks_running_barrier.Run();
-          WaitWithoutBlockingObserver(&unblock_background_tasks);
+          best_effort_tasks_running_barrier.Run();
+          WaitWithoutBlockingObserver(&unblock_best_effort_tasks);
         }));
   }
-  background_tasks_running.Wait();
+  best_effort_tasks_running.Wait();
 
   // Unblock all tasks and tear down.
-  unblock_blocking_background_tasks.Signal();
-  unblock_background_tasks.Signal();
+  unblock_blocking_best_effort_tasks.Signal();
+  unblock_best_effort_tasks.Signal();
   task_tracker_.FlushForTesting();
 }
 
 INSTANTIATE_TEST_CASE_P(
     MayBlock,
-    TaskSchedulerWorkerPoolBlockingCallAndMaxBackgroundTasksTest,
+    TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest,
     ::testing::Values(BlockingType::MAY_BLOCK));
 INSTANTIATE_TEST_CASE_P(
     WillBlock,
-    TaskSchedulerWorkerPoolBlockingCallAndMaxBackgroundTasksTest,
+    TaskSchedulerWorkerPoolBlockingCallAndMaxBestEffortTasksTest,
     ::testing::Values(BlockingType::WILL_BLOCK));
 
 // Verify that worker detachement doesn't race with worker cleanup, regression
diff --git a/base/task/task_scheduler/scheduler_worker_pool_unittest.cc b/base/task/task_scheduler/scheduler_worker_pool_unittest.cc
index 982e6aa8..47c0cca6 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_unittest.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_unittest.cc
@@ -35,8 +35,8 @@
 namespace {
 
 constexpr size_t kMaxTasks = 4;
-// By default, tests allow half of the pool to be used by background tasks.
-constexpr size_t kMaxBackgroundTasks = kMaxTasks / 2;
+// By default, tests allow half of the pool to be used by best-effort tasks.
+constexpr size_t kMaxBestEffortTasks = kMaxTasks / 2;
 constexpr size_t kNumThreadsPostingTasks = 4;
 constexpr size_t kNumTasksPostedPerThread = 150;
 
@@ -134,7 +134,7 @@
             static_cast<SchedulerWorkerPoolImpl*>(worker_pool_.get());
         scheduler_worker_pool_impl->Start(
             SchedulerWorkerPoolParams(kMaxTasks, TimeDelta::Max()),
-            kMaxBackgroundTasks, service_thread_.task_runner(), nullptr,
+            kMaxBestEffortTasks, service_thread_.task_runner(), nullptr,
             SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
         break;
       }
diff --git a/base/task/task_scheduler/sequence_unittest.cc b/base/task/task_scheduler/sequence_unittest.cc
index 931425e..324784b3 100644
--- a/base/task/task_scheduler/sequence_unittest.cc
+++ b/base/task/task_scheduler/sequence_unittest.cc
@@ -95,30 +95,31 @@
 }
 
 // Verifies the sort key of a sequence that contains one BEST_EFFORT task.
-TEST(TaskSchedulerSequenceTest, GetSortKeyBackground) {
+TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) {
   // Create a sequence with a BEST_EFFORT task.
-  Task background_task(FROM_HERE, DoNothing(), {TaskPriority::BEST_EFFORT},
-                       TimeDelta());
-  scoped_refptr<Sequence> background_sequence = MakeRefCounted<Sequence>();
-  background_sequence->PushTask(std::move(background_task));
+  Task best_effort_task(FROM_HERE, DoNothing(), {TaskPriority::BEST_EFFORT},
+                        TimeDelta());
+  scoped_refptr<Sequence> best_effort_sequence = MakeRefCounted<Sequence>();
+  best_effort_sequence->PushTask(std::move(best_effort_task));
 
   // Get the sort key.
-  const SequenceSortKey background_sort_key = background_sequence->GetSortKey();
+  const SequenceSortKey best_effort_sort_key =
+      best_effort_sequence->GetSortKey();
 
   // Take the task from the sequence, so that its sequenced time is available
   // for the check below.
-  auto take_background_task = background_sequence->TakeTask();
+  auto take_best_effort_task = best_effort_sequence->TakeTask();
 
   // Verify the sort key.
-  EXPECT_EQ(TaskPriority::BEST_EFFORT, background_sort_key.priority());
-  EXPECT_EQ(take_background_task->sequenced_time,
-            background_sort_key.next_task_sequenced_time());
+  EXPECT_EQ(TaskPriority::BEST_EFFORT, best_effort_sort_key.priority());
+  EXPECT_EQ(take_best_effort_task->sequenced_time,
+            best_effort_sort_key.next_task_sequenced_time());
 
   // Pop for correctness.
-  background_sequence->Pop();
+  best_effort_sequence->Pop();
 }
 
-// Same as TaskSchedulerSequenceTest.GetSortKeyBackground, but with a
+// Same as TaskSchedulerSequenceTest.GetSortKeyBestEffort, but with a
 // USER_VISIBLE task.
 TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) {
   // Create a sequence with a USER_VISIBLE task.
diff --git a/base/task/task_scheduler/task_scheduler_impl.cc b/base/task/task_scheduler/task_scheduler_impl.cc
index 45604baa..c6f55aac 100644
--- a/base/task/task_scheduler/task_scheduler_impl.cc
+++ b/base/task/task_scheduler/task_scheduler_impl.cc
@@ -140,26 +140,26 @@
       SchedulerWorkerPoolImpl::WorkerEnvironment::NONE;
 #endif
 
-  // On platforms that can't use the background thread priority, background
+  // On platforms that can't use the background thread priority, best-effort
   // tasks run in foreground pools. A cap is set on the number of background
   // tasks that can run in foreground pools to ensure that there is always room
   // for incoming foreground tasks and to minimize the performance impact of
-  // background tasks.
-  const int max_background_tasks_in_foreground_pool = std::max(
+  // best-effort tasks.
+  const int max_best_effort_tasks_in_foreground_pool = std::max(
       1, std::min(init_params.background_worker_pool_params.max_tasks(),
                   init_params.foreground_worker_pool_params.max_tasks() / 2));
   worker_pools_[FOREGROUND]->Start(
       init_params.foreground_worker_pool_params,
-      max_background_tasks_in_foreground_pool, service_thread_task_runner,
+      max_best_effort_tasks_in_foreground_pool, service_thread_task_runner,
       scheduler_worker_observer, worker_environment);
-  const int max_background_tasks_in_foreground_blocking_pool = std::max(
+  const int max_best_effort_tasks_in_foreground_blocking_pool = std::max(
       1,
       std::min(
           init_params.background_blocking_worker_pool_params.max_tasks(),
           init_params.foreground_blocking_worker_pool_params.max_tasks() / 2));
   worker_pools_[FOREGROUND_BLOCKING]->Start(
       init_params.foreground_blocking_worker_pool_params,
-      max_background_tasks_in_foreground_blocking_pool,
+      max_best_effort_tasks_in_foreground_blocking_pool,
       service_thread_task_runner, scheduler_worker_observer,
       worker_environment);
 
diff --git a/base/task/task_scheduler/task_scheduler_impl_unittest.cc b/base/task/task_scheduler/task_scheduler_impl_unittest.cc
index 7c3b939..093f5ed 100644
--- a/base/task/task_scheduler/task_scheduler_impl_unittest.cc
+++ b/base/task/task_scheduler/task_scheduler_impl_unittest.cc
@@ -94,8 +94,8 @@
   EXPECT_NE(std::string::npos, current_thread_name.find("TaskScheduler"));
 
   if (current_thread_name.find("SingleThread") != std::string::npos) {
-    // For now, single-threaded background tasks run on their own threads.
-    // TODO(fdoray): Run single-threaded background tasks on foreground workers
+    // For now, single-threaded best-effort tasks run on their own threads.
+    // TODO(fdoray): Run single-threaded best-effort tasks on foreground workers
     // on platforms that don't support background thread priority.
     EXPECT_NE(
         std::string::npos,
diff --git a/base/task/task_scheduler/task_tracker.cc b/base/task/task_scheduler/task_tracker.cc
index b87615f..346fbe36 100644
--- a/base/task/task_scheduler/task_tracker.cc
+++ b/base/task/task_scheduler/task_tracker.cc
@@ -112,7 +112,7 @@
 
 // Returns the maximum number of TaskPriority::BEST_EFFORT sequences that can be
 // scheduled concurrently based on command line flags.
-int GetMaxNumScheduledBackgroundSequences() {
+int GetMaxNumScheduledBestEffortSequences() {
   // The CommandLine might not be initialized if TaskScheduler is initialized
   // in a dynamic library which doesn't have access to argc/argv.
   if (CommandLine::InitializedForCurrentProcess() &&
@@ -230,7 +230,7 @@
     return next_task_sequenced_time > other.next_task_sequenced_time;
   }
 
-  // A background sequence waiting to be scheduled.
+  // A sequence waiting to be scheduled.
   scoped_refptr<Sequence> sequence;
 
   // The sequenced time of the next task in |sequence|.
@@ -247,10 +247,10 @@
 TaskTracker::PreemptionState::~PreemptionState() = default;
 
 TaskTracker::TaskTracker(StringPiece histogram_label)
-    : TaskTracker(histogram_label, GetMaxNumScheduledBackgroundSequences()) {}
+    : TaskTracker(histogram_label, GetMaxNumScheduledBestEffortSequences()) {}
 
 TaskTracker::TaskTracker(StringPiece histogram_label,
-                         int max_num_scheduled_background_sequences)
+                         int max_num_scheduled_best_effort_sequences)
     : state_(new State),
       flush_cv_(flush_lock_.CreateConditionVariable()),
       shutdown_lock_(&flush_lock_),
@@ -298,7 +298,7 @@
                                      1][0] -
            1));
   preemption_state_[static_cast<int>(TaskPriority::BEST_EFFORT)]
-      .max_scheduled_sequences = max_num_scheduled_background_sequences;
+      .max_scheduled_sequences = max_num_scheduled_best_effort_sequences;
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -856,7 +856,7 @@
   }
 
   // |sequence_to_schedule.sequence| may be null if there was no preempted
-  // background sequence.
+  // sequence.
   if (sequence_to_schedule.sequence)
     SchedulePreemptedSequence(std::move(sequence_to_schedule));
 
diff --git a/base/task/task_scheduler/task_tracker.h b/base/task/task_scheduler/task_tracker.h
index 45989fb..c9341a0 100644
--- a/base/task/task_scheduler/task_tracker.h
+++ b/base/task/task_scheduler/task_tracker.h
@@ -84,13 +84,13 @@
 //                   Go back to (*)                      |_________________|
 //
 //
-// Note: A background task is a task posted with TaskPriority::BEST_EFFORT. A
+// Note: A best-effort task is a task posted with TaskPriority::BEST_EFFORT. A
 // foreground task is a task posted with TaskPriority::USER_VISIBLE or
 // TaskPriority::USER_BLOCKING.
 //
 // TODO(fdoray): We want to allow disabling TaskPriority::BEST_EFFORT tasks in a
 // scope (e.g. during startup or page load), but we don't need a dynamic maximum
-// number of background tasks. The code could probably be simplified if it
+// number of best-effort tasks. The code could probably be simplified if it
 // didn't support that. https://crbug.com/831835
 class BASE_EXPORT TaskTracker {
  public:
@@ -98,10 +98,10 @@
   // The first constructor sets the maximum number of TaskPriority::BEST_EFFORT
   // sequences that can be scheduled concurrently to 0 if the
   // --disable-background-tasks flag is specified, max() otherwise. The second
-  // constructor sets it to |max_num_scheduled_background_sequences|.
+  // constructor sets it to |max_num_scheduled_best_effort_sequences|.
   TaskTracker(StringPiece histogram_label);
   TaskTracker(StringPiece histogram_label,
-              int max_num_scheduled_background_sequences);
+              int max_num_scheduled_best_effort_sequences);
 
   virtual ~TaskTracker();
 
@@ -263,12 +263,11 @@
   void SetMaxNumScheduledSequences(int max_scheduled_sequences,
                                    TaskPriority priority);
 
-  // Pops the next sequence in
-  // |preemption_state_[priority].preempted_sequences| and increments
-  // |preemption_state_[priority].current_scheduled_sequences|. Must only be
-  // called in the scope of |preemption_state_[priority].lock|, with
-  // |preemption_state_[priority].preempted_sequences| non-empty. The caller
-  // must forward the returned sequence to the associated
+  // Pops the next sequence in |preemption_state_[priority].preempted_sequences|
+  // and increments |preemption_state_[priority].current_scheduled_sequences|.
+  // Must only be called in the scope of |preemption_state_[priority].lock|,
+  // with |preemption_state_[priority].preempted_sequences| non-empty. The
+  // caller must forward the returned sequence to the associated
   // CanScheduleSequenceObserver as soon as |preemption_state_[priority].lock|
   // is released.
   PreemptedSequence GetPreemptedSequenceToScheduleLockRequired(
@@ -302,8 +301,8 @@
   // if it reaches zero.
   void DecrementNumIncompleteUndelayedTasks();
 
-  // To be called after running a background task from |just_ran_sequence|.
-  // Performs the following actions:
+  // To be called after running a task from |just_ran_sequence|. Performs the
+  // following actions:
   //  - If |just_ran_sequence| is non-null:
   //    - returns it if it should be rescheduled by the caller of
   //      RunAndPopNextTask(), i.e. its next task is set to run earlier than the
@@ -314,8 +313,7 @@
   //  - If |just_ran_sequence| is null (RunAndPopNextTask() just popped the last
   //    task from it):
   //    - the next preempeted sequence (if any) is scheduled.
-  //  - In all cases: adjusts the number of scheduled background sequences
-  //    accordingly.
+  //  - In all cases: adjusts the number of scheduled sequences accordingly.
   scoped_refptr<Sequence> ManageSequencesAfterRunningTask(
       scoped_refptr<Sequence> just_ran_sequence,
       CanScheduleSequenceObserver* observer,
diff --git a/base/task/task_scheduler/task_tracker_unittest.cc b/base/task/task_scheduler/task_tracker_unittest.cc
index 0240427..994515c31 100644
--- a/base/task/task_scheduler/task_tracker_unittest.cc
+++ b/base/task/task_scheduler/task_tracker_unittest.cc
@@ -1050,14 +1050,14 @@
 
 namespace {
 
-void TestWillScheduleBackgroundSequenceWithMaxBackgroundSequences(
-    int max_num_scheduled_background_sequences,
+void TestWillScheduleBestEffortSequenceWithMaxBestEffortSequences(
+    int max_num_scheduled_best_effort_sequences,
     TaskTracker& tracker) {
-  // Simulate posting |max_num_scheduled_background_sequences| background tasks
-  // and scheduling the associated sequences. This should succeed.
+  // Simulate posting |max_num_scheduled_best_effort_sequences| best-effort
+  // tasks and scheduling the associated sequences. This should succeed.
   std::vector<scoped_refptr<Sequence>> scheduled_sequences;
   testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer;
-  for (int i = 0; i < max_num_scheduled_background_sequences; ++i) {
+  for (int i = 0; i < max_num_scheduled_best_effort_sequences; ++i) {
     Task task(FROM_HERE, DoNothing(), TaskTraits(TaskPriority::BEST_EFFORT),
               TimeDelta());
     EXPECT_TRUE(tracker.WillPostTask(&task));
@@ -1068,15 +1068,15 @@
     scheduled_sequences.push_back(std::move(sequence));
   }
 
-  // Simulate posting extra background tasks and scheduling the associated
-  // sequences. This should fail because the maximum number of background
+  // Simulate posting extra best-effort tasks and scheduling the associated
+  // sequences. This should fail because the maximum number of best-effort
   // sequences that can be scheduled concurrently is already reached.
   std::vector<std::unique_ptr<bool>> extra_tasks_did_run;
   std::vector<
       std::unique_ptr<testing::StrictMock<MockCanScheduleSequenceObserver>>>
       extra_observers;
   std::vector<scoped_refptr<Sequence>> extra_sequences;
-  for (int i = 0; i < max_num_scheduled_background_sequences; ++i) {
+  for (int i = 0; i < max_num_scheduled_best_effort_sequences; ++i) {
     extra_tasks_did_run.push_back(std::make_unique<bool>());
     Task extra_task(
         FROM_HERE,
@@ -1097,7 +1097,7 @@
   // Run the sequences scheduled at the beginning of the test. Expect an
   // observer from |extra_observer| to be notified every time a task finishes to
   // run.
-  for (int i = 0; i < max_num_scheduled_background_sequences; ++i) {
+  for (int i = 0; i < max_num_scheduled_best_effort_sequences; ++i) {
     EXPECT_CALL(*extra_observers[i].get(),
                 MockOnCanScheduleSequence(extra_sequences[i].get()));
     EXPECT_FALSE(tracker.RunAndPopNextTask(scheduled_sequences[i],
@@ -1106,7 +1106,7 @@
   }
 
   // Run the extra sequences.
-  for (int i = 0; i < max_num_scheduled_background_sequences; ++i) {
+  for (int i = 0; i < max_num_scheduled_best_effort_sequences; ++i) {
     EXPECT_FALSE(*extra_tasks_did_run[i]);
     EXPECT_FALSE(tracker.RunAndPopNextTask(extra_sequences[i],
                                            &never_notified_observer));
@@ -1117,28 +1117,28 @@
 }  // namespace
 
 // Verify that WillScheduleSequence() returns nullptr when it receives a
-// background sequence and the maximum number of background sequences that can
+// best-effort sequence and the maximum number of best-effort sequences that can
 // be scheduled concurrently is reached. Verify that an observer is notified
-// when a background sequence can be scheduled (i.e. when one of the previously
-// scheduled background sequences has run).
+// when a best-effort sequence can be scheduled (i.e. when one of the previously
+// scheduled best-effort sequences has run).
 TEST_F(TaskSchedulerTaskTrackerTest,
-       WillScheduleBackgroundSequenceWithMaxBackgroundSequences) {
-  constexpr int kMaxNumScheduledBackgroundSequences = 2;
-  TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences);
-  TestWillScheduleBackgroundSequenceWithMaxBackgroundSequences(
-      kMaxNumScheduledBackgroundSequences, tracker);
+       WillScheduleBestEffortSequenceWithMaxBestEffortSequences) {
+  constexpr int kMaxNumScheduledBestEffortSequences = 2;
+  TaskTracker tracker("Test", kMaxNumScheduledBestEffortSequences);
+  TestWillScheduleBestEffortSequenceWithMaxBestEffortSequences(
+      kMaxNumScheduledBestEffortSequences, tracker);
 }
 
 // Verify that providing a cap for the number of BEST_EFFORT tasks to the
 // constructor of TaskTracker is compatible with using an execution fence.
 TEST_F(TaskSchedulerTaskTrackerTest,
-       WillScheduleBackgroundSequenceWithMaxBackgroundSequencesAndFence) {
-  constexpr int kMaxNumScheduledBackgroundSequences = 2;
-  TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences);
+       WillScheduleBestEffortSequenceWithMaxBestEffortSequencesAndFence) {
+  constexpr int kMaxNumScheduledBestEffortSequences = 2;
+  TaskTracker tracker("Test", kMaxNumScheduledBestEffortSequences);
   tracker.SetExecutionFenceEnabled(true);
   tracker.SetExecutionFenceEnabled(false);
-  TestWillScheduleBackgroundSequenceWithMaxBackgroundSequences(
-      kMaxNumScheduledBackgroundSequences, tracker);
+  TestWillScheduleBestEffortSequenceWithMaxBestEffortSequences(
+      kMaxNumScheduledBestEffortSequences, tracker);
 }
 
 namespace {
@@ -1243,17 +1243,17 @@
                             sequence_d, &never_notified_observer));
 }
 
-// Verify that RunAndPopNextTask() doesn't reschedule the background sequence it
-// was assigned if there is a preempted background sequence with an earlier
+// Verify that RunAndPopNextTask() doesn't reschedule the best-effort sequence
+// it was assigned if there is a preempted best-effort sequence with an earlier
 // sequence time (compared to the next task in the sequence assigned to
 // RunAndPopNextTask()).
 TEST_F(TaskSchedulerTaskTrackerTest,
-       RunNextBackgroundTaskWithEarlierPendingBackgroundTask) {
-  constexpr int kMaxNumScheduledBackgroundSequences = 1;
-  TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences);
+       RunNextBestEffortTaskWithEarlierPendingBestEffortTask) {
+  constexpr int kMaxNumScheduledBestEffortSequences = 1;
+  TaskTracker tracker("Test", kMaxNumScheduledBestEffortSequences);
   testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer;
 
-  // Simulate posting a background task and scheduling the associated sequence.
+  // Simulate posting a best-effort task and scheduling the associated sequence.
   // This should succeed.
   bool task_a_1_did_run = false;
   Task task_a_1(FROM_HERE, BindOnce(&SetBool, Unretained(&task_a_1_did_run)),
@@ -1264,8 +1264,8 @@
   EXPECT_EQ(sequence_a,
             tracker.WillScheduleSequence(sequence_a, &never_notified_observer));
 
-  // Simulate posting an extra background task and scheduling the associated
-  // sequence. This should fail because the maximum number of background
+  // Simulate posting an extra best-effort task and scheduling the associated
+  // sequence. This should fail because the maximum number of best-effort
   // sequences that can be scheduled concurrently is already reached.
   bool task_b_1_did_run = false;
   Task task_b_1(FROM_HERE, BindOnce(&SetBool, Unretained(&task_b_1_did_run)),
@@ -1280,7 +1280,7 @@
   // time of |task_b_1|.
   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
 
-  // Post an extra background task in |sequence_a|.
+  // Post an extra best-effort task in |sequence_a|.
   bool task_a_2_did_run = false;
   Task task_a_2(FROM_HERE, BindOnce(&SetBool, Unretained(&task_a_2_did_run)),
                 TaskTraits(TaskPriority::BEST_EFFORT), TimeDelta());
@@ -1312,12 +1312,12 @@
   EXPECT_TRUE(task_a_2_did_run);
 }
 
-// Verify that preempted background sequences are scheduled when shutdown
+// Verify that preempted best-effort sequences are scheduled when shutdown
 // starts.
 TEST_F(TaskSchedulerTaskTrackerTest,
-       SchedulePreemptedBackgroundSequencesOnShutdown) {
-  constexpr int kMaxNumScheduledBackgroundSequences = 0;
-  TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences);
+       SchedulePreemptedBestEffortSequencesOnShutdown) {
+  constexpr int kMaxNumScheduledBestEffortSequences = 0;
+  TaskTracker tracker("Test", kMaxNumScheduledBestEffortSequences);
   testing::StrictMock<MockCanScheduleSequenceObserver> observer;
 
   // Simulate scheduling sequences. TaskTracker should prevent this.
diff --git a/base/test/gtest_xml_unittest_result_printer.cc b/base/test/gtest_xml_unittest_result_printer.cc
index 558a9867b..2089e4a 100644
--- a/base/test/gtest_xml_unittest_result_printer.cc
+++ b/base/test/gtest_xml_unittest_result_printer.cc
@@ -114,7 +114,7 @@
 
   if (test_info.result()->total_part_count() > limit) {
     WriteTestPartResult(
-        "<unknown>", 0, testing::TestPartResult::kNonFatalFailure,
+        "unknown", 0, testing::TestPartResult::kNonFatalFailure,
         kTestPartLesultsLimitExceeded, kTestPartLesultsLimitExceeded);
   }
 
diff --git a/base/test/metrics/histogram_tester_unittest.cc b/base/test/metrics/histogram_tester_unittest.cc
index e9b9f20..f8f52d78 100644
--- a/base/test/metrics/histogram_tester_unittest.cc
+++ b/base/test/metrics/histogram_tester_unittest.cc
@@ -22,6 +22,7 @@
 const char kHistogram3[] = "Test3";
 const char kHistogram4[] = "Test4";
 const char kHistogram5[] = "Test5";
+const char kHistogram6[] = "Test6";
 
 }  // namespace
 
@@ -130,7 +131,7 @@
 
 TEST_F(HistogramTesterTest, TestGetAllChangedHistograms) {
   // Record into a sample twice, once before the tester creation.
-  UMA_HISTOGRAM_COUNTS_100(kHistogram1, true);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram6, true);
   UMA_HISTOGRAM_COUNTS_100(kHistogram4, 4);
 
   HistogramTester tester;
diff --git a/base/time/time.cc b/base/time/time.cc
index c1d06a8b..e0cd1c2 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -37,14 +37,6 @@
 
 // TimeDelta ------------------------------------------------------------------
 
-int TimeDelta::InDays() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int>::max();
-  }
-  return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
-}
-
 int TimeDelta::InDaysFloored() const {
   if (is_max()) {
     // Preserve max to prevent overflow.
@@ -58,54 +50,6 @@
   return result;
 }
 
-int TimeDelta::InHours() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int>::max();
-  }
-  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
-}
-
-int TimeDelta::InMinutes() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int>::max();
-  }
-  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
-}
-
-double TimeDelta::InSecondsF() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<double>::infinity();
-  }
-  return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
-}
-
-int64_t TimeDelta::InSeconds() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int64_t>::max();
-  }
-  return delta_ / Time::kMicrosecondsPerSecond;
-}
-
-double TimeDelta::InMillisecondsF() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<double>::infinity();
-  }
-  return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
-}
-
-int64_t TimeDelta::InMilliseconds() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int64_t>::max();
-  }
-  return delta_ / Time::kMicrosecondsPerMillisecond;
-}
-
 int64_t TimeDelta::InMillisecondsRoundedUp() const {
   if (is_max()) {
     // Preserve max to prevent overflow.
@@ -119,30 +63,6 @@
   return result;
 }
 
-int64_t TimeDelta::InMicroseconds() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int64_t>::max();
-  }
-  return delta_;
-}
-
-double TimeDelta::InMicrosecondsF() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<double>::infinity();
-  }
-  return static_cast<double>(delta_);
-}
-
-int64_t TimeDelta::InNanoseconds() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int64_t>::max();
-  }
-  return delta_ * Time::kNanosecondsPerMicrosecond;
-}
-
 namespace time_internal {
 
 int64_t SaturatedAdd(TimeDelta delta, int64_t value) {
diff --git a/base/time/time.h b/base/time/time.h
index 970e2b6a..e35c449b 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -186,18 +186,18 @@
   // towards zero, std::trunc() behavior). The InXYZFloored() versions round to
   // lesser integers (std::floor() behavior). The XYZRoundedUp() versions round
   // up to greater integers (std::ceil() behavior).
-  int InDays() const;
+  constexpr int InDays() const;
   int InDaysFloored() const;
-  int InHours() const;
-  int InMinutes() const;
-  double InSecondsF() const;
-  int64_t InSeconds() const;
-  double InMillisecondsF() const;
-  int64_t InMilliseconds() const;
+  constexpr int InHours() const;
+  constexpr int InMinutes() const;
+  constexpr double InSecondsF() const;
+  constexpr int64_t InSeconds() const;
+  constexpr double InMillisecondsF() const;
+  constexpr int64_t InMilliseconds() const;
   int64_t InMillisecondsRoundedUp() const;
-  int64_t InMicroseconds() const;
-  double InMicrosecondsF() const;
-  int64_t InNanoseconds() const;
+  constexpr int64_t InMicroseconds() const;
+  constexpr double InMicrosecondsF() const;
+  constexpr int64_t InNanoseconds() const;
 
   // Computations with other deltas. Can easily be made constexpr with C++17 but
   // hard to do until then per limitations around
@@ -294,6 +294,11 @@
   // and a known-positive value.
   static constexpr TimeDelta FromProduct(int64_t value, int64_t positive_value);
 
+  // Returns |delta_| (microseconds) divided by |divisor|, or the max value
+  // representable in T if is_max().
+  template <typename T>
+  constexpr T DivideOrMax(int64_t divisor) const;
+
   // Delta in microseconds.
   int64_t delta_;
 };
@@ -779,6 +784,64 @@
   return TimeDelta(std::numeric_limits<int64_t>::min());
 }
 
+// Must be defined before use below.
+template <typename T>
+constexpr T TimeDelta::DivideOrMax(int64_t divisor) const {
+  return is_max() ? std::numeric_limits<T>::max()
+                  : static_cast<T>(delta_ / divisor);
+}
+
+// Must be defined before use below.
+template <>
+constexpr double TimeDelta::DivideOrMax<double>(int64_t divisor) const {
+  return is_max() ? std::numeric_limits<double>::infinity()
+                  : static_cast<double>(delta_) / divisor;
+}
+
+constexpr int TimeDelta::InDays() const {
+  return DivideOrMax<int>(Time::kMicrosecondsPerDay);
+}
+
+constexpr int TimeDelta::InHours() const {
+  return DivideOrMax<int>(Time::kMicrosecondsPerHour);
+}
+
+constexpr int TimeDelta::InMinutes() const {
+  return DivideOrMax<int>(Time::kMicrosecondsPerMinute);
+}
+
+constexpr double TimeDelta::InSecondsF() const {
+  return DivideOrMax<double>(Time::kMicrosecondsPerSecond);
+}
+
+constexpr int64_t TimeDelta::InSeconds() const {
+  return DivideOrMax<int64_t>(Time::kMicrosecondsPerSecond);
+}
+
+constexpr double TimeDelta::InMillisecondsF() const {
+  return DivideOrMax<double>(Time::kMicrosecondsPerMillisecond);
+}
+
+constexpr int64_t TimeDelta::InMilliseconds() const {
+  return DivideOrMax<int64_t>(Time::kMicrosecondsPerMillisecond);
+}
+
+constexpr int64_t TimeDelta::InMicroseconds() const {
+  return DivideOrMax<int64_t>(1);
+}
+
+constexpr double TimeDelta::InMicrosecondsF() const {
+  return DivideOrMax<double>(1);
+}
+
+constexpr int64_t TimeDelta::InNanoseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64_t>::max();
+  }
+  return delta_ * Time::kNanosecondsPerMicrosecond;
+}
+
 // static
 constexpr TimeDelta TimeDelta::FromDouble(double value) {
   // TODO(crbug.com/612601): Use saturated_cast<int64_t>(value) once we sort out
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 3799dad..c74f288 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -120,7 +120,7 @@
     if (is_chromecast && chromecast_branding != "public") {
       google_play_services_package = "//chromecast/internal/android/prebuilt/google-play-services-first-party"
     } else {
-      google_play_services_package = "//third_party/android_tools"
+      google_play_services_package = "//third_party/android_deps"
     }
   }
 
diff --git a/build/config/fuchsia/package.gni b/build/config/fuchsia/package.gni
index 448b5fed..fc109349 100644
--- a/build/config/fuchsia/package.gni
+++ b/build/config/fuchsia/package.gni
@@ -12,7 +12,9 @@
 #     if different than |target_name|.
 # binary: The executable target which should be launched.
 # sandbox_policy: A path to the sandbox_policy that will be used.
-#     Defaults to //build/config/fuchsia/sandbox_policy.
+#     "testonly" targets default to using
+#     //build/config/fuchsia/testing_sandbox_policy by default.
+#     Non-test targets must explicitly specify a |sandbox_policy|.
 # deps: Additional targets to build and include in the package (optional).
 template("fuchsia_package") {
   pkg = {
@@ -25,7 +27,8 @@
     }
 
     if (!defined(sandbox_policy)) {
-      sandbox_policy = "//build/config/fuchsia/sandbox_policy"
+      assert(testonly == true)
+      sandbox_policy = "//build/config/fuchsia/testing_sandbox_policy"
     }
   }
   assert(defined(pkg.binary))
diff --git a/build/config/fuchsia/rules.gni b/build/config/fuchsia/rules.gni
index 5194707b..59921c9 100644
--- a/build/config/fuchsia/rules.gni
+++ b/build/config/fuchsia/rules.gni
@@ -23,6 +23,8 @@
 #       prior to execution.
 #   runner_script: The runner script implementation to use, relative to
 #       "build/fuchsia". Defaults to "exe_runner.py".
+#   install_only: If true, executing the script will only install the package
+#       on the device, but not run it.
 template("fuchsia_package_runner") {
   forward_variables_from(invoker, [ "runner_script" ])
 
@@ -36,84 +38,128 @@
              "/" + _pkg_shortname
   _manifest_path = "$_pkg_dir/${_pkg_shortname}.archive_manifest"
   _package_path = "$_pkg_dir/${_pkg_shortname}.far"
-  _generated_script_path = "$root_build_dir/bin/run_$_pkg_shortname"
 
   if (!defined(runner_script)) {
     runner_script = "//build/fuchsia/exe_runner.py"
   }
 
-  action(target_name) {
-    forward_variables_from(invoker,
-                           [
-                             "target",
-                             "testonly",
-                           ])
+  generated_run_pkg_script_path = "$root_build_dir/bin/run_${_pkg_shortname}"
+  generated_install_pkg_script_path =
+      "$root_build_dir/bin/install_$_pkg_shortname"
 
-    deps = [
-      "//build/config/fuchsia:blobstore_extended_qcow2",
-      invoker.package,
-    ]
+  _generate_runner_target = "${target_name}__generate_runner"
+  _generate_installer_target = "${target_name}__generate_installer"
+  _generate_template = "${target_name}__generate_template"
 
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
+  # Generates a script to install and optionally run a package.
+  #
+  # Parameters:
+  #   |install_only|: If true, builds a script that only installs a package.
+  #   |script_path|: The path of the script to generate.
+  template(_generate_template) {
+    action(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "install_only",
+                               "script_path",
+                               "target",
+                               "testonly",
+                             ])
 
-    script = "//build/fuchsia/create_runner_script.py"
+      deps = [
+        "//build/config/fuchsia:blobstore_extended_qcow2",
+        invoker.package,
+      ]
 
-    outputs = [
-      _generated_script_path,
-    ]
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
 
-    data = [
-      _generated_script_path,
-      _manifest_path,
-      "//build/fuchsia/",
-      "//build/util/lib/",
-      "${qemu_root}/",
-      "${fuchsia_sdk}/",
-    ]
+      script = "//build/fuchsia/create_runner_script.py"
 
-    data_deps = [
-      invoker.package,
-    ]
+      outputs = [
+        script_path,
+      ]
 
-    # Arguments used at build time by the runner script generator.
-    args = [
-      "--script-output-path",
-      rebase_path(_generated_script_path, root_build_dir, root_out_dir),
-    ]
+      data = [
+        script_path,
+        _manifest_path,
+        "//build/fuchsia/",
+        "//build/util/lib/",
+        "${qemu_root}/",
+        "${fuchsia_sdk}/",
+      ]
 
-    if (defined(invoker.use_test_server) && invoker.use_test_server) {
-      args += [ "--enable-test-server" ]
-    }
+      data_deps = [
+        invoker.package,
+      ]
 
-    if (defined(invoker.package_deps)) {
-      foreach(cur_package, invoker.package_deps) {
-        deps += [ cur_package[0] ]
-        dep_package_path =
-            "$root_out_dir/gen/" + get_label_info(cur_package[0], "dir") + "/" +
-            cur_package[1] + "/" + cur_package[1] + ".far"
-        args += [
-          "--package-dep",
-          rebase_path(dep_package_path, root_out_dir, root_build_dir),
-        ]
+      # Arguments used at build time by the runner script generator.
+      args = [
+        "--script-output-path",
+        rebase_path(script_path, root_build_dir, root_out_dir),
+      ]
+
+      if (defined(invoker.use_test_server) && invoker.use_test_server) {
+        args += [ "--enable-test-server" ]
+      }
+
+      if (defined(invoker.package_deps)) {
+        foreach(cur_package, invoker.package_deps) {
+          deps += [ cur_package[0] ]
+          dep_package_path =
+              "$root_out_dir/gen/" + get_label_info(cur_package[0], "dir") +
+              "/" + cur_package[1] + "/" + cur_package[1] + ".far"
+          args += [
+            "--package-dep",
+            rebase_path(dep_package_path, root_out_dir, root_build_dir),
+          ]
+        }
+      }
+
+      # Arguments used at runtime by the test runner.
+      args += [
+        "--runner-script",
+        rebase_path(runner_script, root_out_dir),
+        "--output-directory",
+        rebase_path(root_build_dir, root_build_dir),
+        "--target-cpu",
+        target_cpu,
+        "--package",
+        rebase_path(_package_path, root_out_dir, root_build_dir),
+        "--package-name",
+        _pkg_shortname,
+        "--package-manifest",
+        rebase_path(_manifest_path),
+      ]
+
+      if (defined(install_only) && install_only) {
+        args += [ "--install-only" ]
       }
     }
+  }
 
-    # Arguments used at runtime by the test runner.
-    args += [
-      "--runner-script",
-      rebase_path(runner_script, root_out_dir),
-      "--output-directory",
-      rebase_path(root_build_dir, root_build_dir),
-      "--target-cpu",
-      target_cpu,
-      "--package",
-      rebase_path(_package_path, root_out_dir, root_build_dir),
-      "--package-name",
-      _pkg_shortname,
-      "--package-manifest",
-      rebase_path(_manifest_path),
+  target(_generate_template, _generate_runner_target) {
+    forward_variables_from(invoker, "*")
+    script_path = generated_run_pkg_script_path
+  }
+
+  target(_generate_template, _generate_installer_target) {
+    forward_variables_from(invoker, "*")
+    script_path = generated_install_pkg_script_path
+    install_only = true
+  }
+
+  # Build the installer script, and the runner for non-|install_only| targets.
+  group(target_name) {
+    forward_variables_from(invoker, [ "testonly" ])
+    deps = [
+      ":${_generate_installer_target}",
     ]
+
+    # Generate a runner script if the target is not install-only.
+    if (!defined(invoker.install_only)) {
+      deps += [ ":${_generate_runner_target}" ]
+    }
   }
 }
diff --git a/build/config/fuchsia/sandbox_policy b/build/config/fuchsia/sandbox_policy
deleted file mode 100644
index bbf871d3..0000000
--- a/build/config/fuchsia/sandbox_policy
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "features": [ "persistent-storage", "root-ssl-certificates", "system-temp",
-      "deprecated-all-services", "vulkan" ]
-}
diff --git a/build/config/fuchsia/testing_sandbox_policy b/build/config/fuchsia/testing_sandbox_policy
index 9da8b22..e3a67a08 100644
--- a/build/config/fuchsia/testing_sandbox_policy
+++ b/build/config/fuchsia/testing_sandbox_policy
@@ -1,5 +1,15 @@
 {
   "features": [ "persistent-storage", "root-ssl-certificates", "system-temp",
-      "deprecated-all-services", "vulkan" ],
-  "dev": ["null", "zero"]
+      "vulkan" ],
+  "dev": ["null", "zero"],
+  "services": [
+      "fuchsia.fonts.FontProvider",
+      "fuchsia.media.Audio",
+      "fuchsia.net.LegacySocketProvider",
+      "fuchsia.netstack.Netstack",
+      "fuchsia.process.Launcher",
+      "fuchsia.ui.policy.Presenter",
+      "fuchsia.ui.scenic.Scenic",
+      "fuchsia.ui.viewsv1.ViewManager"
+  ]
 }
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index 6d3bb68..902bdbf 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -61,67 +61,6 @@
     include_java_resources = true
   }
 
-  template("android_deps_alias") {
-    java_group(target_name) {
-      deps = [
-        "//third_party/android_deps:${invoker.android_deps_target_name}",
-      ]
-    }
-  }
-  android_deps_alias("google_play_services_basement_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_basement_java"
-  }
-  android_deps_alias("google_play_services_tasks_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_tasks_java"
-  }
-  android_deps_alias("google_play_services_base_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_base_java"
-  }
-  android_deps_alias("google_play_services_auth_base_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_auth_base_java"
-  }
-  android_deps_alias("google_play_services_auth_api_phone_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_auth_api_phone_java"
-  }
-  android_deps_alias("google_play_services_auth_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_auth_java"
-  }
-  android_deps_alias("google_play_services_cast_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_cast_java"
-  }
-  android_deps_alias("google_play_services_cast_framework_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_cast_framework_java"
-  }
-  android_deps_alias("google_play_services_iid_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_iid_java"
-  }
-  android_deps_alias("google_play_services_instantapps_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_instantapps_java"
-  }
-  android_deps_alias("google_play_services_gcm_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_gcm_java"
-  }
-  android_deps_alias("google_play_services_location_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_location_java"
-  }
-  android_deps_alias("google_play_services_vision_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_vision_java"
-  }
-  android_deps_alias("google_play_services_vision_common_java") {
-    android_deps_target_name =
-        "com_google_android_gms_play_services_vision_common_java"
-  }
-  android_deps_alias("google_play_services_fido_java") {
-    android_deps_target_name = "com_google_android_gms_play_services_fido_java"
-  }
-
   # The current version of //third_party/byte_buddy relies on an older
   # version of dx.
   java_prebuilt("dx_25_0_2_java") {
diff --git a/build/secondary/third_party/catapult/devil/devil_arm.gni b/build/secondary/third_party/catapult/devil/devil_arm.gni
deleted file mode 100644
index 97503c1..0000000
--- a/build/secondary/third_party/catapult/devil/devil_arm.gni
+++ /dev/null
@@ -1,5 +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.
-
-# TODO(jbudorick): Remove this file once devil no longer references it.
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index 7f90bd5d..6b9e900 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -103,7 +103,16 @@
   if (surface_hit_testable_ == surface_hit_testable)
     return;
   surface_hit_testable_ = surface_hit_testable;
+}
+
+void SurfaceLayer::SetHasPointerEventsNone(bool has_pointer_events_none) {
+  if (has_pointer_events_none_ == has_pointer_events_none)
+    return;
+  has_pointer_events_none_ = has_pointer_events_none;
   SetNeedsPushProperties();
+  // Change of pointer-events property triggers an update of viz hit test data,
+  // we need to commit in order to submit the new data with compositor frame.
+  SetNeedsCommit();
 }
 
 void SurfaceLayer::SetMayContainVideo(bool may_contain_video) {
@@ -145,6 +154,7 @@
   deadline_in_frames_ = 0u;
   layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_);
   layer_impl->SetSurfaceHitTestable(surface_hit_testable_);
+  layer_impl->SetHasPointerEventsNone(has_pointer_events_none_);
 }
 
 }  // namespace cc
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index 1d1d474..8a832fba 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -39,7 +39,8 @@
   }
 
   void SetSurfaceHitTestable(bool surface_hit_testable);
-  bool surface_hit_testable() const { return surface_hit_testable_; }
+
+  void SetHasPointerEventsNone(bool has_pointer_events_none);
 
   void SetMayContainVideo(bool);
 
@@ -84,6 +85,12 @@
   // be surface hit testable (e.g., a surface layer created by video).
   bool surface_hit_testable_ = false;
 
+  // Whether or not the surface can accept pointer events. It is set to true if
+  // the frame owner has pointer-events: none property.
+  // TODO(sunxd): consider renaming it to oopif_has_pointer_events_none_ for
+  // disambiguation.
+  bool has_pointer_events_none_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(SurfaceLayer);
 };
 
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index b86a128..ad3031e 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -86,6 +86,14 @@
   NoteLayerPropertyChanged();
 }
 
+void SurfaceLayerImpl::SetHasPointerEventsNone(bool has_pointer_events_none) {
+  if (has_pointer_events_none_ == has_pointer_events_none)
+    return;
+
+  has_pointer_events_none_ = has_pointer_events_none;
+  NoteLayerPropertyChanged();
+}
+
 void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
   LayerImpl::PushPropertiesTo(layer);
   SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer);
@@ -95,6 +103,7 @@
   deadline_in_frames_ = 0u;
   layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_);
   layer_impl->SetSurfaceHitTestable(surface_hit_testable_);
+  layer_impl->SetHasPointerEventsNone(has_pointer_events_none_);
 }
 
 bool SurfaceLayerImpl::WillDraw(
diff --git a/cc/layers/surface_layer_impl.h b/cc/layers/surface_layer_impl.h
index f67e362..64ff796 100644
--- a/cc/layers/surface_layer_impl.h
+++ b/cc/layers/surface_layer_impl.h
@@ -54,7 +54,12 @@
   }
 
   void SetSurfaceHitTestable(bool surface_hit_testable);
-  bool surface_hit_testable() const { return surface_hit_testable_; }
+  bool ShouldGenerateSurfaceHitTestData() const {
+    return surface_hit_testable_ && !has_pointer_events_none_;
+  }
+
+  void SetHasPointerEventsNone(bool has_pointer_events_none);
+  bool has_pointer_events_none() const { return has_pointer_events_none_; }
 
   // LayerImpl overrides.
   std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -84,6 +89,7 @@
 
   bool stretch_content_to_fill_bounds_ = false;
   bool surface_hit_testable_ = false;
+  bool has_pointer_events_none_ = false;
   bool will_draw_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceLayerImpl);
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
index 212bdc9..4383a9e 100644
--- a/cc/mojo_embedder/async_layer_tree_frame_sink.cc
+++ b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -252,14 +252,19 @@
   const char* client_name = GetClientNameForMetrics();
   if (client_name && args.trace_id != -1) {
     base::TimeTicks current_time = base::TimeTicks::Now();
-    base::TimeDelta frame_difference = current_time - args.frame_time;
     PipelineReporting report(args, current_time);
     pipeline_reporting_frame_times_.emplace(args.trace_id, report);
-    UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
-        base::StringPrintf("GraphicsPipeline.%s.ReceivedBeginFrame",
-                           client_name),
-        frame_difference, base::TimeDelta::FromMicroseconds(1),
-        base::TimeDelta::FromMilliseconds(100), 50);
+    // Missed BeginFrames use the frame time of the last received BeginFrame
+    // which is bogus from a reporting perspective if nothing has been updating
+    // on screen for a while.
+    if (args.type != viz::BeginFrameArgs::MISSED) {
+      base::TimeDelta frame_difference = current_time - args.frame_time;
+      UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+          base::StringPrintf("GraphicsPipeline.%s.ReceivedBeginFrame",
+                             client_name),
+          frame_difference, base::TimeDelta::FromMicroseconds(1),
+          base::TimeDelta::FromMilliseconds(100), 50);
+    }
   }
 
   if (!needs_begin_frames_) {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 77b82a4..2675af2 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2600,9 +2600,18 @@
 
     if (layer->is_surface_layer()) {
       const auto* surface_layer = static_cast<const SurfaceLayerImpl*>(layer);
-      if (!surface_layer->surface_hit_testable()) {
-        overlapping_region.Union(MathUtil::MapEnclosingClippedRect(
-            layer->ScreenSpaceTransform(), gfx::Rect(surface_layer->bounds())));
+      // If a surface layer is created not by child frame compositor or the
+      // frame owner has pointer-events: none property, the surface layer
+      // becomes not hit testable. We should not generate data for it.
+      if (!surface_layer->ShouldGenerateSurfaceHitTestData()) {
+        // If a surface layer is created due to video or offscreen canvas, it
+        // can still block overlapped surface layers from getting events, we
+        // need to account for all layers that don't have pointer-events: none.
+        if (!surface_layer->has_pointer_events_none()) {
+          overlapping_region.Union(MathUtil::MapEnclosingClippedRect(
+              layer->ScreenSpaceTransform(),
+              gfx::Rect(surface_layer->bounds())));
+        }
         continue;
       }
 
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 9362c11..08567303 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1193,16 +1193,13 @@
   testonly = true
   sources = [
     "../browser/android/chrome_sync_shell_entry_point.cc",
-    "js_utils.cc",
   ]
   deps = [
-    ":chrome_sync_shell_jni",
     ":chrome_sync_shell_jni_registration($default_toolchain)",
     "//chrome:chrome_android_core",
     "//chrome/browser/android/metrics:ukm_utils_for_test",
     "//components/sync",
     "//components/sync:test_support_fake_server_android",
-    "//content/public/test/android:content_native_test_support",
   ]
   if (chromium_linker_supported && use_lld) {
     configs += [ "//build/config/android:lld_pack_relocations" ]
@@ -1214,13 +1211,6 @@
   }
 }
 
-generate_jni("chrome_sync_shell_jni") {
-  sources = [
-    "sync_shell/javatests/src/org/chromium/chrome/browser/sync/JsUtils.java",
-  ]
-  jni_package = "sync_shell_test"
-}
-
 # Java libraries that go into each public chrome APK and base module. The chrome
 # JNI registration is generated based on this target.
 # TODO(tiborg): Remove the following three groups once we have a APK / module
@@ -1250,17 +1240,11 @@
 # Similar to chrome_public_base_module_java but for Java libraries that go into
 # the chrome sync shell APK.
 android_library("chrome_sync_shell_java") {
-  testonly = true
-
   # This exists here rather than in chrome_sync_shell_test_apk for JNI
   # registration to be able to find the native side functions.
-  java_files = [
-    "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java",
-    "sync_shell/javatests/src/org/chromium/chrome/browser/sync/JsUtils.java",
-  ]
+  java_files = [ "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java" ]
   deps = [
     ":chrome_public_base_module_java",
-    "//base:base_java_test_support",
 
     # This exists here because com.google.protobuf.nano is needed in tests,
     # but that code is stripped out via proguard. Adding this deps adds
@@ -1507,11 +1491,7 @@
   deps = _chrome_public_and_sync_shell_shared_deps + [
            ":chrome_sync_shell_apk_template_resources",
            ":chrome_sync_shell_java",
-           "//third_party/android_tools:android_test_mock_java",
          ]
-  if (!is_java_debug) {
-    proguard_configs = [ "//chrome/android/java/apk_for_test.flags" ]
-  }
 }
 
 chrome_public_test_apk_manifest =
diff --git a/chrome/android/java/res/drawable-hdpi/btn_tab_close.png b/chrome/android/java/res/drawable-hdpi/btn_tab_close.png
deleted file mode 100644
index 4e50059..0000000
--- a/chrome/android/java/res/drawable-hdpi/btn_tab_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/btn_tabswitcher.png b/chrome/android/java/res/drawable-hdpi/btn_tabswitcher.png
deleted file mode 100644
index c596b30..0000000
--- a/chrome/android/java/res/drawable-hdpi/btn_tabswitcher.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/btn_tab_close.png b/chrome/android/java/res/drawable-mdpi/btn_tab_close.png
deleted file mode 100644
index 6669bff..0000000
--- a/chrome/android/java/res/drawable-mdpi/btn_tab_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/btn_tabswitcher.png b/chrome/android/java/res/drawable-mdpi/btn_tabswitcher.png
deleted file mode 100644
index 94c46fc2..0000000
--- a/chrome/android/java/res/drawable-mdpi/btn_tabswitcher.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/btn_tab_close.png b/chrome/android/java/res/drawable-xhdpi/btn_tab_close.png
deleted file mode 100644
index 8bcdebc0..0000000
--- a/chrome/android/java/res/drawable-xhdpi/btn_tab_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/btn_tabswitcher.png b/chrome/android/java/res/drawable-xhdpi/btn_tabswitcher.png
deleted file mode 100644
index 9d2a59b..0000000
--- a/chrome/android/java/res/drawable-xhdpi/btn_tabswitcher.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/btn_tab_close.png b/chrome/android/java/res/drawable-xxhdpi/btn_tab_close.png
deleted file mode 100644
index 7378967..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/btn_tab_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/btn_tabswitcher.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabswitcher.png
deleted file mode 100644
index 9e8e0ec..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/btn_tabswitcher.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close.png
deleted file mode 100644
index 3b4c3320..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/btn_tabswitcher.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabswitcher.png
deleted file mode 100644
index ee2d82d..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/btn_tabswitcher.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/layout/toolbar_tablet.xml b/chrome/android/java/res/layout/toolbar_tablet.xml
index 6fdda0c..42b2376 100644
--- a/chrome/android/java/res/layout/toolbar_tablet.xml
+++ b/chrome/android/java/res/layout/toolbar_tablet.xml
@@ -58,7 +58,7 @@
             android:layout_weight="1"
             android:layout_gravity="center_vertical"
             android:background="@drawable/modern_toolbar_background"
-            android:paddingEnd="1dp"
+            android:paddingEnd="@dimen/location_bar_lateral_padding"
             android:paddingStart="2dp" />
 
         <ImageButton
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 794ca8db..fb428f0 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -223,21 +223,6 @@
         <item name="android:background">@color/modern_grey_600</item>
     </style>
 
-    <!-- Dividers -->
-    <style name="HorizontalDivider">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">@dimen/divider_height</item>
-        <item name="android:background">?android:attr/listDivider</item>
-        <item name="android:importantForAccessibility">no</item>
-    </style>
-    <style name="VerticalDivider">
-        <item name="android:layout_width">@dimen/divider_height</item>
-        <item name="android:layout_height">match_parent</item>
-        <item name="android:background">?android:attr/listDivider</item>
-        <item name="android:importantForAccessibility">no</item>
-    </style>
-
-
     <style name="ThemeWithActionBarBase" parent="Theme.AppCompat.Light">
         <item name="android:windowBackground">@drawable/action_bar_activity_bg</item>
         <!-- Action bar color -->
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 248b01e..f4b346e 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -78,7 +78,6 @@
     <!-- Omnibox Suggestion colors -->
     <color name="suggestion_url_dark_modern">@color/default_text_color_link</color>
     <color name="suggestion_url_light_modern">@color/modern_blue_300</color>
-    <color name="suggestion_url_light">#5595FE</color>
     <color name="answers_description_text_negative">@color/google_red_700</color>
     <color name="answers_description_text_positive">@color/google_green_700</color>
     <color name="answers_answer_text">#8A8A8A</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 34b3f85..7b2cc51 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -274,7 +274,6 @@
     <dimen name="location_bar_lateral_padding">10dp</dimen>
 
     <dimen name="tablet_toolbar_start_padding">4dp</dimen>
-    <dimen name="tablet_toolbar_start_padding_no_buttons">6dp</dimen>
     <dimen name="tablet_toolbar_end_padding">6dp</dimen>
     <dimen name="location_bar_status_separator_width">1dp</dimen>
 
@@ -288,7 +287,6 @@
     <dimen name="omnibox_suggestion_height">60dp</dimen>
     <dimen name="omnibox_suggestion_answer_height">72dp</dimen>
     <dimen name="omnibox_suggestion_definition_height">95dp</dimen>
-    <dimen name="omnibox_suggestion_list_padding_top">8dp</dimen>
     <dimen name="omnibox_suggestion_list_padding_bottom">8dp</dimen>
     <dimen name="omnibox_suggestion_first_line_text_size">16sp</dimen>
     <dimen name="omnibox_suggestion_second_line_text_size">14sp</dimen>
@@ -535,9 +533,6 @@
     <dimen name="context_menu_image_vertical_margin">30dp</dimen>
     <dimen name="context_menu_selectable_items_min_size">120dp</dimen>
 
-    <!-- Divider Dimensions -->
-    <dimen name="divider_height">1dp</dimen>
-
     <!-- Reader Mode dimensions -->
     <!-- Padding surrounding the message. -->
     <dimen name="reader_mode_infobar_text_padding">8dp</dimen>
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 d186567..cc6d7d13 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -912,12 +912,10 @@
     protected void setStatusBarColor(int color, boolean isDefaultThemeColor) {
         if (UiUtils.isSystemUiThemingDisabled()) return;
 
-        boolean useModernDesign =
-                supportsModernDesign() && FeatureUtilities.isChromeModernDesignEnabled();
         int statusBarColor = color;
         boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
         View root = getWindow().getDecorView().getRootView();
-        if (useModernDesign && supportsDarkStatusIcons) {
+        if (supportsDarkStatusIcons) {
             mBaseStatusBarColor = color;
 
             if (mScrimColor == 0) {
@@ -2475,13 +2473,6 @@
     }
 
     /**
-     * @return Whether this Activity supports modern design.
-     */
-    public boolean supportsModernDesign() {
-        return false;
-    }
-
-    /**
      * @return Whether this Activity supports showing contextual suggestions in a bottom sheet.
      */
     public boolean supportsContextualSuggestionsBottomSheet() {
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 e92de58..7a26ee5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2229,8 +2229,7 @@
         }
 
         boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
-        if (!supportsDarkStatusIcons || !supportsModernDesign()
-                || !FeatureUtilities.isChromeModernDesignEnabled()) {
+        if (!supportsDarkStatusIcons) {
             super.setStatusBarColor(tab, Color.BLACK);
             return;
         }
@@ -2410,11 +2409,6 @@
     }
 
     @Override
-    public boolean supportsModernDesign() {
-        return true;
-    }
-
-    @Override
     public boolean supportsContextualSuggestionsBottomSheet() {
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
index 6ec00057..c55c950 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
+import org.chromium.chrome.browser.webapps.WebappActivity;
 import org.chromium.ui.DropdownPopupWindow;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -138,6 +139,8 @@
     void initialize(KeyboardAccessoryCoordinator keyboardAccessory,
             AccessorySheetCoordinator accessorySheet, WindowAndroid windowAndroid) {
         assert windowAndroid.getActivity().get() != null;
+        // Abort initialization for PWAs: https://crbug.com/881536.
+        if (windowAndroid.getActivity().get() instanceof WebappActivity) return;
         mWindowAndroid = windowAndroid;
         mKeyboardAccessory = keyboardAccessory;
         mAccessorySheet = accessorySheet;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index b9d83ad..8b32f05 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -50,7 +50,6 @@
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.widget.ControlContainer;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.KeyboardVisibilityDelegate;
@@ -842,13 +841,6 @@
     }
 
     @Override
-    public float getBrowserControlsUrlBarAlpha() {
-        return mTabVisible == null
-                ? 1.f
-                : ColorUtils.getTextBoxAlphaForToolbarBackground(mTabVisible);
-    }
-
-    @Override
     public int getTopControlsHeightPixels() {
         return mFullscreenManager != null ? mFullscreenManager.getTopControlsHeight() : 0;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
index a1a0b1f7..fd20386 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
@@ -4,21 +4,16 @@
 
 package org.chromium.chrome.browser.compositor.layouts;
 
-import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.createAnimation;
-
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.support.annotation.IntDef;
 import android.view.MotionEvent;
 import android.view.ViewGroup;
-import android.view.animation.Interpolator;
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.animation.CompositorAnimationHandler;
-import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
-import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animation;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -96,8 +91,6 @@
     protected TabModelSelector mTabModelSelector;
     protected TabContentManager mTabContentManager;
 
-    private ChromeAnimation<Animatable> mLayoutAnimations;
-
     // Tablet tab strip managers.
     private final List<SceneOverlay> mSceneOverlays = new ArrayList<SceneOverlay>();
 
@@ -209,8 +202,8 @@
      * @param isTitleNeeded   Whether a title will be shown.
      * @return                The newly created {@link LayoutTab}.
      */
-    public LayoutTab createLayoutTab(int id, boolean isIncognito,
-            boolean showCloseButton, boolean isTitleNeeded) {
+    public LayoutTab createLayoutTab(
+            int id, boolean isIncognito, boolean showCloseButton, boolean isTitleNeeded) {
         return createLayoutTab(id, isIncognito, showCloseButton, isTitleNeeded, -1.f, -1.f);
     }
 
@@ -538,19 +531,13 @@
      * @param vx   The horizontal velocity of the fling.
      * @param vy   The vertical velocity of the fling.
      */
-    public void swipeFlingOccurred(long time, float x, float y, float tx, float ty, float vx,
-            float vy) { }
+    public void swipeFlingOccurred(
+            long time, float x, float y, float tx, float ty, float vx, float vy) {}
 
     /**
      * Forces the current animation to finish and broadcasts the proper event.
      */
-    protected void forceAnimationToFinish() {
-        if (mLayoutAnimations != null) {
-            mLayoutAnimations.updateAndFinish();
-            mLayoutAnimations = null;
-            onAnimationFinished();
-        }
-    }
+    protected void forceAnimationToFinish() {}
 
     /**
      * @return The width of the drawing area in dp.
@@ -837,24 +824,7 @@
      * @return          Whether the animation was finished.
      */
     protected boolean onUpdateAnimation(long time, boolean jumpToEnd) {
-        boolean finished = true;
-        if (mLayoutAnimations != null) {
-            if (jumpToEnd) {
-                finished = mLayoutAnimations.finished();
-                mLayoutAnimations.updateAndFinish();
-            } else {
-                finished = mLayoutAnimations.update(time);
-            }
-
-            if (finished || jumpToEnd) {
-                mLayoutAnimations = null;
-                onAnimationFinished();
-            }
-        }
-
-        if (!finished) requestUpdate();
-
-        return finished;
+        return true;
     }
 
     /**
@@ -862,86 +832,7 @@
      */
     @VisibleForTesting
     public boolean isLayoutAnimating() {
-        return mLayoutAnimations != null && !mLayoutAnimations.finished();
-    }
-
-    /**
-     * Called when layout-specific actions are needed after the animation finishes.
-     */
-    protected void onAnimationStarted() {
-    }
-
-    /**
-     * Called when layout-specific actions are needed after the animation finishes.
-     */
-    protected void onAnimationFinished() {
-    }
-
-    /**
-     * Creates an {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation
-     * .AnimatableAnimation} and adds it to the animation.
-     * Automatically sets the start value at the beginning of the animation.
-     */
-    protected void addToAnimation(
-            Animatable object, int prop, float start, float end, long duration, long startTime) {
-        addToAnimation(object, prop, start, end, duration, startTime, false);
-    }
-
-    /**
-     * Creates an {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation
-     * .AnimatableAnimation} and it to the animation. Uses a deceleration interpolator by default.
-     */
-    protected void addToAnimation(Animatable object, int prop, float start, float end,
-            long duration, long startTime, boolean setStartValueAfterDelay) {
-        addToAnimation(object, prop, start, end, duration, startTime, setStartValueAfterDelay,
-                ChromeAnimation.getDecelerateInterpolator());
-    }
-
-    /**
-     * Creates an {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation
-     * .AnimatableAnimation} and
-     * adds it to the animation.
-     *
-     * @param <T>                     The Enum type of the Property being used
-     * @param object                  The object being animated
-     * @param prop                    The property being animated
-     * @param start                   The starting value of the animation
-     * @param end                     The ending value of the animation
-     * @param duration                The duration of the animation in ms
-     * @param startTime               The start time in ms
-     * @param setStartValueAfterDelay See {@link Animation#setStartValueAfterStartDelay(boolean)}
-     * @param interpolator            The interpolator to use for the animation
-     */
-    protected void addToAnimation(Animatable object, int prop, float start, float end,
-            long duration, long startTime, boolean setStartValueAfterDelay,
-            Interpolator interpolator) {
-        ChromeAnimation.Animation<Animatable> component = createAnimation(object, prop, start, end,
-                duration, startTime, setStartValueAfterDelay, interpolator);
-        addToAnimation(component);
-    }
-
-    /**
-     * Appends an Animation to the current animation set and starts it immediately.  If the set is
-     * already finished or doesn't exist, the animation set is also started.
-     */
-    protected void addToAnimation(ChromeAnimation.Animation<Animatable> component) {
-        if (mLayoutAnimations == null || mLayoutAnimations.finished()) {
-            onAnimationStarted();
-            mLayoutAnimations = new ChromeAnimation<Animatable>();
-            mLayoutAnimations.start();
-        }
-        component.start();
-        mLayoutAnimations.add(component);
-        requestUpdate();
-    }
-
-    /**
-     * Cancels any animation for the given object and property.
-     * @param object The object being animated.
-     * @param prop   The property to search for.
-     */
-    protected void cancelAnimation(Animatable object, int prop) {
-        if (mLayoutAnimations != null) mLayoutAnimations.cancel(object, prop);
+        return false;
     }
 
     /**
@@ -1113,13 +1004,7 @@
      */
     protected void updateSceneLayer(RectF viewport, RectF contentViewport,
             LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
-            ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {
-    }
-
-    @VisibleForTesting
-    public void finishAnimationsForTests() {
-        if (mLayoutAnimations != null) mLayoutAnimations.updateAndFinish();
-    }
+            ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {}
 
     /**
      * Gets the full screen manager.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
index a22e74cd..f4a932f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
@@ -47,7 +47,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.base.SPenSupport;
 import org.chromium.ui.resources.ResourceManager;
@@ -690,12 +689,10 @@
         boolean isNtp = tab.getNativePage() instanceof NewTabPage;
         boolean isLocationBarShownInNtp =
                 isNtp ? ((NewTabPage) tab.getNativePage()).isLocationBarShownInNTP() : false;
-        boolean useModernDesign = FeatureUtilities.isChromeModernDesignEnabled()
-                && tab.getActivity() != null && tab.getActivity().supportsModernDesign();
         boolean needsUpdate = layoutTab.initFromHost(tab.getBackgroundColor(), tab.shouldStall(),
                 canUseLiveTexture, themeColor,
-                ColorUtils.getTextBoxColorForToolbarBackground(mContext.getResources(),
-                        isLocationBarShownInNtp, themeColor, useModernDesign),
+                ColorUtils.getTextBoxColorForToolbarBackground(
+                        mContext.getResources(), isLocationBarShownInNtp, themeColor, true),
                 ColorUtils.getTextBoxAlphaForToolbarBackground(tab));
         if (needsUpdate) requestUpdate();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutRenderHost.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutRenderHost.java
index d10bade..00c3e75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutRenderHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutRenderHost.java
@@ -57,11 +57,6 @@
     int getBrowserControlsBackgroundColor();
 
     /**
-     * @return The alpha value of the textbox in the toolbar.
-     */
-    float getBrowserControlsUrlBarAlpha();
-
-    /**
      * @return The {@link ResourceManager}.
      */
     ResourceManager getResourceManager();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
index 1c46d44..9a7d045 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
@@ -10,6 +10,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
+import org.chromium.chrome.browser.compositor.animation.CompositorAnimator;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -43,10 +44,15 @@
         public void run() {
             mUnstalling = false;
             if (mLayoutTabs == null || mLayoutTabs.length == 0) return;
-            addToAnimation(mLayoutTabs[0], LayoutTab.Property.SATURATION,
-                    mLayoutTabs[0].getSaturation(), 1.0f, HIDE_DURATION_MS, 0);
-            addToAnimation(mLayoutTabs[0], LayoutTab.Property.STATIC_TO_VIEW_BLEND,
-                    mLayoutTabs[0].getStaticToViewBlend(), 0.0f, HIDE_DURATION_MS, 0);
+            CompositorAnimator
+                    .ofFloatProperty(getAnimationHandler(), mLayoutTabs[0], LayoutTab.SATURATION,
+                            mLayoutTabs[0].getSaturation(), 1.0f, HIDE_DURATION_MS)
+                    .start();
+            CompositorAnimator
+                    .ofFloatProperty(getAnimationHandler(), mLayoutTabs[0],
+                            LayoutTab.STATIC_TO_VIEW_BLEND, mLayoutTabs[0].getStaticToViewBlend(),
+                            0.0f, HIDE_DURATION_MS)
+                    .start();
             mLayoutTabs[0].setShouldStall(false);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/LayoutTab.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/LayoutTab.java
index 699404f..dbe89c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/LayoutTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/LayoutTab.java
@@ -1020,6 +1020,19 @@
                 }
             };
 
+    public static final FloatProperty<LayoutTab> SATURATION =
+            new FloatProperty<LayoutTab>("SATURATION") {
+                @Override
+                public void setValue(LayoutTab layoutTab, float v) {
+                    layoutTab.setSaturation(v);
+                }
+
+                @Override
+                public Float get(LayoutTab layoutTab) {
+                    return layoutTab.getSaturation();
+                }
+            };
+
     public static final FloatProperty<LayoutTab> SCALE = new FloatProperty<LayoutTab>("SCALE") {
         @Override
         public void setValue(LayoutTab layoutTab, float v) {
@@ -1032,6 +1045,19 @@
         }
     };
 
+    public static final FloatProperty<LayoutTab> STATIC_TO_VIEW_BLEND =
+            new FloatProperty<LayoutTab>("STATIC_TO_VIEW_BLEND") {
+                @Override
+                public void setValue(LayoutTab layoutTab, float v) {
+                    layoutTab.setStaticToViewBlend(v);
+                }
+
+                @Override
+                public Float get(LayoutTab layoutTab) {
+                    return layoutTab.getStaticToViewBlend();
+                }
+            };
+
     public static final FloatProperty<LayoutTab> X = new FloatProperty<LayoutTab>("X") {
         @Override
         public void setValue(LayoutTab layoutTab, float v) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
index 58ac01e..6e49af65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.compositor.layouts.phone;
 
+import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.createAnimation;
+
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -19,6 +21,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
+import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
@@ -190,6 +193,8 @@
 
     private StackLayoutGestureHandler mGestureHandler;
 
+    private ChromeAnimation<Animatable> mLayoutAnimations;
+
     private class StackLayoutGestureHandler implements GestureHandler {
         @Override
         public void onDown(float x, float y, boolean fromMouse, int buttons) {
@@ -628,7 +633,19 @@
 
     @Override
     public boolean onUpdateAnimation(long time, boolean jumpToEnd) {
-        boolean animationsWasDone = super.onUpdateAnimation(time, jumpToEnd);
+        boolean animationsWasDone = true;
+        if (mLayoutAnimations != null) {
+            if (jumpToEnd) {
+                animationsWasDone = mLayoutAnimations.finished();
+                mLayoutAnimations.updateAndFinish();
+            } else {
+                animationsWasDone = mLayoutAnimations.update(time);
+            }
+
+            if (animationsWasDone || jumpToEnd) {
+                mLayoutAnimations = null;
+            }
+        }
 
         boolean finishedAllViews = true;
         for (int i = 0; i < mStacks.size(); i++) {
@@ -660,14 +677,16 @@
      */
     public void onSwitchToFinished() {}
 
-    @Override
+    /**
+     * Called when layout-specific actions are needed after the animation finishes.
+     */
     protected void onAnimationStarted() {
-        if (mStackAnimationCount == 0) super.onAnimationStarted();
     }
 
-    @Override
+    /**
+     * Called when layout-specific actions are needed after the animation finishes.
+     */
     protected void onAnimationFinished() {
-        if (mStackAnimationCount == 0) super.onAnimationFinished();
     }
 
     /**
@@ -1509,7 +1528,6 @@
      * Called by the stacks whenever they start an animation.
      */
     public void onStackAnimationStarted() {
-        if (mStackAnimationCount == 0) super.onAnimationStarted();
         mStackAnimationCount++;
     }
 
@@ -1518,7 +1536,6 @@
      */
     public void onStackAnimationFinished() {
         mStackAnimationCount--;
-        if (mStackAnimationCount == 0) super.onAnimationFinished();
     }
 
     @Override
@@ -1542,4 +1559,46 @@
         mSceneLayer.pushLayers(getContext(), viewport, contentViewport, this, layerTitleCache,
                 tabContentManager, resourceManager, fullscreenManager);
     }
+
+    /**
+     * Creates an {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation
+     * .AnimatableAnimation} and adds it to the animation.
+     * Automatically sets the start value at the beginning of the animation.
+     */
+    protected void addToAnimation(
+            Animatable object, int prop, float start, float end, long duration, long startTime) {
+        ChromeAnimation.Animation<Animatable> component = createAnimation(object, prop, start, end,
+                duration, startTime, false, ChromeAnimation.getDecelerateInterpolator());
+        if (mLayoutAnimations == null || mLayoutAnimations.finished()) {
+            mLayoutAnimations = new ChromeAnimation<Animatable>();
+            mLayoutAnimations.start();
+        }
+        component.start();
+        mLayoutAnimations.add(component);
+        requestUpdate();
+    }
+
+    @Override
+    protected void forceAnimationToFinish() {
+        super.forceAnimationToFinish();
+        if (mLayoutAnimations != null) {
+            mLayoutAnimations.updateAndFinish();
+            mLayoutAnimations = null;
+        }
+    }
+
+    /**
+     * Cancels any animation for the given object and property.
+     * @param object The object being animated.
+     * @param prop   The property to search for.
+     */
+    protected void cancelAnimation(Animatable object, int prop) {
+        if (mLayoutAnimations != null) mLayoutAnimations.cancel(object, prop);
+    }
+
+    @Override
+    @VisibleForTesting
+    public boolean isLayoutAnimating() {
+        return mLayoutAnimations != null && !mLayoutAnimations.finished();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 9890bde56..f7b25d2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -13,6 +13,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
 import android.text.TextUtils;
 import android.view.MotionEvent;
@@ -1077,6 +1078,7 @@
      * @return The StripLayoutTab that corresponds to that tabid.
      */
     @VisibleForTesting
+    @Nullable
     public StripLayoutTab findTabById(int id) {
         if (mStripTabs == null) return null;
         for (int i = 0; i < mStripTabs.length; i++) {
@@ -1649,7 +1651,7 @@
         if (selectedTab == null) return;
 
         StripLayoutTab selectedLayoutTab = findTabById(selectedTab.getId());
-        if (isSelectedTabCompletelyVisible(selectedLayoutTab)) return;
+        if (selectedLayoutTab == null || isSelectedTabCompletelyVisible(selectedLayoutTab)) return;
 
         float delta = calculateOffsetToMakeTabVisible(selectedLayoutTab, true, true, true);
         setScrollForScrollingTabStacker(delta, animate, time);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
index 7dbee91c..331b984 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
@@ -19,7 +19,6 @@
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.ui.resources.ResourceManager;
 
 /**
@@ -71,20 +70,13 @@
             assert t.isVisible() : "LayoutTab in that list should be visible";
             final float decoration = t.getDecorationAlpha();
 
-            boolean useModernDesign = FeatureUtilities.isChromeModernDesignEnabled();
+            float shadowAlpha = decoration / 2;
+            int urlBarBackgroundId = R.drawable.modern_location_bar;
 
-            float shadowAlpha = decoration;
-            int urlBarBackgroundId = R.drawable.card_single;
-            if (useModernDesign) {
-                urlBarBackgroundId = R.drawable.modern_location_bar;
-                shadowAlpha /= 2;
-            }
-
-            int defaultThemeColor =
-                    ColorUtils.getDefaultThemeColor(res, useModernDesign, t.isIncognito());
+            int defaultThemeColor = ColorUtils.getDefaultThemeColor(res, true, t.isIncognito());
 
             // In the modern design, the text box is always drawn opaque in the compositor.
-            float textBoxAlpha = useModernDesign ? 1.f : t.getTextBoxAlpha();
+            float textBoxAlpha = 1.f;
 
             int closeButtonColor =
                     ColorUtils.getThemedAssetColor(defaultThemeColor, t.isIncognito());
@@ -92,12 +84,12 @@
             int borderColorResource =
                     t.isIncognito() ? R.color.tab_back_incognito : R.color.tab_back;
             // TODO(dtrainor, clholgat): remove "* dpToPx" once the native part fully supports dp.
-            nativePutTabLayer(mNativePtr, t.getId(), R.id.control_container, getCloseButtonIconId(),
-                    R.drawable.tabswitcher_border_frame_shadow,
+            nativePutTabLayer(mNativePtr, t.getId(), R.id.control_container,
+                    R.drawable.btn_close_white, R.drawable.tabswitcher_border_frame_shadow,
                     R.drawable.tabswitcher_border_frame_decoration, R.drawable.logo_card_back,
                     R.drawable.tabswitcher_border_frame,
                     R.drawable.tabswitcher_border_frame_inner_shadow, t.canUseLiveTexture(),
-                    FeatureUtilities.isChromeModernDesignEnabled(), t.getBackgroundColor(),
+                    t.getBackgroundColor(),
                     ApiCompatibilityUtils.getColor(res, borderColorResource), t.isIncognito(),
                     t.isCloseButtonOnRight(), t.getRenderX() * dpToPx, t.getRenderY() * dpToPx,
                     t.getScaledContentWidth() * dpToPx, t.getScaledContentHeight() * dpToPx,
@@ -121,20 +113,10 @@
     }
 
     /**
-     * @return The close button resource ID.
-     */
-    private int getCloseButtonIconId() {
-        if (FeatureUtilities.isChromeModernDesignEnabled()) return R.drawable.btn_close_white;
-
-        return R.drawable.btn_tab_close;
-    }
-
-    /**
      * @return The background color of the scene layer.
      */
     protected int getTabListBackgroundColor(Context context) {
-        int colorId = R.color.tab_switcher_background;
-        if (FeatureUtilities.isChromeModernDesignEnabled()) colorId = R.color.modern_primary_color;
+        int colorId = R.color.modern_primary_color;
 
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
             if (mTabModelSelector != null && mTabModelSelector.isIncognitoSelected()) {
@@ -178,8 +160,7 @@
     private native void nativePutTabLayer(long nativeTabListSceneLayer, int id,
             int toolbarResourceId, int closeButtonResourceId, int shadowResourceId,
             int contourResourceId, int backLogoResourceId, int borderResourceId,
-            int borderInnerShadowResourceId, boolean canUseLiveLayer,
-            boolean modernDesignEnabled, int tabBackgroundColor,
+            int borderInnerShadowResourceId, boolean canUseLiveLayer, int tabBackgroundColor,
             int backLogoColor, boolean incognito, boolean isPortrait, float x, float y, float width,
             float height, float contentWidth, float contentHeight, float visibleContentHeight,
             float shadowX, float shadowY, float shadowWidth, float shadowHeight, float pivotX,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
index 43265518..7c72d44 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.compositor.scene_layer;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.RectF;
 
 import org.chromium.base.annotations.JNINamespace;
@@ -22,7 +21,6 @@
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.ClipDrawableProgressBar.DrawingInfo;
 import org.chromium.chrome.browser.widget.ControlContainer;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -95,11 +93,7 @@
         boolean showShadow = fullscreenManager.drawControlsAsTexture()
                 || forceHideAndroidBrowserControls;
 
-        int textBoxColor = Color.WHITE;
-        int textBoxResourceId = R.drawable.card_single;
-
         boolean isLocationBarShownInNtp = false;
-        boolean useModern = false;
         Tab currentTab = fullscreenManager.getTab();
         if (currentTab != null) {
             boolean isNtp =
@@ -108,20 +102,16 @@
                 isLocationBarShownInNtp =
                         ((NewTabPage) currentTab.getNativePage()).isLocationBarShownInNTP();
             }
-            useModern = currentTab.getActivity().supportsModernDesign()
-                    && FeatureUtilities.isChromeModernDesignEnabled();
         }
 
-        if (useModern) {
-            textBoxColor = ColorUtils.getTextBoxColorForToolbarBackground(mContext.getResources(),
-                    isLocationBarShownInNtp, browserControlsBackgroundColor, true);
-            textBoxResourceId = R.drawable.modern_location_bar;
-        }
+        int textBoxColor = ColorUtils.getTextBoxColorForToolbarBackground(mContext.getResources(),
+                isLocationBarShownInNtp, browserControlsBackgroundColor, true);
+        int textBoxResourceId = R.drawable.modern_location_bar;
 
         nativeUpdateToolbarLayer(mNativePtr, resourceManager, R.id.control_container,
                 browserControlsBackgroundColor, textBoxResourceId, browserControlsUrlBarAlpha,
                 textBoxColor, fullscreenManager.getTopControlOffset(), windowHeight, useTexture,
-                showShadow, useModern);
+                showShadow);
 
         if (mProgressBarDrawingInfo == null) return;
         nativeUpdateProgressBar(mNativePtr, mProgressBarDrawingInfo.progressBarRect.left,
@@ -170,8 +160,7 @@
 
         // In Chrome modern design, the url bar is always opaque since it is drawn in the
         // compositor.
-        float alpha = mRenderHost.getBrowserControlsUrlBarAlpha();
-        if (FeatureUtilities.isChromeModernDesignEnabled()) alpha = 1;
+        float alpha = 1;
 
         update(mRenderHost.getBrowserControlsBackgroundColor(), alpha,
                 mLayoutProvider.getFullscreenManager(), resourceManager,
@@ -261,19 +250,10 @@
     private native void nativeSetContentTree(
             long nativeToolbarSceneLayer,
             SceneLayer contentTree);
-    private native void nativeUpdateToolbarLayer(
-            long nativeToolbarSceneLayer,
-            ResourceManager resourceManager,
-            int resourceId,
-            int toolbarBackgroundColor,
-            int urlBarResourceId,
-            float urlBarAlpha,
-            int urlBarColor,
-            float topOffset,
-            float viewHeight,
-            boolean visible,
-            boolean showShadow,
-            boolean browserControlsAtBottom);
+    private native void nativeUpdateToolbarLayer(long nativeToolbarSceneLayer,
+            ResourceManager resourceManager, int resourceId, int toolbarBackgroundColor,
+            int urlBarResourceId, float urlBarAlpha, int urlBarColor, float topOffset,
+            float viewHeight, boolean visible, boolean showShadow);
     private native void nativeUpdateProgressBar(
             long nativeToolbarSceneLayer,
             int progressBarX,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
index 76ee09e..6462768c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.contacts_picker;
 
+import android.graphics.Bitmap;
 import android.support.annotation.Nullable;
 import android.util.JsonWriter;
 
@@ -27,19 +28,26 @@
     // The list of phone numbers registered for this contact.
     private List<String> mPhoneNumbers;
 
+    // The image associated with this contact.
+    private Bitmap mBitmap;
+
     /**
      * The ContactDetails constructor.
      * @param id The unique identifier of this contact.
      * @param displayName The display name of this contact.
      * @param emails The emails registered for this contact.
      * @param phoneNumbers The phone numbers registered for this contact.
+     * @param bitmap The image associated with this contact.
      */
-    public ContactDetails(
-            String id, String displayName, List<String> emails, List<String> phoneNumbers) {
+    public ContactDetails(String id, String displayName, List<String> emails,
+            List<String> phoneNumbers, Bitmap bitmap) {
         mDisplayName = displayName;
         mEmails = emails;
         mPhoneNumbers = phoneNumbers;
         mId = id;
+        // TODO(finnur): Investigate LRU caching for bitmaps.
+        // TODO(finnur): Investigate a changed approach for handling bitmaps.
+        mBitmap = bitmap;
     }
 
     /**
@@ -51,6 +59,14 @@
     }
 
     /**
+     * Accessor for the contact image.
+     * @return The image as bitmap.
+     */
+    public Bitmap getContactImage() {
+        return mBitmap;
+    }
+
+    /**
      * Accessor for the abbreviated display name (first letter of first name and first letter of
      * last name).
      * @return The display name, abbreviated to two characters.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
index b3fe8135..95f8f45 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
@@ -8,6 +8,8 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageView;
@@ -36,7 +38,8 @@
     // The details of the contact shown.
     private ContactDetails mContactDetails;
 
-    // The image view containing the abbreviated letters of the name.
+    // The image view containing the profile image of the contact, or the abbreviated letters of the
+    // contact's name.
     private ImageView mImage;
 
     // The control that signifies the contact has been selected.
@@ -123,9 +126,17 @@
         String displayName = contactDetails.getDisplayName();
         mDisplayName.setText(displayName);
         mDetailsView.setText(contactDetails.getContactDetailsAsString());
-        Bitmap icon = mCategoryView.getIconGenerator().generateIconForText(
-                contactDetails.getDisplayNameAbbreviation(), 2);
-        mImage.setImageBitmap(icon);
+        Bitmap icon = contactDetails.getContactImage();
+        if (icon == null) {
+            icon = mCategoryView.getIconGenerator().generateIconForText(
+                    contactDetails.getDisplayNameAbbreviation(), 2);
+            mImage.setImageBitmap(icon);
+        } else {
+            Resources resources = mContext.getResources();
+            RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(resources, icon);
+            drawable.setCircular(true);
+            mImage.setImageDrawable(drawable);
+        }
 
         updateSelectionState();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
index 09de480..d8d788f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
@@ -5,7 +5,11 @@
 package org.chromium.chrome.browser.contacts_picker;
 
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
 import android.provider.ContactsContract;
 import android.support.v7.widget.RecyclerView.Adapter;
 import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -14,6 +18,7 @@
 
 import org.chromium.chrome.R;
 
+import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
@@ -88,7 +93,7 @@
                     mContactsCursor.getColumnIndex(ContactsContract.Contacts._ID));
             String name = mContactsCursor.getString(
                     mContactsCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY));
-            contacts.add(new ContactDetails(id, name, getEmails(), getPhoneNumbers()));
+            contacts.add(new ContactDetails(id, name, getEmails(), getPhoneNumbers(), getPhoto()));
         } while (mContactsCursor.moveToNext());
 
         return contacts;
@@ -116,7 +121,8 @@
         }
 
         ((ContactView) holder.itemView)
-                .initialize(new ContactDetails(id, name, getEmails(), getPhoneNumbers()));
+                .initialize(
+                        new ContactDetails(id, name, getEmails(), getPhoneNumbers(), getPhoto()));
     }
 
     private ArrayList<String> getEmails() {
@@ -153,6 +159,29 @@
         return phoneNumbers;
     }
 
+    private Bitmap getPhoto() {
+        String id = mContactsCursor.getString(
+                mContactsCursor.getColumnIndex(ContactsContract.Contacts._ID));
+        Uri contactUri = ContentUris.withAppendedId(
+                ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));
+        Uri photoUri =
+                Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
+        Cursor cursor = mContentResolver.query(
+                photoUri, new String[] {ContactsContract.Contacts.Photo.PHOTO}, null, null, null);
+        if (cursor == null) return null;
+        try {
+            if (cursor.moveToFirst()) {
+                byte[] data = cursor.getBlob(0);
+                if (data != null) {
+                    return BitmapFactory.decodeStream(new ByteArrayInputStream(data));
+                }
+            }
+        } finally {
+            cursor.close();
+        }
+        return null;
+    }
+
     @Override
     public int getItemCount() {
         return mContactsCursor.getCount();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 92476d50..5ad709f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -1138,11 +1138,6 @@
         }
     }
 
-    @Override
-    public boolean supportsModernDesign() {
-        return true;
-    }
-
     private void recordClientConnectionStatus() {
         String packageName =
                 (getActivityTab() == null) ? null : getActivityTab().getAppAssociatedWith();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
index 05e23b9..b2fbb0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
@@ -180,11 +180,6 @@
     boolean isSuggestionsListShown();
 
     /**
-     * @return Whether the location bar is allowed to use Chrome modern design.
-     */
-    boolean useModernDesign();
-
-    /**
      * @return The margin to be applied to the URL bar based on the buttons currently visible next
      *         to it, used to avoid text overlapping the buttons and vice versa.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 1f04ee4..168da26 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -72,7 +72,6 @@
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.chrome.browser.toolbar.ToolbarPhone;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.KeyNavigationUtil;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.ScrimView.ScrimParams;
@@ -1250,11 +1249,6 @@
         return mSuggestionList;
     }
 
-    @Override
-    public boolean useModernDesign() {
-        return FeatureUtilities.isChromeModernDesignEnabled();
-    }
-
     /**
      * Initiates the mSuggestionListPopup.  Done on demand to not slow down
      * the initial inflation of the location bar.
@@ -1265,7 +1259,6 @@
         assert mNativeInitialized || mShowCachedZeroSuggestResults
                 : "Trying to initialize native suggestions list before native init";
         if (mSuggestionList != null) return;
-        mSuggestionListAdapter.setUseModernDesign(useModernDesign());
 
         OnLayoutChangeListener suggestionListResizer = new OnLayoutChangeListener() {
             @Override
@@ -1287,11 +1280,6 @@
         OmniboxSuggestionsList.OmniboxSuggestionListEmbedder embedder =
                 new OmniboxSuggestionsList.OmniboxSuggestionListEmbedder() {
                     @Override
-                    public boolean useModernDesign() {
-                        return LocationBarLayout.this.useModernDesign();
-                    }
-
-                    @Override
                     public boolean isTablet() {
                         return mIsTablet;
                     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxResultsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxResultsAdapter.java
index 7f693b8..d2fb283 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxResultsAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxResultsAdapter.java
@@ -24,7 +24,6 @@
     private final LocationBar mLocationBar;
     private OmniboxSuggestionDelegate mSuggestionDelegate;
     private boolean mUseDarkColors = true;
-    private boolean mUseModernDesign;
 
     public OmniboxResultsAdapter(
             Context context,
@@ -62,8 +61,8 @@
         } else {
             suggestionView = new SuggestionView(mContext, mLocationBar);
         }
-        suggestionView.init(mSuggestionItems.get(position), mSuggestionDelegate, position,
-                mUseDarkColors, mUseModernDesign);
+        suggestionView.init(
+                mSuggestionItems.get(position), mSuggestionDelegate, position, mUseDarkColors);
         return suggestionView;
     }
 
@@ -93,14 +92,6 @@
     }
 
     /**
-     * Specifies whether suggestions should use the modern design.
-     * @param useModernDesign Whether modern design should be used for suggestion views.
-     */
-    public void setUseModernDesign(boolean useModernDesign) {
-        mUseModernDesign = useModernDesign;
-    }
-
-    /**
      * Handler for actions that happen on suggestion view.
      */
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java
index 7153167..7376cde 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java
@@ -31,10 +31,8 @@
  */
 @VisibleForTesting
 public class OmniboxSuggestionsList extends ListView {
-    private static final int OMNIBOX_RESULTS_BG_COLOR = 0xFFF5F5F6;
-    private static final int OMNIBOX_RESULTS_CHROME_MODERN_BG_COLOR = 0xFFFFFFFF;
-    private static final int OMNIBOX_INCOGNITO_RESULTS_BG_COLOR = 0xFF323232;
-    private static final int OMNIBOX_INCOGNITO_RESULTS_CHROME_MODERN_BG_COLOR = 0xFF3C4043;
+    private static final int OMNIBOX_RESULTS_BG_COLOR = 0xFFFFFFFF;
+    private static final int OMNIBOX_INCOGNITO_RESULTS_BG_COLOR = 0xFF3C4043;
 
     private final OmniboxSuggestionListEmbedder mEmbedder;
     private final int mSuggestionHeight;
@@ -64,9 +62,6 @@
         /** Return the delegate used to interact with the Window. */
         WindowDelegate getWindowDelegate();
 
-        /** Return whether modern design should be used when styling the popup. */
-        boolean useModernDesign();
-
         /** Return whether the suggestions are being rendered in the tablet UI. */
         boolean isTablet();
 
@@ -94,13 +89,9 @@
         mSuggestionDefinitionHeight = context.getResources().getDimensionPixelOffset(
                 R.dimen.omnibox_suggestion_definition_height);
 
-        int paddingTop = mEmbedder.useModernDesign()
-                ? 0
-                : context.getResources().getDimensionPixelOffset(
-                          R.dimen.omnibox_suggestion_list_padding_top);
         int paddingBottom = context.getResources().getDimensionPixelOffset(
                 R.dimen.omnibox_suggestion_list_padding_bottom);
-        ViewCompat.setPaddingRelative(this, 0, paddingTop, 0, paddingBottom);
+        ViewCompat.setPaddingRelative(this, 0, 0, 0, paddingBottom);
 
         refreshPopupBackground();
         getBackground().getPadding(mTempRect);
@@ -135,12 +126,6 @@
     private Drawable getSuggestionPopupBackground() {
         int omniboxResultsColorForNonIncognito = OMNIBOX_RESULTS_BG_COLOR;
         int omniboxResultsColorForIncognito = OMNIBOX_INCOGNITO_RESULTS_BG_COLOR;
-        if (mEmbedder.useModernDesign()) {
-            omniboxResultsColorForNonIncognito = OMNIBOX_RESULTS_CHROME_MODERN_BG_COLOR;
-            if (!mEmbedder.isTablet()) {
-                omniboxResultsColorForIncognito = OMNIBOX_INCOGNITO_RESULTS_CHROME_MODERN_BG_COLOR;
-            }
-        }
 
         int color = mEmbedder.isIncognito() ? omniboxResultsColorForIncognito
                                             : omniboxResultsColorForNonIncognito;
@@ -250,9 +235,8 @@
                 Math.min(mTempRect.height(), decorHeight) + additionalHeightForBottomNavMenu;
         int availableListHeight = availableViewportHeight - anchorBottomRelativeToContent;
         // The suggestions should consume all available space in Modern on phone.
-        int desiredHeight = mEmbedder.useModernDesign() && !mEmbedder.isTablet()
-                ? availableListHeight
-                : Math.min(availableListHeight, getIdealHeight());
+        int desiredHeight = !mEmbedder.isTablet() ? availableListHeight
+                                                  : Math.min(availableListHeight, getIdealHeight());
         if (layoutParams.height != desiredHeight) {
             layoutParams.height = desiredHeight;
             updateLayout = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
index b8faa31..e5f3c1d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
@@ -75,8 +75,7 @@
 
     private final int mDarkTitleColorStandardFont;
     private final int mLightTitleColorStandardFont;
-    private final int mDarkUrlStandardModernColor;
-    private final int mLightUrlStandardModernColor;
+    private final int mDarkUrlStandardColor;
     private final int mLightUrlStandardColor;
 
     private OmniboxResultItem mSuggestionItem;
@@ -122,12 +121,10 @@
                 ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_default_text);
         mLightTitleColorStandardFont =
                 ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_light_default_text);
-        mDarkUrlStandardModernColor =
+        mDarkUrlStandardColor =
                 ApiCompatibilityUtils.getColor(resources, R.color.suggestion_url_dark_modern);
-        mLightUrlStandardModernColor =
-                ApiCompatibilityUtils.getColor(resources, R.color.suggestion_url_light_modern);
         mLightUrlStandardColor =
-                ApiCompatibilityUtils.getColor(resources, R.color.suggestion_url_light);
+                ApiCompatibilityUtils.getColor(resources, R.color.suggestion_url_light_modern);
 
         TypedArray a = getContext().obtainStyledAttributes(
                 new int [] {R.attr.selectableItemBackground});
@@ -286,10 +283,9 @@
      * @param suggestionDelegate The suggestion delegate.
      * @param position Position of the suggestion in the dropdown list.
      * @param useDarkColors Whether dark colors should be used for fonts and icons.
-     * @param useModernDesign Whether modern design should be used.
      */
     public void init(OmniboxResultItem suggestionItem, OmniboxSuggestionDelegate suggestionDelegate,
-            int position, boolean useDarkColors, boolean useModernDesign) {
+            int position, boolean useDarkColors) {
         ViewCompat.setLayoutDirection(this, ViewCompat.getLayoutDirection(mUrlBar));
 
         // Update the position unconditionally.
@@ -318,9 +314,8 @@
         mContentsView.mTextLine2.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
                 .getDimension(R.dimen.omnibox_suggestion_second_line_text_size));
 
-        mRefineViewOffsetPx = useModernDesign ? mRefineViewModernEndPadding : 0;
-        mSuggestionViewStartOffset =
-                useModernDesign && !mLocationBar.mustQueryUrlBarLocationForSuggestions()
+        mRefineViewOffsetPx = mRefineViewModernEndPadding;
+        mSuggestionViewStartOffset = !mLocationBar.mustQueryUrlBarLocationForSuggestions()
                 ? mSuggestionListModernOffset
                 : 0;
 
@@ -352,7 +347,7 @@
             boolean urlShown = !TextUtils.isEmpty(mSuggestion.getUrl());
             boolean urlHighlighted = false;
             if (urlShown) {
-                urlHighlighted = setUrlText(suggestionItem, useModernDesign);
+                urlHighlighted = setUrlText(suggestionItem);
             } else {
                 mContentsView.mTextLine2.setVisibility(INVISIBLE);
             }
@@ -373,8 +368,7 @@
             setSuggestedQuery(suggestionItem, false, false, false);
             if ((suggestionType == OmniboxSuggestionType.SEARCH_SUGGEST_ENTITY)
                     || (suggestionType == OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE)) {
-                showDescriptionLine(SpannableString.valueOf(mSuggestion.getDescription()), false,
-                        useModernDesign);
+                showDescriptionLine(SpannableString.valueOf(mSuggestion.getDescription()), false);
             } else {
                 mContentsView.mTextLine2.setVisibility(INVISIBLE);
             }
@@ -404,10 +398,9 @@
                                                           : mLightTitleColorStandardFont;
     }
 
-    private int getStandardUrlColor(boolean useModernDesign) {
-        if (!useModernDesign) return mLightUrlStandardColor;
-        return (mUseDarkColors == null || mUseDarkColors) ? mDarkUrlStandardModernColor
-                                                          : mLightUrlStandardModernColor;
+    private int getStandardUrlColor() {
+        return (mUseDarkColors == null || mUseDarkColors) ? mDarkUrlStandardColor
+                                                          : mLightUrlStandardColor;
     }
 
     @Override
@@ -437,15 +430,14 @@
      * Sets (and highlights) the URL text of the second line of the omnibox suggestion.
      *
      * @param result The suggestion containing the URL.
-     * @param useModernDesign Whether modern design should be used.
      * @return Whether the URL was highlighted based on the user query.
      */
-    private boolean setUrlText(OmniboxResultItem result, boolean useModernDesign) {
+    private boolean setUrlText(OmniboxResultItem result) {
         OmniboxSuggestion suggestion = result.getSuggestion();
         Spannable str = SpannableString.valueOf(suggestion.getDisplayText());
         boolean hasMatch = applyHighlightToMatchRegions(
                 str, suggestion.getDisplayTextClassifications());
-        showDescriptionLine(str, true, useModernDesign);
+        showDescriptionLine(str, true);
         return hasMatch;
     }
 
@@ -480,9 +472,8 @@
      *
      * @param str The description text.
      * @param isUrl Whether this text is a URL (as opposed to a normal string).
-     * @param useModernDesign Whether modern design should be used.
      */
-    private void showDescriptionLine(Spannable str, boolean isUrl, boolean useModernDesign) {
+    private void showDescriptionLine(Spannable str, boolean isUrl) {
         TextView textLine = mContentsView.mTextLine2;
         if (textLine.getVisibility() != VISIBLE) {
             textLine.setVisibility(VISIBLE);
@@ -491,7 +482,7 @@
 
         // Force left-to-right rendering for URLs. See UrlBar constructor for details.
         if (isUrl) {
-            textLine.setTextColor(getStandardUrlColor(useModernDesign));
+            textLine.setTextColor(getStandardUrlColor());
             ApiCompatibilityUtils.setTextDirection(textLine, TEXT_DIRECTION_LTR);
         } else {
             textLine.setTextColor(getStandardFontColor());
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 b4842c494..5da3baf 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
@@ -860,6 +860,9 @@
             getPreferenceScreen().addPreference(mUseSyncAndAllServices);
 
             mUseSyncAndAllServices.setChecked(useSyncAndAllServices);
+            boolean hasCustomPassphrase = mProfileSyncService.isEngineInitialized()
+                    && mProfileSyncService.getPassphraseType() == PassphraseType.CUSTOM_PASSPHRASE;
+            mUseSyncAndAllServices.setEnabled(!hasCustomPassphrase);
             mSyncGroup.setEnabled(true);
 
             mGoogleActivityControls.setOnPreferenceClickListener(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java
index 364229c..970ed7b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.browser.preferences.LocationSettings;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.PreferenceUtils;
+import org.chromium.chrome.browser.preferences.website.SiteSettingsCategory.Type;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -73,7 +74,7 @@
         ((ListView) getView().findViewById(android.R.id.list)).setDivider(null);
     }
 
-    private Preference findPreference(@SiteSettingsCategory.Type int type) {
+    private Preference findPreference(@Type int type) {
         return findPreference(SiteSettingsCategory.preferenceKey(type));
     }
 
@@ -81,11 +82,8 @@
         if (mMediaSubMenu) {
             // The Media sub-menu only contains Protected Content and Autoplay, so remove all other
             // menus.
-            for (@SiteSettingsCategory.Type int i = 0; i < SiteSettingsCategory.Type.NUM_ENTRIES;
-                    i++) {
-                if (i == SiteSettingsCategory.Type.AUTOPLAY
-                        || i == SiteSettingsCategory.Type.PROTECTED_MEDIA)
-                    continue;
+            for (@Type int i = 0; i < Type.NUM_ENTRIES; i++) {
+                if (i == Type.AUTOPLAY || i == Type.PROTECTED_MEDIA) continue;
                 getPreferenceScreen().removePreference(findPreference(i));
             }
             getPreferenceScreen().removePreference(findPreference(MEDIA_KEY));
@@ -97,24 +95,19 @@
                 getPreferenceScreen().removePreference(findPreference(MEDIA_KEY));
             } else {
                 // This will be tucked under the Media subkey, so no reason to show them now.
-                getPreferenceScreen().removePreference(
-                        findPreference(SiteSettingsCategory.Type.AUTOPLAY));
+                getPreferenceScreen().removePreference(findPreference(Type.AUTOPLAY));
             }
-            getPreferenceScreen().removePreference(
-                    findPreference(SiteSettingsCategory.Type.PROTECTED_MEDIA));
+            getPreferenceScreen().removePreference(findPreference(Type.PROTECTED_MEDIA));
             // TODO(csharrison): Remove this condition once the experimental UI lands. It is not
             // great to dynamically remove the preference in this way.
             if (!SiteSettingsCategory.adsCategoryEnabled()) {
-                getPreferenceScreen().removePreference(
-                        findPreference(SiteSettingsCategory.Type.ADS));
+                getPreferenceScreen().removePreference(findPreference(Type.ADS));
             }
             if (!ChromeFeatureList.isEnabled(ChromeFeatureList.SOUND_CONTENT_SETTING)) {
-                getPreferenceScreen().removePreference(
-                        findPreference(SiteSettingsCategory.Type.SOUND));
+                getPreferenceScreen().removePreference(findPreference(Type.SOUND));
             }
             if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CLIPBOARD_CONTENT_SETTING)) {
-                getPreferenceScreen().removePreference(
-                        findPreference(SiteSettingsCategory.Type.CLIPBOARD));
+                getPreferenceScreen().removePreference(findPreference(Type.CLIPBOARD));
             }
             // The new Languages Preference *feature* is an advanced version of this translate
             // preference. Once Languages Preference is enabled, remove this setting.
@@ -122,8 +115,7 @@
                 getPreferenceScreen().removePreference(findPreference(TRANSLATE_KEY));
             }
             if (!ChromeFeatureList.isEnabled(ChromeFeatureList.GENERIC_SENSOR_EXTRA_CLASSES)) {
-                getPreferenceScreen().removePreference(
-                        findPreference(SiteSettingsCategory.Type.SENSORS));
+                getPreferenceScreen().removePreference(findPreference(Type.SENSORS));
             }
         }
     }
@@ -138,40 +130,40 @@
         // Preferences that navigate to Website Settings.
         List<Integer> websitePrefs = new ArrayList<Integer>();
         if (mMediaSubMenu) {
-            websitePrefs.add(SiteSettingsCategory.Type.PROTECTED_MEDIA);
-            websitePrefs.add(SiteSettingsCategory.Type.AUTOPLAY);
+            websitePrefs.add(Type.PROTECTED_MEDIA);
+            websitePrefs.add(Type.AUTOPLAY);
         } else {
             if (SiteSettingsCategory.adsCategoryEnabled()) {
-                websitePrefs.add(SiteSettingsCategory.Type.ADS);
+                websitePrefs.add(Type.ADS);
             }
             // When showing the main menu, if Protected Content is not available, only Autoplay
             // will be visible.
             if (!mProtectedContentMenuAvailable) {
-                websitePrefs.add(SiteSettingsCategory.Type.AUTOPLAY);
+                websitePrefs.add(Type.AUTOPLAY);
             }
-            websitePrefs.add(SiteSettingsCategory.Type.BACKGROUND_SYNC);
-            websitePrefs.add(SiteSettingsCategory.Type.CAMERA);
+            websitePrefs.add(Type.BACKGROUND_SYNC);
+            websitePrefs.add(Type.CAMERA);
             if (ChromeFeatureList.isEnabled(ChromeFeatureList.CLIPBOARD_CONTENT_SETTING)) {
-                websitePrefs.add(SiteSettingsCategory.Type.CLIPBOARD);
+                websitePrefs.add(Type.CLIPBOARD);
             }
-            websitePrefs.add(SiteSettingsCategory.Type.COOKIES);
-            websitePrefs.add(SiteSettingsCategory.Type.JAVASCRIPT);
-            websitePrefs.add(SiteSettingsCategory.Type.DEVICE_LOCATION);
-            websitePrefs.add(SiteSettingsCategory.Type.MICROPHONE);
-            websitePrefs.add(SiteSettingsCategory.Type.NOTIFICATIONS);
-            websitePrefs.add(SiteSettingsCategory.Type.POPUPS);
+            websitePrefs.add(Type.COOKIES);
+            websitePrefs.add(Type.JAVASCRIPT);
+            websitePrefs.add(Type.DEVICE_LOCATION);
+            websitePrefs.add(Type.MICROPHONE);
+            websitePrefs.add(Type.NOTIFICATIONS);
+            websitePrefs.add(Type.POPUPS);
             if (ChromeFeatureList.isEnabled(ChromeFeatureList.GENERIC_SENSOR_EXTRA_CLASSES)) {
-                websitePrefs.add(SiteSettingsCategory.Type.SENSORS);
+                websitePrefs.add(Type.SENSORS);
             }
             if (ChromeFeatureList.isEnabled(ChromeFeatureList.SOUND_CONTENT_SETTING)) {
-                websitePrefs.add(SiteSettingsCategory.Type.SOUND);
+                websitePrefs.add(Type.SOUND);
             }
-            websitePrefs.add(SiteSettingsCategory.Type.USB);
+            websitePrefs.add(Type.USB);
         }
 
         // Initialize the summary and icon for all preferences that have an
         // associated content settings entry.
-        for (@SiteSettingsCategory.Type int prefCategory : websitePrefs) {
+        for (@Type int prefCategory : websitePrefs) {
             Preference p = findPreference(prefCategory);
             int contentType = SiteSettingsCategory.contentSettingsType(prefCategory);
             boolean requiresTriStateSetting =
@@ -180,7 +172,7 @@
             boolean checked = false;
             ContentSetting setting = ContentSetting.DEFAULT;
 
-            if (prefCategory == SiteSettingsCategory.Type.DEVICE_LOCATION) {
+            if (prefCategory == Type.DEVICE_LOCATION) {
                 checked = LocationSettings.getInstance().areAllLocationSettingsEnabled();
             } else if (requiresTriStateSetting) {
                 setting = ContentSetting.fromInt(prefServiceBridge.getContentSetting(contentType));
@@ -191,28 +183,27 @@
             p.setTitle(ContentSettingsResources.getTitle(contentType));
             p.setOnPreferenceClickListener(this);
 
-            if ((SiteSettingsCategory.Type.CAMERA == prefCategory
-                        || SiteSettingsCategory.Type.MICROPHONE == prefCategory)
+            if ((Type.CAMERA == prefCategory || Type.MICROPHONE == prefCategory)
                     && SiteSettingsCategory.createFromType(prefCategory)
                                .showPermissionBlockedMessage(getActivity())) {
                 // Show 'disabled' message when permission is not granted in Android.
                 p.setSummary(ContentSettingsResources.getCategorySummary(contentType, false));
-            } else if (SiteSettingsCategory.Type.AUTOPLAY == prefCategory
+            } else if (Type.AUTOPLAY == prefCategory
                     && DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()) {
                 // Disable autoplay preference if Data Saver is ON.
                 p.setSummary(ContentSettingsResources.getAutoplayDisabledByDataSaverSummary());
                 p.setEnabled(false);
-            } else if (SiteSettingsCategory.Type.COOKIES == prefCategory && checked
+            } else if (Type.COOKIES == prefCategory && checked
                     && prefServiceBridge.isBlockThirdPartyCookiesEnabled()) {
                 p.setSummary(ContentSettingsResources.getCookieAllowedExceptThirdPartySummary());
-            } else if (SiteSettingsCategory.Type.CLIPBOARD == prefCategory && !checked) {
-                p.setSummary(ContentSettingsResources.getClipboardBlockedListSummary());
-            } else if (SiteSettingsCategory.Type.DEVICE_LOCATION == prefCategory && checked
+            } else if (Type.DEVICE_LOCATION == prefCategory && checked
                     && prefServiceBridge.isLocationAllowedByPolicy()) {
                 p.setSummary(ContentSettingsResources.getGeolocationAllowedSummary());
-            } else if (SiteSettingsCategory.Type.ADS == prefCategory && !checked) {
+            } else if (Type.CLIPBOARD == prefCategory && !checked) {
+                p.setSummary(ContentSettingsResources.getClipboardBlockedListSummary());
+            } else if (Type.ADS == prefCategory && !checked) {
                 p.setSummary(ContentSettingsResources.getAdsBlockedListSummary());
-            } else if (SiteSettingsCategory.Type.SOUND == prefCategory && !checked) {
+            } else if (Type.SOUND == prefCategory && !checked) {
                 p.setSummary(ContentSettingsResources.getSoundBlockedListSummary());
             } else if (requiresTriStateSetting) {
                 p.setSummary(ContentSettingsResources.getCategorySummary(setting));
@@ -228,12 +219,12 @@
             }
         }
 
-        Preference p = findPreference(SiteSettingsCategory.Type.ALL_SITES);
+        Preference p = findPreference(Type.ALL_SITES);
         if (p != null) p.setOnPreferenceClickListener(this);
         p = findPreference(MEDIA_KEY);
         if (p != null) p.setOnPreferenceClickListener(this);
         // TODO(finnur): Re-move this for Storage once it can be moved to the 'Usage' menu.
-        p = findPreference(SiteSettingsCategory.Type.USE_STORAGE);
+        p = findPreference(Type.USE_STORAGE);
         if (p != null) p.setOnPreferenceClickListener(this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
index 8a12f69..9c7bffb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
@@ -162,9 +162,4 @@
             }
         });
     }
-
-    @Override
-    public boolean useModernDesign() {
-        return true;
-    }
 }
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 764479d..f45f638 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
@@ -92,7 +92,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabReparentingParams;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.widget.PulseDrawable;
 import org.chromium.chrome.browser.widget.textbubble.TextBubble;
@@ -655,10 +654,8 @@
     }
 
     private int calculateDefaultThemeColor() {
-        boolean useModernDesign = getActivity() != null && getActivity().supportsModernDesign()
-                && FeatureUtilities.isChromeModernDesignEnabled();
         Resources resources = mThemedApplicationContext.getResources();
-        return ColorUtils.getDefaultThemeColor(resources, useModernDesign, mIncognito);
+        return ColorUtils.getDefaultThemeColor(resources, true, mIncognito);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index 2a6366b..50490a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -58,7 +58,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.TintedDrawable;
 import org.chromium.chrome.browser.widget.TintedImageButton;
@@ -163,8 +162,8 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        setBackground(new ColorDrawable(ColorUtils.getDefaultThemeColor(
-                getResources(), FeatureUtilities.isChromeModernDesignEnabled(), false)));
+        setBackground(
+                new ColorDrawable(ColorUtils.getDefaultThemeColor(getResources(), true, false)));
         mUrlBar = (TextView) findViewById(R.id.url_bar);
         mUrlBar.setHint("");
         mUrlBar.setEnabled(false);
@@ -826,11 +825,6 @@
     }
 
     @Override
-    public boolean useModernDesign() {
-        return true;
-    }
-
-    @Override
     public int getUrlContainerMarginEnd() {
         return 0;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawable.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawable.java
index c693a7ea..1abefda 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawable.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawable.java
@@ -18,9 +18,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.TintedDrawable;
-import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.Locale;
 
@@ -45,10 +43,8 @@
      * @return          A {@link TabSwitcherDrawable} instance.
      */
     public static TabSwitcherDrawable createTabSwitcherDrawable(Context context, boolean useLight) {
-        Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
-                FeatureUtilities.isChromeModernDesignEnabled() && !DeviceFormFactor.isTablet()
-                        ? R.drawable.btn_tabswitcher_modern
-                        : R.drawable.btn_tabswitcher);
+        Bitmap icon = BitmapFactory.decodeResource(
+                context.getResources(), R.drawable.btn_tabswitcher_modern);
         return new TabSwitcherDrawable(context, useLight, icon);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index d701720..eec6907 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -238,8 +238,7 @@
         mActivity = activity;
         mActionBarDelegate = new ViewShiftingActionBarDelegate(activity, controlContainer);
 
-        mToolbarModel = new ToolbarModel(activity, activity.getBottomSheet(),
-                activity.supportsModernDesign() && FeatureUtilities.isChromeModernDesignEnabled());
+        mToolbarModel = new ToolbarModel(activity, activity.getBottomSheet());
         mControlContainer = controlContainer;
         assert mControlContainer != null;
         mUrlFocusChangedCallback = urlFocusChangedCallback;
@@ -1564,8 +1563,8 @@
                 }
                 if (tab != null) tab.addObserver(mTabObserver);
             }
-            int defaultPrimaryColor = ColorUtils.getDefaultThemeColor(mToolbar.getResources(),
-                    FeatureUtilities.isChromeModernDesignEnabled(), isIncognito);
+            int defaultPrimaryColor =
+                    ColorUtils.getDefaultThemeColor(mToolbar.getResources(), true, isIncognito);
             int primaryColor = tab != null ? tab.getThemeColor() : defaultPrimaryColor;
             updatePrimaryColor(primaryColor, false);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
index 67dbe30..e1e51ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
@@ -54,17 +54,11 @@
 
     private final Context mContext;
     private final BottomSheet mBottomSheet;
-    private final boolean mUseModernDesign;
 
     private Tab mTab;
     private boolean mIsIncognito;
     private int mPrimaryColor;
     private boolean mIsUsingBrandColor;
-    private String mPreviousUrl;
-    @ConnectionSecurityLevel
-    private int mPreviousSecurityLevel;
-    private String mCachedSearchTerms;
-    private boolean mIgnoreSecurityLevelForSearchTerms;
     private boolean mIsNativeLibraryReady;
 
     private long mNativeToolbarModelAndroid;
@@ -73,16 +67,11 @@
      * Default constructor for this class.
      * @param context The Context used for styling the toolbar visuals.
      * @param bottomSheet The {@link BottomSheet} for the activity displaying this toolbar.
-     * @param useModernDesign Whether the modern design should be used for the toolbar represented
-     *                        by this model.
      */
-    public ToolbarModel(
-            Context context, @Nullable BottomSheet bottomSheet, boolean useModernDesign) {
+    public ToolbarModel(Context context, @Nullable BottomSheet bottomSheet) {
         mContext = context;
         mBottomSheet = bottomSheet;
-        mUseModernDesign = useModernDesign;
-        mPrimaryColor =
-                ColorUtils.getDefaultThemeColor(context.getResources(), useModernDesign, false);
+        mPrimaryColor = ColorUtils.getDefaultThemeColor(context.getResources(), true, false);
     }
 
     /**
@@ -311,7 +300,7 @@
         mIsUsingBrandColor = !isIncognito()
                 && mPrimaryColor
                         != ColorUtils.getDefaultThemeColor(
-                                   context.getResources(), mUseModernDesign, isIncognito())
+                                   context.getResources(), true, isIncognito())
                 && hasTab() && !mTab.isNativePage();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 2e62bb48..32502d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -842,7 +842,7 @@
                 return Color.TRANSPARENT;
             default:
                 assert false;
-                return ApiCompatibilityUtils.getColor(res, R.color.default_primary_color);
+                return ApiCompatibilityUtils.getColor(res, R.color.modern_primary_color);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
index 040a6535..9eb4027 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
@@ -89,8 +89,8 @@
         super(context, attrs);
         mStartPaddingWithButtons = getResources().getDimensionPixelOffset(
                 R.dimen.tablet_toolbar_start_padding);
-        mStartPaddingWithoutButtons = getResources().getDimensionPixelOffset(
-                R.dimen.tablet_toolbar_start_padding_no_buttons);
+        mStartPaddingWithoutButtons =
+                getResources().getDimensionPixelOffset(R.dimen.toolbar_edge_padding);
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java
index 8521f7f4..74969d5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
-import org.chromium.content_public.browser.test.util.WebContentsUtils;
 
 import java.util.concurrent.TimeoutException;
 
@@ -75,16 +74,16 @@
         for (int i = 1; i <= 30; ++i) {
             for (int j = 0; j < 5; ++j) {
                 // Start evaluation of a JavaScript script -- we don't need a result.
-                WebContentsUtils.evaluateJavaScript(tab1.getWebContents(), "foobar();", null);
-                WebContentsUtils.evaluateJavaScript(tab2.getWebContents(), "foobar();", null);
+                tab1.getWebContents().evaluateJavaScriptForTests("foobar();", null);
+                tab2.getWebContents().evaluateJavaScriptForTests("foobar();", null);
             }
             Assert.assertEquals("Incorrect JavaScript evaluation result on tab1", i * 2,
                     Integer.parseInt(JavaScriptUtils.executeJavaScriptAndWaitForResult(
                             tab1.getWebContents(), "add2()")));
             for (int j = 0; j < 5; ++j) {
                 // Start evaluation of a JavaScript script -- we don't need a result.
-                WebContentsUtils.evaluateJavaScript(tab1.getWebContents(), "foobar();", null);
-                WebContentsUtils.evaluateJavaScript(tab2.getWebContents(), "foobar();", null);
+                tab1.getWebContents().evaluateJavaScriptForTests("foobar();", null);
+                tab2.getWebContents().evaluateJavaScriptForTests("foobar();", null);
             }
             Assert.assertEquals("Incorrect JavaScript evaluation result on tab2", i * 2 + 1,
                     Integer.parseInt(JavaScriptUtils.executeJavaScriptAndWaitForResult(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 89e0afd..8ab40e18 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -78,7 +78,6 @@
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TouchCommon;
 import org.chromium.content_public.browser.test.util.UiUtils;
-import org.chromium.content_public.browser.test.util.WebContentsUtils;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.net.test.EmbeddedTestServer;
@@ -191,11 +190,11 @@
 
         mActivityTestRule.newIncognitoTabFromMenu();
 
-        WebContentsUtils.evaluateJavaScript(tab.getWebContents(),
+        ThreadUtils.runOnUiThreadBlocking(() -> tab.getWebContents().evaluateJavaScriptForTests(
                 "(function() {"
                         + "  window.open('www.google.com');"
                         + "})()",
-                null);
+                null));
 
         CriteriaHelper.pollUiThread(Criteria.equals(2,
                 () -> mActivityTestRule.getActivity()
@@ -213,11 +212,11 @@
         mActivityTestRule.newIncognitoTabFromMenu();
         mActivityTestRule.loadUrl(mTestServer.getURL(TEST_FILE_PATH));
         final Tab tab = mActivityTestRule.getActivity().getActivityTab();
-        WebContentsUtils.evaluateJavaScript(tab.getWebContents(),
+        ThreadUtils.runOnUiThreadBlocking(() -> tab.getWebContents().evaluateJavaScriptForTests(
                 "(function() {"
                         + "  alert('hi');"
                         + "})()",
-                null);
+                null));
 
         final AtomicReference<JavascriptAppModalDialog> dialog =
                 new AtomicReference<>();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/CompositorVisibilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/CompositorVisibilityTest.java
index 76b74d2..0d8e880c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/CompositorVisibilityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/CompositorVisibilityTest.java
@@ -64,11 +64,6 @@
         }
 
         @Override
-        public float getBrowserControlsUrlBarAlpha() {
-            return 0;
-        }
-
-        @Override
         public ResourceManager getResourceManager() {
             return null;
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutHost.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutHost.java
index 0e4f983..e5280d8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutHost.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutHost.java
@@ -153,11 +153,6 @@
     }
 
     @Override
-    public float getBrowserControlsUrlBarAlpha() {
-        return 1f;
-    }
-
-    @Override
     public void hideKeyboard(Runnable postHideTask) {
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
index 6d2e7ff..0bc7323 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -67,8 +67,7 @@
         private Integer mSecurityLevel;
 
         public TestToolbarModel() {
-            super(ContextUtils.getApplicationContext(), null /* bottomSheet */,
-                    false /* useModernDesign */);
+            super(ContextUtils.getApplicationContext(), null /* bottomSheet */);
             initializeWithNative();
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java
index b4197a5..8185022 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java
@@ -138,8 +138,7 @@
         private String mUrl;
 
         public TestToolbarModel() {
-            super(ContextUtils.getApplicationContext(), null /* bottomSheet */,
-                    false /* useModernDesign */);
+            super(ContextUtils.getApplicationContext(), null /* bottomSheet */);
             initializeWithNative();
 
             Tab tab = new Tab(0, false, null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
index 72d3df6..df318b9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
@@ -35,7 +35,6 @@
 import org.chromium.chrome.test.util.browser.WebappTestPage;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.WebContentsUtils;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.net.test.EmbeddedTestServerRule;
 
@@ -348,8 +347,10 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                WebContentsUtils.evaluateJavaScript(mTab.getWebContents(),
-                        "(function() { window.open('" + url + "'); })()", null);
+                mTab.getWebContents().evaluateJavaScriptForTests("(function() {"
+                                + "window.open('" + url + "');"
+                                + "})()",
+                        null);
             }
         });
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
index 74259fb9..1ba8adf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
@@ -187,7 +187,7 @@
         ChromeTabUtils.waitForTabPageLoaded(customTab.getActivityTab(), offOriginUrl());
 
         Assert.assertEquals(
-                getDefaultPrimaryColorForCct(), customTab.getToolbarManager().getPrimaryColor());
+                getDefaultPrimaryColor(), customTab.getToolbarManager().getPrimaryColor());
     }
 
     /**
@@ -228,7 +228,7 @@
         CustomTabActivity customTab = ChromeActivityTestRule.waitFor(CustomTabActivity.class);
         ChromeTabUtils.waitForTabPageLoaded(customTab.getActivityTab(), offOriginUrl());
         Assert.assertEquals(
-                getDefaultPrimaryColorForCct(), customTab.getToolbarManager().getPrimaryColor());
+                getDefaultPrimaryColor(), customTab.getToolbarManager().getPrimaryColor());
     }
 
     /**
@@ -421,11 +421,6 @@
     }
 
     private long getDefaultPrimaryColor() {
-        return ApiCompatibilityUtils.getColor(
-                mActivityTestRule.getActivity().getResources(), R.color.default_primary_color);
-    }
-
-    private long getDefaultPrimaryColorForCct() {
         return ColorUtils.getDefaultThemeColor(
                 mActivityTestRule.getActivity().getResources(), true, false);
     }
diff --git a/chrome/android/js_utils.cc b/chrome/android/js_utils.cc
deleted file mode 100644
index 214e374..0000000
--- a/chrome/android/js_utils.cc
+++ /dev/null
@@ -1,20 +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 "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "content/public/test/android/web_contents_utils.h"
-#include "jni/JsUtils_jni.h"
-
-using base::android::ConvertJavaStringToUTF16;
-using base::android::JavaParamRef;
-
-void JNI_JsUtils_EvaluateJavaScript(JNIEnv* env,
-                                    const JavaParamRef<jclass>& clazz,
-                                    const JavaParamRef<jobject>& jweb_contents,
-                                    const JavaParamRef<jstring>& script,
-                                    const JavaParamRef<jobject>& callback) {
-  content::EvaluateJavaScript(env, jweb_contents, script, callback);
-}
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/JsUtils.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/JsUtils.java
deleted file mode 100644
index 531e038..0000000
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/JsUtils.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.sync;
-
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
-
-import org.junit.Assert;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.content_public.browser.JavaScriptCallback;
-import org.chromium.content_public.browser.WebContents;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Collection of utilities for Sync tests.
- */
-public class JsUtils {
-    private static final long EVALUATION_TIMEOUT_SECONDS = scaleTimeout(5);
-
-    /**
-     * Executes the given snippet of JavaScript code within the given ContentView.
-     * Returns the result of its execution in JSON format.
-     */
-    public static String executeJavaScriptAndWaitForResult(WebContents webContents, String code)
-            throws InterruptedException, TimeoutException {
-        return executeJavaScriptAndWaitForResult(
-                webContents, code, EVALUATION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-    }
-
-    /**
-     * Executes the given snippet of JavaScript code within the given WebContents.
-     * Does not depend on ContentView and TestCallbackHelperContainer.
-     * Returns the result of its execution in JSON format.
-     */
-    public static String executeJavaScriptAndWaitForResult(final WebContents webContents,
-            final String code, final long timeout, final TimeUnit timeoutUnits)
-            throws InterruptedException, TimeoutException {
-        final EvaluateJavaScriptResultHelper helper = new EvaluateJavaScriptResultHelper();
-        // Calling this from the UI thread causes it to time-out: the UI thread being blocked won't
-        // have a chance to process the JavaScript eval response).
-        Assert.assertFalse("Executing JavaScript should be done from the test thread, "
-                        + " not the UI thread",
-                ThreadUtils.runningOnUiThread());
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                helper.evaluateJavaScriptForTests(webContents, code);
-            }
-        });
-        helper.waitUntilHasValue(timeout, timeoutUnits);
-        Assert.assertTrue("Failed to retrieve JavaScript evaluation results.", helper.hasValue());
-        return helper.getJsonResultAndClear();
-    }
-
-    private static class EvaluateJavaScriptResultHelper extends CallbackHelper {
-        private String mJsonResult;
-
-        /**
-         * Starts evaluation of a given JavaScript code on a given webContents.
-         * @param webContents A WebContents instance to be used.
-         * @param code A JavaScript code to be evaluated.
-         */
-        public void evaluateJavaScriptForTests(WebContents webContents, String code) {
-            JavaScriptCallback callback = new JavaScriptCallback() {
-                @Override
-                public void handleJavaScriptResult(String jsonResult) {
-                    notifyCalled(jsonResult);
-                }
-            };
-            mJsonResult = null;
-            nativeEvaluateJavaScript(webContents, code, callback);
-        }
-
-        /**
-         * Returns true if the evaluation started by evaluateJavaScriptForTests() has completed.
-         */
-        public boolean hasValue() {
-            return mJsonResult != null;
-        }
-
-        /**
-         * Returns the JSON result of a previously completed JavaScript evaluation and
-         * resets the helper to accept new evaluations.
-         * @return String JSON result of a previously completed JavaScript evaluation.
-         */
-        public String getJsonResultAndClear() {
-            assert hasValue();
-            String result = mJsonResult;
-            mJsonResult = null;
-            return result;
-        }
-
-        /**
-         * Waits till the JavaScript evaluation finishes and returns true if a value was returned,
-         * false if it timed-out.
-         */
-        public boolean waitUntilHasValue(long timeout, TimeUnit unit)
-                throws InterruptedException, TimeoutException {
-            int count = getCallCount();
-            // Reads and writes are atomic for reference variables in java, this is thread safe
-            if (hasValue()) return true;
-            waitForCallback(count, 1, timeout, unit);
-            return hasValue();
-        }
-
-        public boolean waitUntilHasValue() throws InterruptedException, TimeoutException {
-            return waitUntilHasValue(CallbackHelper.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-        }
-
-        public void notifyCalled(String jsonResult) {
-            assert !hasValue();
-            mJsonResult = jsonResult;
-            notifyCalled();
-        }
-    }
-
-    private static native void nativeEvaluateJavaScript(
-            WebContents webContents, String script, JavaScriptCallback callback);
-}
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java
index c4a7d2bc..43bee7a 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
 import org.chromium.components.sync.ModelType;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.ui.base.PageTransition;
 
 /**
@@ -61,7 +62,7 @@
     public String getElementContent(Tab normalTab, String elementId) throws Exception {
         mSyncTestRule.loadUrlInTab(
                 DEBUG_PAGE, PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR, normalTab);
-        return JsUtils.executeJavaScriptAndWaitForResult(normalTab.getWebContents(),
+        return JavaScriptUtils.executeJavaScriptAndWaitForResult(normalTab.getWebContents(),
                 "document.getElementById('" + elementId + "').textContent");
     }
 
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd
index 101ea60..c9a1775 100644
--- a/chrome/app/theme/chrome_unscaled_resources.grd
+++ b/chrome/app/theme/chrome_unscaled_resources.grd
@@ -40,6 +40,10 @@
         <if expr="not is_macosx and not is_win">
           <include name="IDR_STATUS_TRAY_ICON" file="google_chrome/product_logo_22.png" type="BINDATA" />
         </if>
+        <if expr="chromeos">
+          <include name="IDR_CHROME_APP_ICON_32" file="google_chrome/chromeos/chrome_app_icon_32.png" type="BINDATA" />
+          <include name="IDR_CHROME_APP_ICON_192" file="google_chrome/chromeos/chrome_app_icon_192.png" type="BINDATA" />
+        </if>
       </if>
       <if expr="not _google_chrome">
         <include name="IDR_PRODUCT_LOGO_64" file="chromium/product_logo_64.png" type="BINDATA" />
@@ -54,6 +58,10 @@
         <if expr="not is_macosx and not is_win">
           <include name="IDR_STATUS_TRAY_ICON" file="chromium/product_logo_22.png" type="BINDATA" />
         </if>
+        <if expr="chromeos">
+          <include name="IDR_CHROME_APP_ICON_32" file="chromium/chromeos/chrome_app_icon_32.png" type="BINDATA" />
+          <include name="IDR_CHROME_APP_ICON_192" file="chromium/chromeos/chrome_app_icon_192.png" type="BINDATA" />
+        </if>
       </if>
       <if expr="is_win">
         <!-- Double-size profile avatar images used for generating .ico
diff --git a/chrome/app/theme/chromium/chromeos/chrome_app_icon_192.png b/chrome/app/theme/chromium/chromeos/chrome_app_icon_192.png
new file mode 100644
index 0000000..ef1b68c
--- /dev/null
+++ b/chrome/app/theme/chromium/chromeos/chrome_app_icon_192.png
Binary files differ
diff --git a/chrome/app/theme/chromium/chromeos/chrome_app_icon_32.png b/chrome/app/theme/chromium/chromeos/chrome_app_icon_32.png
new file mode 100644
index 0000000..76555dc2
--- /dev/null
+++ b/chrome/app/theme/chromium/chromeos/chrome_app_icon_32.png
Binary files differ
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c8cd8666..53afb68 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1127,21 +1127,6 @@
 };
 #endif  // defined(OS_ANDROID)
 
-const FeatureEntry::FeatureParam kSpeculativePreconnectPreconnect[] = {
-    {predictors::kModeParamName, predictors::kPreconnectMode}};
-const FeatureEntry::FeatureParam kSpeculativePreconnectLearning[] = {
-    {predictors::kModeParamName, predictors::kLearningMode}};
-const FeatureEntry::FeatureParam kSpeculativePreconnectNoPreconnect[] = {
-    {predictors::kModeParamName, predictors::kNoPreconnectMode}};
-
-const FeatureEntry::FeatureVariation kSpeculativePreconnectFeatureVariations[] =
-    {{"Preconnect", kSpeculativePreconnectPreconnect,
-      arraysize(kSpeculativePreconnectPreconnect), nullptr},
-     {"Learning", kSpeculativePreconnectLearning,
-      arraysize(kSpeculativePreconnectLearning), nullptr},
-     {"No preconnect", kSpeculativePreconnectNoPreconnect,
-      arraysize(kSpeculativePreconnectNoPreconnect), nullptr}};
-
 const FeatureEntry::FeatureParam kMarkHttpAsDangerous[] = {
     {security_state::features::kMarkHttpAsFeatureParameterName,
      security_state::features::kMarkHttpAsParameterDangerous}};
@@ -3698,12 +3683,6 @@
      FEATURE_VALUE_TYPE(
          password_manager::features::kHtmlBasedUsernameDetector)},
 
-    {"enable-new-preconnect", flag_descriptions::kSpeculativePreconnectName,
-     flag_descriptions::kSpeculativePreconnectDescription, kOsAll,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(predictors::kSpeculativePreconnectFeature,
-                                    kSpeculativePreconnectFeatureVariations,
-                                    "SpeculativePreconnectValidation")},
-
 #if defined(OS_ANDROID)
     {"enable-async-dns", flag_descriptions::kAsyncDnsName,
      flag_descriptions::kAsyncDnsDescription, kOsAndroid,
@@ -4474,6 +4453,12 @@
      flag_descriptions::kUseMultiloginEndpointDescription, kOsAll,
      FEATURE_VALUE_TYPE(kUseMultiloginEndpoint)},
 
+#if defined(OS_CHROMEOS)
+    {"enable-usbguard", flag_descriptions::kUsbguardName,
+     flag_descriptions::kUsbguardDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(features::kUsbguard)},
+#endif
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/compositor/OWNERS b/chrome/browser/android/compositor/OWNERS
index 0492e0e0..aa2f428 100644
--- a/chrome/browser/android/compositor/OWNERS
+++ b/chrome/browser/android/compositor/OWNERS
@@ -1,8 +1,8 @@
 changwan@chromium.org
 dtrainor@chromium.org
+mdjones@chromium.org
 
 per-file *contextual_search*=donnd@chromium.org
-per-file *contextual_search*=mdjones@chromium.org
 per-file *contextual_search*=twellington@chromium.org
 
 # COMPONENT: UI>Browser>Mobile>CompositedUI
diff --git a/chrome/browser/android/compositor/layer/tab_layer.cc b/chrome/browser/android/compositor/layer/tab_layer.cc
index 580102c..09370553 100644
--- a/chrome/browser/android/compositor/layer/tab_layer.cc
+++ b/chrome/browser/android/compositor/layer/tab_layer.cc
@@ -93,7 +93,6 @@
 
 void TabLayer::SetProperties(int id,
                              bool can_use_live_layer,
-                             bool modern_design_enabled,
                              int toolbar_resource_id,
                              int close_button_resource_id,
                              int shadow_resource_id,
@@ -225,19 +224,13 @@
   //--------------------------------------------------------------------------
 
   // TODO(kkimlabs): Tab switcher doesn't show the progress bar.
-  toolbar_layer_->PushResource(toolbar_resource_id,
-                               toolbar_background_color,
-                               anonymize_toolbar,
-                               toolbar_textbox_background_color,
-                               toolbar_textbox_resource_id,
-                               toolbar_textbox_alpha,
-                               view_height,
-                               // TODO(mdjones): Feels odd to pass 0 here when
-                               // we have access to toolbar_y_offset.
-                               0,
-                               false,
-                               false,
-                               modern_design_enabled);
+  toolbar_layer_->PushResource(
+      toolbar_resource_id, toolbar_background_color, anonymize_toolbar,
+      toolbar_textbox_background_color, toolbar_textbox_resource_id,
+      toolbar_textbox_alpha, view_height,
+      // TODO(mdjones): Feels odd to pass 0 here when
+      // we have access to toolbar_y_offset.
+      0, false, false);
   toolbar_layer_->UpdateProgressBar(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
   float toolbar_impact_height = 0;
diff --git a/chrome/browser/android/compositor/layer/tab_layer.h b/chrome/browser/android/compositor/layer/tab_layer.h
index cf63508..36686b8 100644
--- a/chrome/browser/android/compositor/layer/tab_layer.h
+++ b/chrome/browser/android/compositor/layer/tab_layer.h
@@ -44,7 +44,6 @@
 
   void SetProperties(int id,
                      bool can_use_live_layer,
-                     bool modern_design_enabled,
                      int toolbar_resource_id,
                      int close_button_resource_id,
                      int shadow_resource_id,
diff --git a/chrome/browser/android/compositor/layer/toolbar_layer.cc b/chrome/browser/android/compositor/layer/toolbar_layer.cc
index 64f623b..9cefae2 100644
--- a/chrome/browser/android/compositor/layer/toolbar_layer.cc
+++ b/chrome/browser/android/compositor/layer/toolbar_layer.cc
@@ -26,18 +26,16 @@
   return layer_;
 }
 
-void ToolbarLayer::PushResource(
-    int toolbar_resource_id,
-    int toolbar_background_color,
-    bool anonymize,
-    int toolbar_textbox_background_color,
-    int url_bar_background_resource_id,
-    float url_bar_alpha,
-    float window_height,
-    float y_offset,
-    bool show_debug,
-    bool clip_shadow,
-    bool modern_design_enabled) {
+void ToolbarLayer::PushResource(int toolbar_resource_id,
+                                int toolbar_background_color,
+                                bool anonymize,
+                                int toolbar_textbox_background_color,
+                                int url_bar_background_resource_id,
+                                float url_bar_alpha,
+                                float window_height,
+                                float y_offset,
+                                bool show_debug,
+                                bool clip_shadow) {
   ToolbarResource* resource =
       ToolbarResource::From(resource_manager_->GetResource(
           ui::ANDROID_RESOURCE_TYPE_DYNAMIC, toolbar_resource_id));
@@ -65,16 +63,9 @@
   url_bar_background_layer_->SetHideLayerAndSubtree(!url_bar_visible);
   if (url_bar_visible) {
     ui::NinePatchResource* url_bar_background_resource;
-    if (!modern_design_enabled) {
-      url_bar_background_resource = ui::NinePatchResource::From(
-          resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
-                                         url_bar_background_resource_id));
-    } else {
-      url_bar_background_resource = ui::NinePatchResource::From(
-          resource_manager_->GetStaticResourceWithTint(
-              url_bar_background_resource_id,
-              toolbar_textbox_background_color));
-    }
+    url_bar_background_resource = ui::NinePatchResource::From(
+        resource_manager_->GetStaticResourceWithTint(
+            url_bar_background_resource_id, toolbar_textbox_background_color));
 
     gfx::Size draw_size(url_bar_background_resource->DrawSize(
         resource->location_bar_content_rect().size()));
@@ -97,34 +88,21 @@
 
   layer_->SetMasksToBounds(clip_shadow);
 
-  // TODO(mdjones): Remove the anonymize layer once modern launches.
-  anonymize_layer_->SetHideLayerAndSubtree(!anonymize || modern_design_enabled);
-  if (!modern_design_enabled && anonymize) {
-    anonymize_layer_->SetPosition(
-        gfx::PointF(resource->location_bar_content_rect().origin()));
-    anonymize_layer_->SetBounds(resource->location_bar_content_rect().size());
-    anonymize_layer_->SetBackgroundColor(toolbar_textbox_background_color);
-  }
+  // The location bar background doubles as the anonymize layer -- it just
+  // needs to be drawn on top of the toolbar bitmap.
+  int background_layer_index = GetIndexOfLayer(toolbar_background_layer_);
 
-  // If modern is enabled, the location bar background doubles as the
-  // anonymize layer -- it just needs to be drawn on top of the toolbar
-  // bitmap.
-  if (modern_design_enabled) {
-    int background_layer_index = GetIndexOfLayer(toolbar_background_layer_);
+  bool needs_move_to_front =
+      anonymize && layer_->children().back() != url_bar_background_layer_;
+  bool needs_move_to_back =
+      !anonymize &&
+      layer_->children()[background_layer_index] != url_bar_background_layer_;
 
-    bool needs_move_to_front =
-        anonymize && layer_->children().back() != url_bar_background_layer_;
-    bool needs_move_to_back =
-        !anonymize &&
-        layer_->children()[background_layer_index] != url_bar_background_layer_;
-
-    // If the layer needs to move, remove and re-add it.
-    if (needs_move_to_front) {
-      layer_->AddChild(url_bar_background_layer_);
-    } else if (needs_move_to_back) {
-      layer_->InsertChild(url_bar_background_layer_,
-                          background_layer_index + 1);
-    }
+  // If the layer needs to move, remove and re-add it.
+  if (needs_move_to_front) {
+    layer_->AddChild(url_bar_background_layer_);
+  } else if (needs_move_to_back) {
+    layer_->InsertChild(url_bar_background_layer_, background_layer_index + 1);
   }
 
   debug_layer_->SetBounds(resource->size());
@@ -187,7 +165,6 @@
       bitmap_layer_(cc::UIResourceLayer::Create()),
       progress_bar_layer_(cc::SolidColorLayer::Create()),
       progress_bar_background_layer_(cc::SolidColorLayer::Create()),
-      anonymize_layer_(cc::SolidColorLayer::Create()),
       debug_layer_(cc::SolidColorLayer::Create()) {
   toolbar_background_layer_->SetIsDrawable(true);
   layer_->AddChild(toolbar_background_layer_);
@@ -207,10 +184,6 @@
   progress_bar_layer_->SetHideLayerAndSubtree(true);
   layer_->AddChild(progress_bar_layer_);
 
-  anonymize_layer_->SetIsDrawable(true);
-  anonymize_layer_->SetBackgroundColor(SK_ColorWHITE);
-  layer_->AddChild(anonymize_layer_);
-
   debug_layer_->SetIsDrawable(true);
   debug_layer_->SetBackgroundColor(SK_ColorGREEN);
   debug_layer_->SetOpacity(0.5f);
diff --git a/chrome/browser/android/compositor/layer/toolbar_layer.h b/chrome/browser/android/compositor/layer/toolbar_layer.h
index 2bcf533..8dfb6d8 100644
--- a/chrome/browser/android/compositor/layer/toolbar_layer.h
+++ b/chrome/browser/android/compositor/layer/toolbar_layer.h
@@ -38,8 +38,7 @@
                     float window_height,
                     float y_offset,
                     bool show_debug,
-                    bool clip_shadow,
-                    bool browser_controls_at_bottom);
+                    bool clip_shadow);
 
   void UpdateProgressBar(int progress_bar_x,
                          int progress_bar_y,
@@ -67,7 +66,6 @@
   scoped_refptr<cc::UIResourceLayer> bitmap_layer_;
   scoped_refptr<cc::SolidColorLayer> progress_bar_layer_;
   scoped_refptr<cc::SolidColorLayer> progress_bar_background_layer_;
-  scoped_refptr<cc::SolidColorLayer> anonymize_layer_;
   scoped_refptr<cc::SolidColorLayer> debug_layer_;
 
   DISALLOW_COPY_AND_ASSIGN(ToolbarLayer);
diff --git a/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc
index bd7f536d..191368d 100644
--- a/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc
@@ -97,7 +97,6 @@
                                     jint border_resource_id,
                                     jint border_inner_shadow_resource_id,
                                     jboolean can_use_live_layer,
-                                    jboolean modern_design_enabled,
                                     jint tab_background_color,
                                     jint back_logo_color,
                                     jboolean incognito,
@@ -158,25 +157,23 @@
   used_tints_.insert(toolbar_background_color);
   used_tints_.insert(close_button_color);
   used_tints_.insert(default_theme_color);
-  if (modern_design_enabled) {
-    used_tints_.insert(toolbar_textbox_background_color);
-  }
+  used_tints_.insert(toolbar_textbox_background_color);
 
   DCHECK(layer);
   if (layer) {
     layer->SetProperties(
-        id, can_use_live_layer, modern_design_enabled, toolbar_resource_id,
-        close_button_resource_id, shadow_resource_id, contour_resource_id,
-        back_logo_resource_id, border_resource_id,
-        border_inner_shadow_resource_id, tab_background_color, back_logo_color,
-        close_button_on_right, x, y, width, height, shadow_x, shadow_y,
-        shadow_width, shadow_height, pivot_x, pivot_y, rotation_x, rotation_y,
-        alpha, border_alpha, border_inner_shadow_alpha, contour_alpha,
-        shadow_alpha, close_alpha, border_scale, saturation, brightness,
-        close_btn_width, static_to_view_blend, content_width, content_height,
-        content_width, visible_content_height, show_toolbar,
-        default_theme_color, toolbar_background_color, close_button_color,
-        anonymize_toolbar, show_tab_title, toolbar_textbox_resource_id,
+        id, can_use_live_layer, toolbar_resource_id, close_button_resource_id,
+        shadow_resource_id, contour_resource_id, back_logo_resource_id,
+        border_resource_id, border_inner_shadow_resource_id,
+        tab_background_color, back_logo_color, close_button_on_right, x, y,
+        width, height, shadow_x, shadow_y, shadow_width, shadow_height, pivot_x,
+        pivot_y, rotation_x, rotation_y, alpha, border_alpha,
+        border_inner_shadow_alpha, contour_alpha, shadow_alpha, close_alpha,
+        border_scale, saturation, brightness, close_btn_width,
+        static_to_view_blend, content_width, content_height, content_width,
+        visible_content_height, show_toolbar, default_theme_color,
+        toolbar_background_color, close_button_color, anonymize_toolbar,
+        show_tab_title, toolbar_textbox_resource_id,
         toolbar_textbox_background_color, toolbar_textbox_alpha, toolbar_alpha,
         toolbar_y_offset, side_border_scale, inset_border);
   }
diff --git a/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.h b/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.h
index 562b387..dc4b397 100644
--- a/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.h
@@ -58,7 +58,6 @@
                    jint border_resource_id,
                    jint border_inner_shadow_resource_id,
                    jboolean can_use_live_layer,
-                   jboolean modern_design_enabled,
                    jint tab_background_color,
                    jint back_logo_color,
                    jboolean incognito,
diff --git a/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc
index 21c20b5f..b21f00a 100644
--- a/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc
@@ -42,8 +42,7 @@
     jfloat y_offset,
     jfloat view_height,
     bool visible,
-    bool show_shadow,
-    bool modern_design_enabled) {
+    bool show_shadow) {
   // If the toolbar layer has not been created yet, create it.
   if (!toolbar_layer_) {
     ui::ResourceManager* resource_manager =
@@ -58,7 +57,7 @@
     toolbar_layer_->PushResource(toolbar_resource_id, toolbar_background_color,
                                  false, url_bar_color, url_bar_resource_id,
                                  url_bar_alpha, view_height, y_offset, false,
-                                 !show_shadow, modern_design_enabled);
+                                 !show_shadow);
   }
 }
 
diff --git a/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.h b/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.h
index fd3e2e3..e8c0e8c 100644
--- a/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.h
@@ -41,8 +41,7 @@
       jfloat y_offset,
       jfloat view_height,
       bool visible,
-      bool show_shadow,
-      bool modern_design_enabled);
+      bool show_shadow);
 
   // Update the progress bar.
   void UpdateProgressBar(
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 6ba0398b..4d24541 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -2107,7 +2107,7 @@
 
 // Test that we can Autofill forms where some fields name change during the
 // fill.
-IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, FieldsChangeName) {
+IN_PROC_BROWSER_TEST_P(AutofillCompanyInteractiveTest, FieldsChangeName) {
   CreateTestProfile();
 
   GURL url = embedded_test_server()->GetURL(
@@ -2127,7 +2127,7 @@
   ExpectFieldValue("address", "4120 Freidrich Lane");
   ExpectFieldValue("state", "TX");
   ExpectFieldValue("city", "Austin");
-  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("company", company_name_enabled_ ? "Initech" : "");
   ExpectFieldValue("email", "red.swingline@initech.com");
   ExpectFieldValue("phone", "15125551234");
 }
@@ -2178,9 +2178,11 @@
 //        restricted to checkout related pages.
 class AutofillRestrictUnownedFieldsTest
     : public AutofillInteractiveTestBase,
-      public testing::WithParamInterface<bool> {
+      public testing::WithParamInterface<std::tuple<bool, bool>> {
  protected:
-  AutofillRestrictUnownedFieldsTest() : restrict_unowned_fields_(GetParam()) {
+  AutofillRestrictUnownedFieldsTest()
+      : restrict_unowned_fields_(std::get<0>(GetParam())),
+        autofill_enable_company_name_(std::get<1>(GetParam())) {
     std::vector<base::Feature> enabled;
     std::vector<base::Feature> disabled = {
         features::kAutofillEnforceMinRequiredFieldsForHeuristics,
@@ -2188,10 +2190,13 @@
         features::kAutofillEnforceMinRequiredFieldsForUpload};
     (restrict_unowned_fields_ ? enabled : disabled)
         .push_back(features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
+    (autofill_enable_company_name_ ? enabled : disabled)
+        .push_back(features::kAutofillEnableCompanyName);
     scoped_feature_list_.InitWithFeatures(enabled, disabled);
   }
 
   const bool restrict_unowned_fields_;
+  const bool autofill_enable_company_name_;
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -2247,7 +2252,7 @@
   ExpectFieldValue("address", "4120 Freidrich Lane");
   ExpectFieldValue("state", "TX");
   ExpectFieldValue("city", "Austin");
-  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("company", autofill_enable_company_name_ ? "Initech" : "");
   ExpectFieldValue("email", "red.swingline@initech.com");
   ExpectFieldValue("phone", "15125551234");
 }
@@ -2309,7 +2314,7 @@
     ExpectFieldValue("address", "4120 Freidrich Lane");
     ExpectFieldValue("state", "TX");
     ExpectFieldValue("city", "Austin");
-    ExpectFieldValue("company", "Initech");
+    ExpectFieldValue("company", autofill_enable_company_name_ ? "Initech" : "");
     ExpectFieldValue("email", "red.swingline@initech.com");
     ExpectFieldValue("phone", "15125551234");
   }
@@ -2355,7 +2360,7 @@
   ExpectFieldValue("address", "4120 Freidrich Lane");
   ExpectFieldValue("state", "TX");
   ExpectFieldValue("city", "Austin");
-  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("company", autofill_enable_company_name_ ? "Initech" : "");
   ExpectFieldValue("email", "red.swingline@initech.com");
   ExpectFieldValue("phone", "15125551234");
 }
@@ -3070,5 +3075,5 @@
 
 INSTANTIATE_TEST_CASE_P(All,
                         AutofillRestrictUnownedFieldsTest,
-                        testing::Bool());
+                        testing::Combine(testing::Bool(), testing::Bool()));
 }  // namespace autofill
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 5b65c0c..f7a7dc5 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -79,6 +79,7 @@
           fetch_description->job_unique_id)),
       fetch_description(std::move(fetch_description)) {
   offline_item.is_off_the_record = is_off_the_record;
+  current_download_guids = std::move(this->fetch_description->current_guids);
   UpdateOfflineItem();
 }
 
@@ -212,6 +213,9 @@
     std::unique_ptr<content::BackgroundFetchDescription> fetch_description) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  // Initialize the download service in case it hasn't been yet.
+  GetDownloadService();
+
   std::string job_unique_id = fetch_description->job_unique_id;
   DCHECK(!job_details_map_.count(job_unique_id));
   auto emplace_result = job_details_map_.emplace(
@@ -220,13 +224,9 @@
                  profile_->IsOffTheRecord()));
 
   const JobDetails& details = emplace_result.first->second;
-  for (const auto& download_guid : details.fetch_description->current_guids) {
+  for (const auto& download_guid : details.current_download_guids) {
     DCHECK(!download_job_unique_id_map_.count(download_guid));
     download_job_unique_id_map_.emplace(download_guid, job_unique_id);
-    if (GetDownloadService()->GetStatus() ==
-        download::DownloadService::ServiceStatus::READY) {
-      GetDownloadService()->ResumeDownload(download_guid);
-    }
   }
 
   for (auto* observer : observers_) {
@@ -560,16 +560,6 @@
   // TODO(delphick): Start new downloads that weren't started because of pause.
 }
 
-void BackgroundFetchDelegateImpl::ResumeActiveJobs() {
-  DCHECK_EQ(GetDownloadService()->GetStatus(),
-            download::DownloadService::ServiceStatus::READY);
-
-  for (const auto& job_details : job_details_map_) {
-    for (const auto& download_guid : job_details.second.current_download_guids)
-      GetDownloadService()->ResumeDownload(download_guid);
-  }
-}
-
 void BackgroundFetchDelegateImpl::GetItemById(
     const offline_items_collection::ContentId& id,
     SingleItemCallback callback) {
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 85561d5..357064b 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -108,10 +108,6 @@
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
-  // Called once the Download Service is initialized. Resumes all previously
-  // active Jobs.
-  void ResumeActiveJobs();
-
   base::WeakPtr<BackgroundFetchDelegateImpl> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
diff --git a/chrome/browser/background_fetch/background_fetch_download_client.cc b/chrome/browser/background_fetch/background_fetch_download_client.cc
index 2ccbc997..9dea82c 100644
--- a/chrome/browser/background_fetch/background_fetch_download_client.cc
+++ b/chrome/browser/background_fetch/background_fetch_download_client.cc
@@ -35,11 +35,8 @@
   if (!delegate)
     return;
 
-  delegate_ = static_cast<BackgroundFetchDelegateImpl*>(
-                  browser_context_->GetBackgroundFetchDelegate())
-                  ->GetWeakPtr();
+  delegate_ = static_cast<BackgroundFetchDelegateImpl*>(delegate)->GetWeakPtr();
   DCHECK(delegate_);
-  delegate_->ResumeActiveJobs();
 }
 
 void BackgroundFetchDownloadClient::OnServiceUnavailable() {}
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index 654d23c..d42a460d 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -116,7 +116,7 @@
 
   base::RunLoop run_loop;
   blink::mojom::ServiceWorkerRegistrationOptions options(
-      embedded_test_server()->GetURL("/"), blink::mojom::ScriptType::kClassic,
+      embedded_test_server()->GetURL("/"),
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   GetServiceWorkerContext()->RegisterServiceWorker(
       embedded_test_server()->GetURL("/service_worker.js"), options,
@@ -142,7 +142,7 @@
 
   base::RunLoop run_loop;
   blink::mojom::ServiceWorkerRegistrationOptions options(
-      embedded_test_server()->GetURL("/"), blink::mojom::ScriptType::kClassic,
+      embedded_test_server()->GetURL("/"),
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   GetServiceWorkerContext()->RegisterServiceWorker(
       embedded_test_server()->GetURL("/service_worker.js"), options,
@@ -168,7 +168,7 @@
 
   base::RunLoop run_loop;
   blink::mojom::ServiceWorkerRegistrationOptions options(
-      embedded_test_server()->GetURL("/"), blink::mojom::ScriptType::kClassic,
+      embedded_test_server()->GetURL("/"),
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   GetServiceWorkerContext()->RegisterServiceWorker(
       embedded_test_server()->GetURL("/service_worker.js"), options,
@@ -551,7 +551,6 @@
   base::RunLoop run_loop;
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL("/scope/"),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   GetServiceWorkerContext()->RegisterServiceWorker(
       embedded_test_server()->GetURL("/sw.js"), options,
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index d1324f7..ca97df60 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "ash/public/cpp/default_scale_factor_retriever.h"
+#include "ash/public/interfaces/constants.mojom.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
@@ -67,6 +69,8 @@
 #include "components/arc/volume_mounter/arc_volume_mounter_bridge.h"
 #include "components/arc/wake_lock/arc_wake_lock_bridge.h"
 #include "components/prefs/pref_member.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace arc {
 namespace {
@@ -81,9 +85,16 @@
       arc_session_manager_(std::make_unique<ArcSessionManager>(
           std::make_unique<ArcSessionRunner>(
               base::Bind(ArcSession::Create,
-                         arc_service_manager_->arc_bridge_service())))) {
+                         arc_service_manager_->arc_bridge_service(),
+                         &default_scale_factor_retriever_)))) {
   DCHECK(g_arc_service_launcher == nullptr);
   g_arc_service_launcher = this;
+
+  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config;
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindInterface(ash::mojom::kServiceName, &cros_display_config);
+  default_scale_factor_retriever_.Start(std::move(cros_display_config));
 }
 
 ArcServiceLauncher::~ArcServiceLauncher() {
@@ -212,7 +223,8 @@
   // unexpected behavior, specifically on test teardown.
   arc_session_manager_ = std::make_unique<ArcSessionManager>(
       std::make_unique<ArcSessionRunner>(base::Bind(
-          ArcSession::Create, arc_service_manager_->arc_bridge_service())));
+          ArcSession::Create, arc_service_manager_->arc_bridge_service(),
+          &default_scale_factor_retriever_)));
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.h b/chrome/browser/chromeos/arc/arc_service_launcher.h
index 93ab8fd..d400b98 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.h
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.h
@@ -7,10 +7,15 @@
 
 #include <memory>
 
+#include "ash/public/cpp/default_scale_factor_retriever.h"
 #include "base/macros.h"
 
 class Profile;
 
+namespace ash {
+class DefaultScaleFactorRetriever;
+}
+
 namespace arc {
 
 class ArcPlayStoreEnabledPreferenceHandler;
@@ -45,6 +50,7 @@
   void ResetForTesting();
 
  private:
+  ash::DefaultScaleFactorRetriever default_scale_factor_retriever_;
   std::unique_ptr<ArcServiceManager> arc_service_manager_;
   std::unique_ptr<ArcSessionManager> arc_session_manager_;
   std::unique_ptr<ArcPlayStoreEnabledPreferenceHandler>
diff --git a/chrome/browser/chromeos/attestation/enrollment_policy_observer.cc b/chrome/browser/chromeos/attestation/enrollment_policy_observer.cc
index 6897f4d4..fdf5c81 100644
--- a/chrome/browser/chromeos/attestation/enrollment_policy_observer.cc
+++ b/chrome/browser/chromeos/attestation/enrollment_policy_observer.cc
@@ -122,6 +122,13 @@
 }
 
 void EnrollmentPolicyObserver::Start() {
+  // If we already uploaded an empty identification, we are done, because
+  // we asked to compute and upload it only if the PCA refused to give
+  // us an enrollment certificate, an error that will happen again (the
+  // AIK certificate sent to request an enrollment certificate does not
+  // contain an EID).
+  if (did_upload_empty_eid_)
+    return;
   // If identification for enrollment isn't needed, there is nothing to do.
   const enterprise_management::PolicyData* policy_data =
       device_settings_service_->policy_data();
@@ -193,8 +200,9 @@
   }
   policy_client_->UploadEnterpriseEnrollmentId(
       enrollment_id,
-      base::BindRepeating(&EnrollmentPolicyObserver::OnUploadComplete,
-                          weak_factory_.GetWeakPtr(), "Enrollment Identifier"));
+      base::BindRepeating(
+          &EnrollmentPolicyObserver::OnUploadEnrollmentIdComplete,
+          weak_factory_.GetWeakPtr(), enrollment_id));
 }
 
 void EnrollmentPolicyObserver::RescheduleGetEnrollmentId() {
@@ -235,6 +243,16 @@
                           "Enterprise Enrollment Certificate"));
 }
 
+void EnrollmentPolicyObserver::OnUploadEnrollmentIdComplete(
+    const std::string& enrollment_id,
+    bool status) {
+  if (status && enrollment_id.empty())
+    did_upload_empty_eid_ = true;
+  OnUploadComplete(enrollment_id.empty() ? "Empty Enrollment Identifier"
+                                         : "Enrollment Identifier",
+                   status);
+}
+
 void EnrollmentPolicyObserver::OnUploadComplete(const std::string& what,
                                                 bool status) {
   if (!status) {
diff --git a/chrome/browser/chromeos/attestation/enrollment_policy_observer.h b/chrome/browser/chromeos/attestation/enrollment_policy_observer.h
index 7116c55..f8749ce 100644
--- a/chrome/browser/chromeos/attestation/enrollment_policy_observer.h
+++ b/chrome/browser/chromeos/attestation/enrollment_policy_observer.h
@@ -68,6 +68,12 @@
   // Reschedule an attempt to get an enrollment identifier directly.
   void RescheduleGetEnrollmentId();
 
+  // Called when an enrollment identifier upload operation completes.
+  // On success, |status| will be true. The string |enrollment_id|
+  // is the identifier that was uploaded.
+  void OnUploadEnrollmentIdComplete(const std::string& enrollment_id,
+                                    bool status);
+
   // Handles a failure to get a certificate.
   void HandleGetCertificateFailure(AttestationStatus status);
 
@@ -87,6 +93,10 @@
   int num_retries_;
   int retry_limit_;
   int retry_delay_;
+  // Used to remember we uploaded an empty identifier this session for
+  // devices that can't obtain the identifier until they are powerwashed or
+  // updated and rebooted (see http://crbug.com/867724).
+  bool did_upload_empty_eid_ = false;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
diff --git a/chrome/browser/chromeos/attestation/enrollment_policy_observer_unittest.cc b/chrome/browser/chromeos/attestation/enrollment_policy_observer_unittest.cc
index dd89c0b..22b1689 100644
--- a/chrome/browser/chromeos/attestation/enrollment_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/attestation/enrollment_policy_observer_unittest.cc
@@ -140,6 +140,22 @@
   Run();
 }
 
+TEST_F(EnrollmentPolicyObserverTest,
+       UploadEmptyEnterpriseEnrollmentIdOnlyOnce) {
+  cryptohome_client_.set_tpm_attestation_enrollment_id(true /* ignore_cache */,
+                                                       "");
+  EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _))
+      .WillRepeatedly(WithArgs<4>(Invoke(CertCallbackBadRequestFailure)));
+  EXPECT_CALL(policy_client_, UploadEnterpriseEnrollmentId("", _))
+      .WillOnce(WithArgs<1>(Invoke(StatusCallbackSuccess)));
+  SetUpDevicePolicy(true);
+  // Request the EID again. We first setup device policy so that there is
+  // a change so the observer gets called again.
+  SetUpDevicePolicy(false);
+  SetUpDevicePolicy(true);
+  Run();
+}
+
 TEST_F(EnrollmentPolicyObserverTest, DBusFailureRetry) {
   SetUpEnrollmentIdNeeded(true);
 
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
index 4068a63..52de951 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
@@ -19,11 +19,14 @@
 
 namespace {
 
-const char kNoTabIdError[] = "targetTab doesn't have id field set.";
-const char kNoUrlError[] = "targetTab doesn't have URL field set.";
-const char kInvalidOriginError[] = "targetTab.url is not a valid URL.";
-const char kInvalidTabIdError[] = "Invalid tab specified.";
-const char kTabUrlNotSecure[] =
+const char kDesktopCaptureApiNoTabIdError[] =
+    "targetTab doesn't have id field set.";
+const char kDesktopCaptureApiNoUrlError[] =
+    "targetTab doesn't have URL field set.";
+const char kDesktopCaptureApiInvalidOriginError[] =
+    "targetTab.url is not a valid URL.";
+const char kDesktopCaptureApiInvalidTabIdError[] = "Invalid tab specified.";
+const char kDesktopCaptureApiTabUrlNotSecure[] =
     "URL scheme for the specified tab is not secure.";
 }  // namespace
 
@@ -55,20 +58,20 @@
   GURL origin;
   if (params->target_tab) {
     if (!params->target_tab->url) {
-      error_ = kNoUrlError;
+      error_ = kDesktopCaptureApiNoUrlError;
       return false;
     }
     origin = GURL(*(params->target_tab->url)).GetOrigin();
 
     if (!origin.is_valid()) {
-      error_ = kInvalidOriginError;
+      error_ = kDesktopCaptureApiInvalidOriginError;
       return false;
     }
 
     if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
             ::switches::kAllowHttpScreenCapture) &&
         !content::IsOriginSecure(origin)) {
-      error_ = kTabUrlNotSecure;
+      error_ = kDesktopCaptureApiTabUrlNotSecure;
       return false;
     }
     target_name = base::UTF8ToUTF16(content::IsOriginSecure(origin) ?
@@ -76,13 +79,13 @@
 
     if (!params->target_tab->id ||
         *params->target_tab->id == api::tabs::TAB_ID_NONE) {
-      error_ = kNoTabIdError;
+      error_ = kDesktopCaptureApiNoTabIdError;
       return false;
     }
 
     if (!ExtensionTabUtil::GetTabById(*(params->target_tab->id), GetProfile(),
                                       true, NULL, NULL, &web_contents, NULL)) {
-      error_ = kInvalidTabIdError;
+      error_ = kDesktopCaptureApiInvalidTabIdError;
       return false;
     }
     DCHECK(web_contents);
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index cac23b1..e96645d 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -1051,8 +1051,9 @@
 
 // Tests that an extension pop-up can be navigated to another page
 // in the same extension.
+// Times out on all platforms: https://crbug.com/882200
 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
-                       PageInSameExtension) {
+                       DISABLED_PageInSameExtension) {
   GURL other_page_in_same_extension =
       popup_extension().GetResourceURL("other_page.html");
   TestPopupNavigationViaGet(other_page_in_same_extension,
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
index 7ea1809..0fae4f1 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
@@ -20,6 +20,7 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/api/tab_capture/offscreen_tabs_owner.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
@@ -30,6 +31,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/origin_util.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 #include "extensions/common/features/simple_feature.h"
@@ -63,6 +65,11 @@
 const char kCapturingSameOffscreenTab[] =
     "Cannot capture the same off-screen tab more than once.";
 
+const char kInvalidOriginError[] = "Caller tab.url is not a valid URL.";
+const char kInvalidTabIdError[] = "Invalid tab specified.";
+const char kTabUrlNotSecure[] =
+    "URL scheme for the specified tab is not secure.";
+
 // Keys/values passed to renderer-side JS bindings.
 const char kMediaStreamSource[] = "chromeMediaSource";
 const char kMediaStreamSourceId[] = "chromeMediaSourceId";
@@ -121,7 +128,7 @@
 
 bool GetAutoThrottlingFromOptions(TabCapture::CaptureOptions* options) {
   bool enable_auto_throttling = false;
-  if (options->video && *options->video) {
+  if (options && options->video && *options->video) {
     if (options->video_constraints) {
       // Check for the Tab Capture-specific video constraint for enabling
       // automatic resolution/rate throttling mode in the capture pipeline.  See
@@ -202,10 +209,9 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   // Figure out the active WebContents and retrieve the needed ids.
-  Browser* target_browser =
-      chrome::FindAnyBrowser(Profile::FromBrowserContext(browser_context()),
-                             include_incognito_information());
-  if (!target_browser)
+  Browser* target_browser = chrome::FindLastActiveWithProfile(
+      Profile::FromBrowserContext(browser_context()));
+  if (!target_browser || target_browser->type() != Browser::TYPE_TABBED)
     return RespondNow(Error(kFindingTabError));
 
   content::WebContents* target_contents =
@@ -223,7 +229,7 @@
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kWhitelistedExtensionID) != extension_id &&
       !SimpleFeature::IsIdInArray(extension_id, kMediaRouterExtensionIds,
-                                  arraysize(kMediaRouterExtensionIds))) {
+                                  base::size(kMediaRouterExtensionIds))) {
     return RespondNow(Error(kGrantError));
   }
 
@@ -375,4 +381,80 @@
                    std::max(kDefaultHeight, min_size.height()));
 }
 
+ExtensionFunction::ResponseAction TabCaptureGetMediaStreamIdFunction::Run() {
+  std::unique_ptr<api::tab_capture::GetMediaStreamId::Params> params =
+      TabCapture::GetMediaStreamId::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  content::WebContents* target_contents = nullptr;
+  if (params->options && params->options->target_tab_id) {
+    if (!ExtensionTabUtil::GetTabById(*(params->options->target_tab_id),
+                                      browser_context(), true, nullptr, nullptr,
+                                      &target_contents, nullptr)) {
+      return RespondNow(Error(kInvalidTabIdError));
+    }
+  } else {
+    // Figure out the active WebContents and retrieve the needed ids.
+    Browser* target_browser = chrome::FindLastActiveWithProfile(
+        Profile::FromBrowserContext(browser_context()));
+    if (!target_browser || target_browser->type() != Browser::TYPE_TABBED)
+      return RespondNow(Error(kFindingTabError));
+
+    target_contents = target_browser->tab_strip_model()->GetActiveWebContents();
+  }
+  if (!target_contents)
+    return RespondNow(Error(kFindingTabError));
+
+  const std::string& extension_id = extension()->id();
+
+  // Make sure either we have been granted permission to capture through an
+  // extension icon click or our extension is whitelisted.
+  if (!extension()->permissions_data()->HasAPIPermissionForTab(
+          SessionTabHelper::IdForTab(target_contents).id(),
+          APIPermission::kTabCaptureForTab) &&
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kWhitelistedExtensionID) != extension_id) {
+    return RespondNow(Error(kGrantError));
+  }
+
+  // |consumer_contents| is the WebContents for which the stream is created.
+  content::WebContents* consumer_contents = nullptr;
+  std::string consumer_name;
+  GURL origin;
+  if (params->options && params->options->consumer_tab_id) {
+    if (!ExtensionTabUtil::GetTabById(*(params->options->consumer_tab_id),
+                                      browser_context(), true, nullptr, nullptr,
+                                      &consumer_contents, nullptr)) {
+      return RespondNow(Error(kInvalidTabIdError));
+    }
+
+    origin = consumer_contents->GetLastCommittedURL().GetOrigin();
+    if (!origin.is_valid()) {
+      return RespondNow(Error(kInvalidOriginError));
+    }
+
+    if (!content::IsOriginSecure(origin)) {
+      return RespondNow(Error(kTabUrlNotSecure));
+    }
+
+    consumer_name = net::GetHostAndOptionalPort(origin);
+  } else {
+    origin = extension()->url();
+    consumer_name = extension()->name();
+    consumer_contents = GetSenderWebContents();
+  }
+  EXTENSION_FUNCTION_VALIDATE(consumer_contents);
+
+  DesktopMediaID source = BuildDesktopMediaID(target_contents, nullptr);
+  TabCaptureRegistry* registry = TabCaptureRegistry::Get(browser_context());
+  std::string device_id =
+      registry->AddRequest(target_contents, extension_id, false, origin, source,
+                           consumer_name, consumer_contents);
+  if (device_id.empty()) {
+    return RespondNow(Error(kCapturingSameTab));
+  }
+
+  return RespondNow(OneArgument(std::make_unique<base::Value>(device_id)));
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_api.h b/chrome/browser/extensions/api/tab_capture/tab_capture_api.h
index b035882..2f3979b 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_api.h
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_api.h
@@ -62,6 +62,18 @@
   ResponseAction Run() final;
 };
 
+class TabCaptureGetMediaStreamIdFunction : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("tabCapture.getMediaStreamId",
+                             TABCAPTURE_GETMEDIASTREAMID)
+
+ private:
+  ~TabCaptureGetMediaStreamIdFunction() final {}
+
+  // ExtensionFunction:
+  ResponseAction Run() final;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_TAB_CAPTURE_API_H_
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index 78462cb..1101115 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -242,7 +242,6 @@
   }
 
   if (request->is_verified() ||
-      request->extension_id() != extension_id ||
       (request->capture_state() != tab_capture::TAB_CAPTURE_STATE_NONE &&
        request->capture_state() != tab_capture::TAB_CAPTURE_STATE_PENDING))
     return false;
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
index cce474c..d02f2d87 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -27,9 +27,9 @@
   static const GritResourceMap kExtraComponentExtensionResources[] = {
     {"web_store/webstore_icon_128.png", IDR_WEBSTORE_ICON},
     {"web_store/webstore_icon_16.png", IDR_WEBSTORE_ICON_16},
-    {"chrome_app/product_logo_128.png", IDR_PRODUCT_LOGO_128},
-    {"chrome_app/product_logo_16.png", IDR_PRODUCT_LOGO_16},
 #if defined(OS_CHROMEOS)
+    {"chrome_app/chrome_app_icon_32.png", IDR_CHROME_APP_ICON_32},
+    {"chrome_app/chrome_app_icon_192.png", IDR_CHROME_APP_ICON_192},
     {"webstore_widget/app/icons/icon_16.png", IDR_WEBSTORE_ICON_16},
     {"webstore_widget/app/icons/icon_32.png", IDR_WEBSTORE_ICON_32},
     {"webstore_widget/app/icons/icon_128.png", IDR_WEBSTORE_ICON},
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4792f43..d0d2eccc 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1756,20 +1756,6 @@
 const char kSoundContentSettingDescription[] =
     "Enable site-wide muting in content settings and tab strip context menu.";
 
-const char kSpeculativePreconnectName[] = "Enable new preconnect predictor";
-const char kSpeculativePreconnectDescription[] =
-    "Enable the new implementation of preconnect and DNS preresolve. "
-    "\"Learning\" means that only database construction is enabled, "
-    "\"Preconnect\" enables both learning and preconnect and disables the "
-    "existing implementation. \"No preconnect\" disables both implementations.";
-
-const char kSpeculativePrefetchName[] = "Speculative Prefetch";
-const char kSpeculativePrefetchDescription[] =
-    R"*("Speculative Prefetch" fetches likely resources early to improve )*"
-    R"*(load times, based on a local database (see chrome://predictors). )*"
-    R"*("Learning" means that only the database construction is enabled, )*"
-    R"*("Prefetching" that learning and prefetching are enabled.)*";
-
 const char kSpeculativeServiceWorkerStartOnQueryInputName[] =
     "Enable speculative start of a service worker when a search is predicted.";
 const char kSpeculativeServiceWorkerStartOnQueryInputDescription[] =
@@ -3526,6 +3512,12 @@
 const char kUnfilteredBluetoothDevicesDescription[] =
     "Shows all Bluetooth devices in UI (System Tray/Settings Page.)";
 
+const char kUsbguardName[] = "Block new USB devices at the lock screen.";
+const char kUsbguardDescription[] =
+    "Prevents newly connected USB devices from operating at the lock screen"
+    " until Chrome OS is unlocked to protect against malicious USB devices."
+    " Already connected USB devices will continue to function.";
+
 const char kUseMashName[] = "Out-of-process system UI (mash)";
 const char kUseMashDescription[] =
     "Runs the mojo UI service (mus) and the ash window manager and system UI "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 650842b..cc27a42 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1062,12 +1062,6 @@
 extern const char kSoundContentSettingName[];
 extern const char kSoundContentSettingDescription[];
 
-extern const char kSpeculativePreconnectName[];
-extern const char kSpeculativePreconnectDescription[];
-
-extern const char kSpeculativePrefetchName[];
-extern const char kSpeculativePrefetchDescription[];
-
 extern const char kSpeculativeServiceWorkerStartOnQueryInputName[];
 extern const char kSpeculativeServiceWorkerStartOnQueryInputDescription[];
 
@@ -2144,6 +2138,9 @@
 extern const char kUnfilteredBluetoothDevicesName[];
 extern const char kUnfilteredBluetoothDevicesDescription[];
 
+extern const char kUsbguardName[];
+extern const char kUsbguardDescription[];
+
 extern const char kUseMashName[];
 extern const char kUseMashDescription[];
 
diff --git a/chrome/browser/media/webrtc/tab_capture_access_handler.cc b/chrome/browser/media/webrtc/tab_capture_access_handler.cc
index 1034a8d..3e1d12e 100644
--- a/chrome/browser/media/webrtc/tab_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/tab_capture_access_handler.cc
@@ -43,12 +43,6 @@
   content::MediaStreamDevices devices;
   std::unique_ptr<content::MediaStreamUI> ui;
 
-  if (!extension) {
-    std::move(callback).Run(devices, content::MEDIA_DEVICE_TAB_CAPTURE_FAILURE,
-                            std::move(ui));
-    return;
-  }
-
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   extensions::TabCaptureRegistry* tab_capture_registry =
@@ -59,21 +53,21 @@
                             std::move(ui));
     return;
   }
+  // |extension| may be null if the tabCapture starts with
+  // tabCapture.getMediaStreamId().
+  // TODO(crbug.com/831722): Deprecate tabCaptureRegistry soon.
+  const std::string extension_id = extension ? extension->id() : "";
   const bool tab_capture_allowed = tab_capture_registry->VerifyRequest(
-      request.render_process_id, request.render_frame_id, extension->id());
+      request.render_process_id, request.render_frame_id, extension_id);
 
   if (request.audio_type == content::MEDIA_GUM_TAB_AUDIO_CAPTURE &&
-      tab_capture_allowed &&
-      extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kTabCapture)) {
+      tab_capture_allowed) {
     devices.push_back(content::MediaStreamDevice(
         content::MEDIA_GUM_TAB_AUDIO_CAPTURE, std::string(), std::string()));
   }
 
   if (request.video_type == content::MEDIA_GUM_TAB_VIDEO_CAPTURE &&
-      tab_capture_allowed &&
-      extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kTabCapture)) {
+      tab_capture_allowed) {
     devices.push_back(content::MediaStreamDevice(
         content::MEDIA_GUM_TAB_VIDEO_CAPTURE, std::string(), std::string()));
   }
diff --git a/chrome/browser/page_load_metrics/observers/loading_predictor_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/loading_predictor_page_load_metrics_observer_unittest.cc
index 35dc3c66..5975c98 100644
--- a/chrome/browser/page_load_metrics/observers/loading_predictor_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/loading_predictor_page_load_metrics_observer_unittest.cc
@@ -39,7 +39,6 @@
   void SetUp() override {
     page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp();
     predictors::LoadingPredictorConfig config;
-    config.mode = predictors::LoadingPredictorConfig::LEARNING;
     predictor_ =
         std::make_unique<testing::StrictMock<MockResourcePrefetchPredictor>>(
             config, profile());
diff --git a/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc
index bb332451..2785314 100644
--- a/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc
@@ -66,6 +66,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_42:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.ParseTiming.NavigationToParseStart",
@@ -123,6 +124,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_42:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.PaintTiming."
@@ -186,6 +188,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_42:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.Experimental.PaintTiming."
@@ -239,6 +242,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_42:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.DocumentTiming."
@@ -287,6 +291,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_42:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.DocumentTiming."
diff --git a/chrome/browser/predictors/loading_data_collector.cc b/chrome/browser/predictors/loading_data_collector.cc
index 52cf577..6240d4a 100644
--- a/chrome/browser/predictors/loading_data_collector.cc
+++ b/chrome/browser/predictors/loading_data_collector.cc
@@ -191,9 +191,7 @@
     return;
 
   auto& page_request_summary = *nav_it->second;
-
-  if (config_.is_origin_learning_enabled)
-    page_request_summary.UpdateOrAddToOrigins(resource_load_info);
+  page_request_summary.UpdateOrAddToOrigins(resource_load_info);
 }
 
 void LoadingDataCollector::RecordMainFrameLoadComplete(
diff --git a/chrome/browser/predictors/loading_predictor.cc b/chrome/browser/predictors/loading_predictor.cc
index 5f7eaade..33ac5e1 100644
--- a/chrome/browser/predictors/loading_predictor.cc
+++ b/chrome/browser/predictors/loading_predictor.cc
@@ -94,9 +94,8 @@
   if (has_preconnect_prediction) {
     // To report hint durations and deduplicate hints to the same url.
     active_hints_.emplace(url, base::TimeTicks::Now());
-    if (config_.IsPreconnectEnabledForOrigin(profile_, origin)) {
+    if (IsPreconnectAllowed(profile_))
       MaybeAddPreconnect(url, std::move(prediction.requests), origin);
-    }
   }
 }
 
@@ -123,11 +122,10 @@
 }
 
 PreconnectManager* LoadingPredictor::preconnect_manager() {
-  if (shutdown_)
+  if (shutdown_ || !IsPreconnectFeatureEnabled())
     return nullptr;
 
-  if (!preconnect_manager_ &&
-      config_.IsPreconnectEnabledForSomeOrigin(profile_)) {
+  if (!preconnect_manager_) {
     preconnect_manager_ =
         std::make_unique<PreconnectManager>(GetWeakPtr(), profile_);
   }
@@ -225,10 +223,8 @@
 }
 
 void LoadingPredictor::HandleOmniboxHint(const GURL& url, bool preconnectable) {
-  if (!url.is_valid() || !url.has_host() ||
-      !config_.IsPreconnectEnabledForOrigin(profile_, HintOrigin::OMNIBOX)) {
+  if (!url.is_valid() || !url.has_host() || !IsPreconnectAllowed(profile_))
     return;
-  }
 
   GURL origin = url.GetOrigin();
   bool is_new_origin = origin != last_omnibox_origin_;
diff --git a/chrome/browser/predictors/loading_predictor_config.cc b/chrome/browser/predictors/loading_predictor_config.cc
index 712dbb6c..146ad85 100644
--- a/chrome/browser/predictors/loading_predictor_config.cc
+++ b/chrome/browser/predictors/loading_predictor_config.cc
@@ -4,101 +4,45 @@
 
 #include "chrome/browser/predictors/loading_predictor_config.h"
 
-#include <string>
-
-#include "base/metrics/field_trial_params.h"
 #include "chrome/browser/net/prediction_options.h"
-#include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
 
 namespace predictors {
 
-namespace {
-
-bool IsPreconnectEnabledInternal(Profile* profile, int mode, int mask) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if ((mode & mask) == 0)
-    return false;
-
-  if (!profile || !profile->GetPrefs() ||
-      !chrome_browser_net::CanPreresolveAndPreconnectUI(profile->GetPrefs())) {
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace
-
 const char kSpeculativePreconnectFeatureName[] = "SpeculativePreconnect";
-const char kModeParamName[] = "mode";
-const char kLearningMode[] = "learning";
-const char kPreconnectMode[] = "preconnect";
-const char kNoPreconnectMode[] = "no-preconnect";
-
 const base::Feature kSpeculativePreconnectFeature{
     kSpeculativePreconnectFeatureName, base::FEATURE_ENABLED_BY_DEFAULT};
 
-bool MaybeEnableSpeculativePreconnect(LoadingPredictorConfig* config) {
-  if (!base::FeatureList::IsEnabled(kSpeculativePreconnectFeature))
-    return false;
-
-  std::string mode_value = base::GetFieldTrialParamValueByFeature(
-      kSpeculativePreconnectFeature, kModeParamName);
-  if (mode_value.empty())
-    mode_value = kPreconnectMode;
-
-  if (mode_value == kLearningMode) {
-    if (config) {
-      config->mode |= LoadingPredictorConfig::LEARNING;
-      config->is_origin_learning_enabled = true;
-    }
-    return true;
-  } else if (mode_value == kPreconnectMode) {
-    if (config) {
-      config->mode |=
-          LoadingPredictorConfig::LEARNING | LoadingPredictorConfig::PRECONNECT;
-      config->is_origin_learning_enabled = true;
-      config->should_disable_other_preconnects = true;
-    }
-    return true;
-  } else if (mode_value == kNoPreconnectMode) {
-    if (config) {
-      config->should_disable_other_preconnects = true;
-    }
-    return false;
-  }
-
-  return false;
+// Returns whether the speculative preconnect feature is enabled.
+bool IsPreconnectFeatureEnabled() {
+  return base::FeatureList::IsEnabled(kSpeculativePreconnectFeature);
 }
 
-bool ShouldDisableOtherPreconnects() {
-  LoadingPredictorConfig config;
-  MaybeEnableSpeculativePreconnect(&config);
-  return config.should_disable_other_preconnects;
-}
-
-bool IsLoadingPredictorEnabled(Profile* profile,
-                               LoadingPredictorConfig* config) {
-  // Disabled for of-the-record. Policy choice, not a technical limitation.
+bool IsLoadingPredictorEnabled(Profile* profile) {
+  // Disabled for off-the-record. Policy choice, not a technical limitation.
   if (!profile || profile->IsOffTheRecord())
     return false;
 
-  // Compute both statements because they have side effects.
-  bool preconnect_enabled = MaybeEnableSpeculativePreconnect(config);
-  return preconnect_enabled;
+  // Run the Loading Predictor only if the preconnect feature is turned on,
+  // otherwise the predictor will be no-op.
+  return IsPreconnectFeatureEnabled();
+}
+
+bool IsPreconnectAllowed(Profile* profile) {
+  if (!IsPreconnectFeatureEnabled())
+    return false;
+
+  // Checks that the preconnect is allowed by user settings.
+  return profile && profile->GetPrefs() &&
+         chrome_browser_net::CanPreresolveAndPreconnectUI(profile->GetPrefs());
 }
 
 LoadingPredictorConfig::LoadingPredictorConfig()
-    : mode(0),
-      max_navigation_lifetime_seconds(60),
+    : max_navigation_lifetime_seconds(60),
       max_hosts_to_track(100),
       max_origins_per_entry(50),
       max_consecutive_misses(3),
       max_redirect_consecutive_misses(5),
-      is_origin_learning_enabled(false),
-      should_disable_other_preconnects(false),
       flush_data_to_disk_delay_seconds(30) {}
 
 LoadingPredictorConfig::LoadingPredictorConfig(
@@ -106,21 +50,6 @@
 
 LoadingPredictorConfig::~LoadingPredictorConfig() = default;
 
-bool LoadingPredictorConfig::IsLearningEnabled() const {
-  return (mode & LEARNING) > 0;
-}
-
-bool LoadingPredictorConfig::IsPreconnectEnabledForSomeOrigin(
-    Profile* profile) const {
-  return IsPreconnectEnabledInternal(profile, mode, PRECONNECT);
-}
-
-bool LoadingPredictorConfig::IsPreconnectEnabledForOrigin(
-    Profile* profile,
-    HintOrigin origin) const {
-  return IsPreconnectEnabledInternal(profile, mode, PRECONNECT);
-}
-
 bool LoadingPredictorConfig::IsSmallDBEnabledForTest() const {
   return max_hosts_to_track == 100;
 }
diff --git a/chrome/browser/predictors/loading_predictor_config.h b/chrome/browser/predictors/loading_predictor_config.h
index 32f5fe5..d8922440 100644
--- a/chrome/browser/predictors/loading_predictor_config.h
+++ b/chrome/browser/predictors/loading_predictor_config.h
@@ -14,25 +14,20 @@
 namespace predictors {
 
 extern const char kSpeculativePreconnectFeatureName[];
-extern const char kModeParamName[];
-extern const char kLearningMode[];
-extern const char kPreconnectMode[];
-extern const char kNoPreconnectMode[];
 extern const base::Feature kSpeculativePreconnectFeature;
 
-struct LoadingPredictorConfig;
+// Returns whether the speculative preconnect feature is enabled.
+bool IsPreconnectFeatureEnabled();
 
-// Returns whether the predictor is enabled, and populates |config|, if not
-// nullptr.
-bool IsLoadingPredictorEnabled(Profile* profile,
-                               LoadingPredictorConfig* config);
+// Returns whether the Loading Predictor is enabled for the given |profile|. If
+// true, the predictor can observe page load events, build historical database
+// and perform allowed speculative actions based on this database.
+bool IsLoadingPredictorEnabled(Profile* profile);
 
-// Returns true if speculative preconnect is enabled, and initializes |config|,
-// if not nullptr.
-bool MaybeEnableSpeculativePreconnect(LoadingPredictorConfig* config);
-
-// Returns true if all other implementations of preconnect should be disabled.
-bool ShouldDisableOtherPreconnects();
+// Returns whether the current |profile| settings allow to perform preresolve
+// and preconnect actions. This setting is controlled by the user, so the return
+// value shouldn't be cached.
+bool IsPreconnectAllowed(Profile* profile);
 
 // Indicates what caused the page load hint.
 enum class HintOrigin { NAVIGATION, EXTERNAL, OMNIBOX };
@@ -44,20 +39,6 @@
   LoadingPredictorConfig(const LoadingPredictorConfig& other);
   ~LoadingPredictorConfig();
 
-  // The mode the LoadingPredictor is running in. Forms a bit map.
-  enum Mode {
-    LEARNING = 1 << 0,
-    PREFETCHING_FOR_NAVIGATION = 1 << 2,  // deprecated
-    PREFETCHING_FOR_EXTERNAL = 1 << 3,    // deprecated
-    PRECONNECT = 1 << 4
-  };
-  int mode;
-
-  // Helpers to deal with mode.
-  bool IsLearningEnabled() const;
-  bool IsPreconnectEnabledForSomeOrigin(Profile* profile) const;
-  bool IsPreconnectEnabledForOrigin(Profile* profile, HintOrigin origin) const;
-
   bool IsSmallDBEnabledForTest() const;
 
   // If a navigation hasn't seen a load complete event in this much time, it
@@ -76,12 +57,6 @@
   // endpoint.
   size_t max_redirect_consecutive_misses;
 
-  // True iff origin-based learning is enabled.
-  bool is_origin_learning_enabled;
-
-  // True iff all other implementations of preconnect should be disabled.
-  bool should_disable_other_preconnects;
-
   // Delay between writing data to the predictors database memory cache and
   // flushing it to disk.
   size_t flush_data_to_disk_delay_seconds;
diff --git a/chrome/browser/predictors/loading_predictor_config_unittest.cc b/chrome/browser/predictors/loading_predictor_config_unittest.cc
index 979e3b00..fefeb66 100644
--- a/chrome/browser/predictors/loading_predictor_config_unittest.cc
+++ b/chrome/browser/predictors/loading_predictor_config_unittest.cc
@@ -2,123 +2,69 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <memory>
-#include <string>
-
-#include "base/memory/ptr_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/net/prediction_options.h"
 #include "chrome/browser/predictors/loading_predictor_config.h"
-#include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/pref_service.h"
-#include "components/variations/variations_params_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "net/base/network_change_notifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using chrome_browser_net::NetworkPredictionOptions;
-using net::NetworkChangeNotifier;
-
-namespace {
-
-class MockNetworkChangeNotifierWIFI : public NetworkChangeNotifier {
- public:
-  ConnectionType GetCurrentConnectionType() const override {
-    return NetworkChangeNotifier::CONNECTION_WIFI;
-  }
-};
-
-class MockNetworkChangeNotifier4G : public NetworkChangeNotifier {
- public:
-  ConnectionType GetCurrentConnectionType() const override {
-    return NetworkChangeNotifier::CONNECTION_4G;
-  }
-};
-
-}  // namespace
-
 namespace predictors {
 
 class LoadingPredictorConfigTest : public testing::Test {
  public:
-  LoadingPredictorConfigTest();
-
-  void SetPreference(NetworkPredictionOptions value) {
-    profile_->GetPrefs()->SetInteger(prefs::kNetworkPredictionOptions, value);
+  void SetPreference(chrome_browser_net::NetworkPredictionOptions value) {
+    profile_.GetPrefs()->SetInteger(prefs::kNetworkPredictionOptions, value);
   }
 
- protected:
+  Profile* profile() { return &profile_; }
+
+ private:
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
-  std::unique_ptr<TestingProfile> profile_;
+  TestingProfile profile_;
 };
 
-LoadingPredictorConfigTest::LoadingPredictorConfigTest()
-    : profile_(new TestingProfile()) {}
-
-TEST_F(LoadingPredictorConfigTest, Enabled) {
+TEST_F(LoadingPredictorConfigTest, FeatureAndPrefEnabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(predictors::kSpeculativePreconnectFeature);
+  SetPreference(chrome_browser_net::NETWORK_PREDICTION_ALWAYS);
 
-  LoadingPredictorConfig config;
-  EXPECT_TRUE(MaybeEnableSpeculativePreconnect(&config));
-
-  EXPECT_TRUE(config.IsLearningEnabled());
-  EXPECT_TRUE(config.should_disable_other_preconnects);
-  EXPECT_TRUE(config.IsPreconnectEnabledForSomeOrigin(profile_.get()));
+  EXPECT_TRUE(IsPreconnectFeatureEnabled());
+  EXPECT_TRUE(IsLoadingPredictorEnabled(profile()));
+  EXPECT_TRUE(IsPreconnectAllowed(profile()));
 }
 
-TEST_F(LoadingPredictorConfigTest, Disabled) {
+TEST_F(LoadingPredictorConfigTest, FeatureDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(predictors::kSpeculativePreconnectFeature);
+  SetPreference(chrome_browser_net::NETWORK_PREDICTION_ALWAYS);
 
-  LoadingPredictorConfig config;
-  EXPECT_FALSE(MaybeEnableSpeculativePreconnect(&config));
-
-  EXPECT_FALSE(config.IsLearningEnabled());
-  EXPECT_FALSE(config.should_disable_other_preconnects);
-  EXPECT_FALSE(config.IsPreconnectEnabledForSomeOrigin(profile_.get()));
+  EXPECT_FALSE(IsPreconnectFeatureEnabled());
+  EXPECT_FALSE(IsLoadingPredictorEnabled(profile()));
+  EXPECT_FALSE(IsPreconnectAllowed(profile()));
 }
 
-TEST_F(LoadingPredictorConfigTest, EnablePreconnectLearning) {
-  variations::testing::VariationParamsManager params_manager(
-      "dummy-trial", {{kModeParamName, kLearningMode}},
-      {kSpeculativePreconnectFeatureName});
+TEST_F(LoadingPredictorConfigTest, FeatureEnabledAndPrefDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(predictors::kSpeculativePreconnectFeature);
+  SetPreference(chrome_browser_net::NETWORK_PREDICTION_NEVER);
 
-  LoadingPredictorConfig config;
-  EXPECT_TRUE(MaybeEnableSpeculativePreconnect(&config));
-
-  EXPECT_TRUE(config.IsLearningEnabled());
-  EXPECT_TRUE(config.is_origin_learning_enabled);
-  EXPECT_FALSE(config.should_disable_other_preconnects);
-  EXPECT_FALSE(config.IsPreconnectEnabledForSomeOrigin(profile_.get()));
+  EXPECT_TRUE(IsPreconnectFeatureEnabled());
+  EXPECT_TRUE(IsLoadingPredictorEnabled(profile()));
+  EXPECT_FALSE(IsPreconnectAllowed(profile()));
 }
 
-TEST_F(LoadingPredictorConfigTest, EnablePreconnect) {
-  variations::testing::VariationParamsManager params_manager(
-      "dummy-trial", {{kModeParamName, kPreconnectMode}},
-      {kSpeculativePreconnectFeatureName});
+TEST_F(LoadingPredictorConfigTest, OffTheRecordProfile) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(predictors::kSpeculativePreconnectFeature);
+  SetPreference(chrome_browser_net::NETWORK_PREDICTION_ALWAYS);
+  Profile* incognito = profile()->GetOffTheRecordProfile();
 
-  LoadingPredictorConfig config;
-  EXPECT_TRUE(MaybeEnableSpeculativePreconnect(&config));
-
-  EXPECT_TRUE(config.IsLearningEnabled());
-  EXPECT_TRUE(config.should_disable_other_preconnects);
-  EXPECT_TRUE(config.IsPreconnectEnabledForSomeOrigin(profile_.get()));
-}
-
-TEST_F(LoadingPredictorConfigTest, EnableNoPreconnect) {
-  variations::testing::VariationParamsManager params_manager(
-      "dummy-trial", {{kModeParamName, kNoPreconnectMode}},
-      {kSpeculativePreconnectFeatureName});
-
-  LoadingPredictorConfig config;
-  EXPECT_FALSE(MaybeEnableSpeculativePreconnect(&config));
-
-  EXPECT_FALSE(config.IsLearningEnabled());
-  EXPECT_TRUE(config.should_disable_other_preconnects);
-  EXPECT_FALSE(config.IsPreconnectEnabledForSomeOrigin(profile_.get()));
+  EXPECT_TRUE(IsPreconnectFeatureEnabled());
+  EXPECT_FALSE(IsLoadingPredictorEnabled(incognito));
+  EXPECT_TRUE(IsPreconnectAllowed(incognito));
 }
 
 }  // namespace predictors
diff --git a/chrome/browser/predictors/loading_predictor_factory.cc b/chrome/browser/predictors/loading_predictor_factory.cc
index 057a558..1166d85 100644
--- a/chrome/browser/predictors/loading_predictor_factory.cc
+++ b/chrome/browser/predictors/loading_predictor_factory.cc
@@ -39,11 +39,10 @@
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
 
-  LoadingPredictorConfig config;
-  if (!IsLoadingPredictorEnabled(profile, &config))
+  if (!IsLoadingPredictorEnabled(profile))
     return nullptr;
 
-  return new LoadingPredictor(config, profile);
+  return new LoadingPredictor(LoadingPredictorConfig(), profile);
 }
 
 }  // namespace predictors
diff --git a/chrome/browser/predictors/loading_predictor_unittest.cc b/chrome/browser/predictors/loading_predictor_unittest.cc
index 517cb71..15ceec7 100644
--- a/chrome/browser/predictors/loading_predictor_unittest.cc
+++ b/chrome/browser/predictors/loading_predictor_unittest.cc
@@ -11,8 +11,11 @@
 #include <vector>
 
 #include "base/test/metrics/histogram_tester.h"
+#include "chrome/browser/net/prediction_options.h"
 #include "chrome/browser/predictors/loading_test_util.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "net/url_request/url_request_context.h"
@@ -60,17 +63,22 @@
                                              Profile* profile)
     : PreconnectManager(delegate, profile) {}
 
+LoadingPredictorConfig CreateConfig() {
+  LoadingPredictorConfig config;
+  PopulateTestConfig(&config);
+  return config;
+}
+
 }  // namespace
 
 class LoadingPredictorTest : public testing::Test {
  public:
-  LoadingPredictorTest();
   ~LoadingPredictorTest() override;
   void SetUp() override;
   void TearDown() override;
 
  protected:
-  virtual LoadingPredictorConfig CreateConfig();
+  virtual void SetPreference();
 
   content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<TestingProfile> profile_;
@@ -78,12 +86,11 @@
   StrictMock<MockResourcePrefetchPredictor>* mock_predictor_;
 };
 
-LoadingPredictorTest::LoadingPredictorTest()
-    : profile_(std::make_unique<TestingProfile>()) {}
-
 LoadingPredictorTest::~LoadingPredictorTest() = default;
 
 void LoadingPredictorTest::SetUp() {
+  profile_ = std::make_unique<TestingProfile>();
+  SetPreference();
   auto config = CreateConfig();
   predictor_ = std::make_unique<LoadingPredictor>(config, profile_.get());
 
@@ -107,10 +114,10 @@
   predictor_->Shutdown();
 }
 
-LoadingPredictorConfig LoadingPredictorTest::CreateConfig() {
-  LoadingPredictorConfig config;
-  PopulateTestConfig(&config);
-  return config;
+void LoadingPredictorTest::SetPreference() {
+  profile_->GetPrefs()->SetInteger(
+      prefs::kNetworkPredictionOptions,
+      chrome_browser_net::NETWORK_PREDICTION_NEVER);
 }
 
 class LoadingPredictorPreconnectTest : public LoadingPredictorTest {
@@ -118,7 +125,8 @@
   void SetUp() override;
 
  protected:
-  LoadingPredictorConfig CreateConfig() override;
+  void SetPreference() override;
+
   StrictMock<MockPreconnectManager>* mock_preconnect_manager_;
 };
 
@@ -131,10 +139,10 @@
   predictor_->set_mock_preconnect_manager(std::move(mock_preconnect_manager));
 }
 
-LoadingPredictorConfig LoadingPredictorPreconnectTest::CreateConfig() {
-  LoadingPredictorConfig config = LoadingPredictorTest::CreateConfig();
-  config.mode |= LoadingPredictorConfig::PRECONNECT;
-  return config;
+void LoadingPredictorPreconnectTest::SetPreference() {
+  profile_->GetPrefs()->SetInteger(
+      prefs::kNetworkPredictionOptions,
+      chrome_browser_net::NETWORK_PREDICTION_ALWAYS);
 }
 
 TEST_F(LoadingPredictorTest, TestPrefetchingDurationHistogram) {
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc
index 01d682df..ea61f37 100644
--- a/chrome/browser/predictors/loading_test_util.cc
+++ b/chrome/browser/predictors/loading_test_util.cc
@@ -146,8 +146,6 @@
     config->max_consecutive_misses = 2;
     config->max_redirect_consecutive_misses = 2;
   }
-  config->is_origin_learning_enabled = true;
-  config->mode = LoadingPredictorConfig::LEARNING;
   config->flush_data_to_disk_delay_seconds = 0;
 }
 
diff --git a/chrome/browser/predictors/preconnect_manager.cc b/chrome/browser/predictors/preconnect_manager.cc
index 7305e3ac..6c6c2b7 100644
--- a/chrome/browser/predictors/preconnect_manager.cc
+++ b/chrome/browser/predictors/preconnect_manager.cc
@@ -64,9 +64,7 @@
   DCHECK(profile_);
 }
 
-PreconnectManager::~PreconnectManager() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-}
+PreconnectManager::~PreconnectManager() = default;
 
 void PreconnectManager::Start(const GURL& url,
                               std::vector<PreconnectRequest> requests) {
diff --git a/chrome/browser/predictors/predictor_database.cc b/chrome/browser/predictors/predictor_database.cc
index 3bfa132..8e9072b 100644
--- a/chrome/browser/predictors/predictor_database.cc
+++ b/chrome/browser/predictors/predictor_database.cc
@@ -84,7 +84,7 @@
   // This db does not use [meta] table, store mmap status data elsewhere.
   db_->set_mmap_alt_status();
 
-  is_loading_predictor_enabled_ = IsLoadingPredictorEnabled(profile, nullptr);
+  is_loading_predictor_enabled_ = IsLoadingPredictorEnabled(profile);
 }
 
 PredictorDatabaseInternal::~PredictorDatabaseInternal() {
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index 4373e08..4c26ff5 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -136,9 +136,6 @@
       history_service_observer_(this),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  // Some form of learning has to be enabled.
-  DCHECK(config_.IsLearningEnabled());
 }
 
 ResourcePrefetchPredictor::~ResourcePrefetchPredictor() {}
@@ -200,9 +197,7 @@
 
   const std::string& host = summary->main_frame_url.host();
   LearnRedirect(summary->initial_url.host(), host, host_redirect_data_.get());
-
-  if (config_.is_origin_learning_enabled)
-    LearnOrigins(host, summary->main_frame_url.GetOrigin(), summary->origins);
+  LearnOrigins(host, summary->main_frame_url.GetOrigin(), summary->origins);
 
   if (observer_)
     observer_->OnNavigationLearned(*summary);
diff --git a/chrome/browser/resources/chrome_app/manifest.json b/chrome/browser/resources/chrome_app/manifest.json
index 3f1c329..0714d7a4 100644
--- a/chrome/browser/resources/chrome_app/manifest.json
+++ b/chrome/browser/resources/chrome_app/manifest.json
@@ -4,8 +4,8 @@
   "version": "0.1",
   "description": "Chrome as an app",
   "icons": {
-    "16": "product_logo_16.png",
-    "128": "product_logo_128.png"
+    "32": "chrome_app_icon_32.png",
+    "192": "chrome_app_icon_192.png"
   },
   "app": {
     "launch": {
diff --git a/chrome/browser/resources/chromeos/login/enrollment_license_card.html b/chrome/browser/resources/chromeos/login/enrollment_license_card.html
index 6946020d4..024ce26 100644
--- a/chrome/browser/resources/chromeos/login/enrollment_license_card.html
+++ b/chrome/browser/resources/chromeos/login/enrollment_license_card.html
@@ -25,16 +25,19 @@
 <dom-module id="enrollment-license-card">
   <template>
     <link rel="stylesheet" href="gaia_input_form.css">
+    <link rel="stylesheet" href="enterprise_card.css">
     <link rel="stylesheet" href="enterprise_card_footer.css">
     <link rel="stylesheet" href="enrollment_license_card.css">
 
     <enterprise-card id="license-selection-prompt-card" class="fit">
       <enterprise-header slot="header"
-                         i18n-values="header-title:oauthEnrollScreenTitle;
-                   header-comment:licenseSelectionCardExplanation">
+                         i18n-values="header-title:oauthEnrollScreenTitle">
         <hd-iron-icon slot="enterprise-icon"
                       icon1x="enterprise-header-32:briefcase"
                       icon2x="enterprise-header-64:briefcase"></hd-iron-icon>
+        <div slot="header-comment" class="header-comment">
+          [[i18nDynamic(locale, 'licenseSelectionCardExplanation')]]
+        </div>
       </enterprise-header>
       <div slot="content" class="content flex vertical layout justified">
         <div>
diff --git a/chrome/browser/resources/chromeos/login/enterprise_card.css b/chrome/browser/resources/chromeos/login/enterprise_card.css
index 0766dba4..914d8ef8 100644
--- a/chrome/browser/resources/chromeos/login/enterprise_card.css
+++ b/chrome/browser/resources/chromeos/login/enterprise_card.css
@@ -28,8 +28,14 @@
   padding: 64px 64px 0 64px;
 }
 
+.header-comment {
+  color: #333;
+  font-size: 13px;
+  line-height: 20px;
+  min-height: 40px;
+}
+
 .content-container {
-  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.17);
   padding: 0 64px 0 64px;
   z-index: 1;
 }
diff --git a/chrome/browser/resources/chromeos/login/enterprise_header.css b/chrome/browser/resources/chromeos/login/enterprise_header.css
index cf1c724..0139178 100644
--- a/chrome/browser/resources/chromeos/login/enterprise_header.css
+++ b/chrome/browser/resources/chromeos/login/enterprise_header.css
@@ -15,12 +15,3 @@
   font-size: 28px;
   height: 64px;
 }
-
-.header-comment {
-  color: #333;
-  display: flex;
-  flex-direction: column-reverse;
-  font-size: 13px;
-  height: 40px;
-  line-height: 20px;
-}
diff --git a/chrome/browser/resources/chromeos/login/enterprise_header.html b/chrome/browser/resources/chromeos/login/enterprise_header.html
index 1f45e28..ab383a1 100644
--- a/chrome/browser/resources/chromeos/login/enterprise_header.html
+++ b/chrome/browser/resources/chromeos/login/enterprise_header.html
@@ -49,9 +49,7 @@
       <div class="header-title" hidden$="{{!headerTitle}}">
         <span>[[headerTitle]]</span>
       </div>
-      <div class="header-comment" hidden$="{{!headerComment}}">
-        <span>[[headerComment]]</span>
-      </div>
+      <slot name="header-comment"></slot>
     </div>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/login/enterprise_header.js b/chrome/browser/resources/chromeos/login/enterprise_header.js
index f61bc14..bc78c0a 100644
--- a/chrome/browser/resources/chromeos/login/enterprise_header.js
+++ b/chrome/browser/resources/chromeos/login/enterprise_header.js
@@ -5,17 +5,13 @@
 Polymer({
   is: 'enterprise-header',
 
+  behaviors: [I18nBehavior],
+
   properties: {
     /**
      * Title of the header
      * @type {String}
      */
     headerTitle: {type: String, value: ''},
-
-    /**
-     * Additional text shown in the header
-     * @type {String}
-     */
-    headerComment: {type: String, value: ''},
   },
 });
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.html b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.html
index 90f66594..4ede965 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.html
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://oobe/custom_elements.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="stylesheet" href="enterprise_card.css">
 <link rel="stylesheet" href="gaia_card_parameters.css">
 
 <div id="oauth-enrollment" class="step no-logo hidden" hidden>
@@ -61,11 +62,13 @@
     <div id="oauth-enroll-step-success" role="alert">
       <enterprise-card id="oauth-enroll-success-card">
         <enterprise-header slot="header"
-            i18n-values="header-title:oauthEnrollSuccessTitle;
-                header-comment:oauthEnrollSuccess">
+            i18n-values="header-title:oauthEnrollSuccessTitle">
           <hd-iron-icon slot="enterprise-icon"
               icon1x="enterprise-header-32:briefcase"
               icon2x="enterprise-header-64:briefcase"></hd-iron-icon>
+          <div slot="header-comment" class="header-comment"
+               i18n-content="oauthEnrollSuccess">
+          </div>
         </enterprise-header >
         <div slot="content" class="layout vertical center">
           <img srcset="images/enrollment_success_illustration_1x.png 1x,
@@ -82,16 +85,20 @@
       <div id="oauth-enroll-step-abe-success" role="alert">
         <enterprise-card id="oauth-enroll-abe-success-card">
             <enterprise-header slot="header"
-               i18n-values="header-title:oauthEnrollSuccessTitle;
-                   header-comment:oauthEnrollSuccess">
+               i18n-values="header-title:oauthEnrollSuccessTitle">
               <hd-iron-icon slot="enterprise-icon"
                   icon1x="enterprise-header-32:briefcase"
                   icon2x="enterprise-header-64:briefcase"></hd-iron-icon>
+              <div slot="header-comment" class="header-comment"
+                   id="oauth-enroll-abe-success-comment-no-domain"
+                   i18n-content="oauthEnrollSuccess"></div>
+              <div slot="header-comment" class="header-comment"
+                     id="oauth-enroll-abe-success-comment-domain" hidden></div>
             </enterprise-header >
-            <div class="layout vertical center">
-                <img srcset="images/enrollment_success_illustration_1x.png 1x,
-                         images/enrollment_success_illustration_2x.png 2x"
-                     i18n-values="alt:enrollmentSuccessIllustrationTitle">
+            <div slot="content" class="layout vertical center">
+              <img srcset="images/enrollment_success_illustration_1x.png 1x,
+                    images/enrollment_success_illustration_2x.png 2x"
+                   i18n-values="alt:enrollmentSuccessIllustrationTitle">
             </div>
           <div slot="footer"
               class="footer horizontal-reverse justified layout center">
@@ -104,11 +111,13 @@
     <div id="oauth-enroll-step-attribute-prompt">
         <enterprise-card id="oauth-enroll-attribute-prompt-card">
             <enterprise-header slot="header"
-               i18n-values="header-title:oauthEnrollScreenTitle;
-                   header-comment:oauthEnrollDeviceInformation">
+               i18n-values="header-title:oauthEnrollScreenTitle">
               <hd-iron-icon slot="enterprise-icon"
                   icon1x="enterprise-header-32:briefcase"
                   icon2x="enterprise-header-64:briefcase"></hd-iron-icon>
+              <div slot="header-comment" class="header-comment"
+                   i18n-content="oauthEnrollDeviceInformation">
+              </div>
             </enterprise-header >
             <div slot="content" class="layout vertical start">
                 <div class="oauth-enroll-step-message">
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
index ff498fc..a1dca61 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
@@ -320,8 +320,11 @@
      */
     showAttestationBasedEnrollmentSuccess: function(
         device, enterpriseEnrollmentDomain) {
-      $('oauth-enroll-abe-success-card').innerHTML = loadTimeData.getStringF(
-          'oauthEnrollAbeSuccess', device, enterpriseEnrollmentDomain);
+      $('oauth-enroll-abe-success-comment-no-domain').hidden = true;
+      $('oauth-enroll-abe-success-comment-domain').hidden = false;
+      $('oauth-enroll-abe-success-comment-domain').innerHTML =
+          loadTimeData.getStringF(
+              'oauthEnrollAbeSuccess', device, enterpriseEnrollmentDomain);
       this.showStep(STEP_ABE_SUCCESS);
     },
 
diff --git a/chrome/browser/resources/chromeos/switch_access/commands.js b/chrome/browser/resources/chromeos/switch_access/commands.js
index 273db48a..9443052 100644
--- a/chrome/browser/resources/chromeos/switch_access/commands.js
+++ b/chrome/browser/resources/chromeos/switch_access/commands.js
@@ -64,7 +64,7 @@
   buildCommandMap_: function() {
     return {
       'next': {
-        'defaultKeyCode': 49, /* '1' key */
+        'defaultKeyCode': 51, /* '3' key */
         'binding': this.switchAccess_.moveForward.bind(this.switchAccess_)
       },
       'previous': {
@@ -72,7 +72,11 @@
         'binding': this.switchAccess_.moveBackward.bind(this.switchAccess_)
       },
       'select': {
-        'defaultKeyCode': 51, /* '3' key */
+        'defaultKeyCode': 49, /* '1' key */
+        'binding': this.switchAccess_.selectCurrentNode.bind(this.switchAccess_)
+      },
+      'menu': {
+        'defaultKeyCode': 52, /* '4' key */
         'binding': this.switchAccess_.enterContextMenu.bind(this.switchAccess_)
       }
     };
diff --git a/chrome/browser/resources/chromeos/switch_access/options.html b/chrome/browser/resources/chromeos/switch_access/options.html
index 9d56e00..bd12eb1a 100644
--- a/chrome/browser/resources/chromeos/switch_access/options.html
+++ b/chrome/browser/resources/chromeos/switch_access/options.html
@@ -26,6 +26,10 @@
   <h2>Keyboard Mapping</h2>
   <div id="keyboardMappingDiv" class="container">
     <label>
+      <span>Select: </span>
+      <input id="select" type="text" maxlength="1">
+    </label>
+    <label>
       <span>Next: </span>
       <input id="next" type="text" maxlength="1">
     </label>
@@ -34,27 +38,9 @@
       <input id="previous" type="text" maxlength="1">
     </label>
     <label>
-      <span>Select: </span>
-      <input id="select" type="text" maxlength="1">
+      <span>Menu: </span>
+      <input id="menu" type="text" maxlength="1">
     </label>
-    <div id="debugKeyMappingDiv">
-      <label>
-        <span>Debug Next: </span>
-        <input id="debugNext" type="text" maxlength="1">
-      </label>
-      <label>
-        <span>Debug Previous: </span>
-        <input id="debugPrevious" type="text" maxlength="1">
-      </label>
-      <label>
-        <span>Debug Child: </span>
-        <input id="debugChild" type="text" maxlength="1">
-      </label>
-      <label>
-        <span>Debug Parent: </span>
-        <input id="debugParent" type="text" maxlength="1">
-      </label>
-    </div>
   </div>
   <script type="text/javascript" src="options.js"></script>
 </body>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index 5ff7eb617..1e7beeb2 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -288,6 +288,9 @@
    * @private
    */
   disableUILanguageCheckbox_: function(languageState, prospectiveUILanguage) {
+    if (this.detailLanguage_ === undefined)
+      return true;
+
     // UI language setting belongs to the primary user.
     if (this.isSecondaryUser_())
       return true;
diff --git a/chrome/browser/resources/settings/people_page/sync_page.js b/chrome/browser/resources/settings/people_page/sync_page.js
index 559f2dc..f2fa222 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.js
+++ b/chrome/browser/resources/settings/people_page/sync_page.js
@@ -248,8 +248,8 @@
     return !!this.unifiedConsentEnabled &&
         (!this.syncStatus.signedIn || !!this.syncStatus.disabled ||
          (!!this.syncStatus.hasError &&
-          this.syncStatus.statusAction ===
-              settings.StatusAction.REAUTHENTICATE));
+          this.syncStatus.statusAction !==
+              settings.StatusAction.ENTER_PASSPHRASE));
   },
 
   /** @protected */
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index 1fc2e7f..1baeb45 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -37,8 +37,9 @@
   explicit ChromeSyncClient(Profile* profile);
   ~ChromeSyncClient() override;
 
+  void Initialize();
+
   // SyncClient implementation.
-  void Initialize() override;
   syncer::SyncService* GetSyncService() override;
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 1ccf87b..b4c81f6 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -181,6 +181,13 @@
 
   Profile* profile = Profile::FromBrowserContext(context);
 
+  std::unique_ptr<browser_sync::ChromeSyncClient> sync_client =
+      client_factory_
+          ? client_factory_->Run(profile)
+          : std::make_unique<browser_sync::ChromeSyncClient>(profile);
+  sync_client->Initialize();
+
+  init_params.sync_client = std::move(sync_client);
   init_params.network_time_update_callback = base::Bind(&UpdateNetworkTime);
   init_params.url_loader_factory =
       content::BrowserContext::GetDefaultStoragePartition(profile)
@@ -190,13 +197,6 @@
   init_params.user_events_separate_pref_group =
       unified_consent::IsUnifiedConsentFeatureEnabled();
 
-  if (!client_factory_) {
-    init_params.sync_client =
-        std::make_unique<browser_sync::ChromeSyncClient>(profile);
-  } else {
-    init_params.sync_client = client_factory_->Run(profile);
-  }
-
   bool local_sync_backend_enabled = false;
 // Since the local sync backend is currently only supported on Windows don't
 // even check the pref on other os-es.
@@ -264,8 +264,6 @@
   }
 
   auto pss = std::make_unique<ProfileSyncService>(std::move(init_params));
-
-  // Will also initialize the sync client.
   pss->Initialize();
   return pss.release();
 }
diff --git a/chrome/browser/sync/profile_sync_service_factory.h b/chrome/browser/sync/profile_sync_service_factory.h
index 621ecf3..8fa620d 100644
--- a/chrome/browser/sync/profile_sync_service_factory.h
+++ b/chrome/browser/sync/profile_sync_service_factory.h
@@ -18,18 +18,19 @@
 }  // namespace base
 
 namespace browser_sync {
+class ChromeSyncClient;
 class ProfileSyncService;
 }  // namespace browser_sync
 
 namespace syncer {
-class SyncClient;
 class SyncService;
 }  // namespace syncer
 
 class ProfileSyncServiceFactory : public BrowserContextKeyedServiceFactory {
  public:
   using SyncClientFactory =
-      base::Callback<std::unique_ptr<syncer::SyncClient>(Profile*)>;
+      base::RepeatingCallback<std::unique_ptr<browser_sync::ChromeSyncClient>(
+          Profile*)>;
 
   static browser_sync::ProfileSyncService* GetForProfile(Profile* profile);
   static bool HasProfileSyncService(Profile* profile);
diff --git a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
index 450e43e..f929c34 100644
--- a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
@@ -253,7 +253,7 @@
   }
 
  protected:
-  std::unique_ptr<syncer::SyncClient> CreateSyncClient(Profile* profile) {
+  std::unique_ptr<ChromeSyncClient> CreateSyncClient(Profile* profile) {
     if (number_of_clients_ignored_ > 0) {
       --number_of_clients_ignored_;
       return std::make_unique<ChromeSyncClient>(profile);
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index f765d4a21..5a8746a 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -24,6 +24,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/frame/window_frame_util.h"
 #include "chrome/common/extensions/manifest_handlers/theme_handler.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/crx_file/id_util.h"
@@ -58,7 +59,7 @@
 // theme packs that aren't int-equal to this. Increment this number if you
 // change default theme assets or if you need themes to recreate their generated
 // images (which are cached).
-const int kThemePackVersion = 58;
+const int kThemePackVersion = 59;
 
 // IDs that are in the DataPack won't clash with the positive integer
 // uint16_t. kHeaderID should always have the maximum value because we want the
@@ -231,7 +232,7 @@
 const size_t kTintTableLength = arraysize(kTintTable);
 
 // Strings used by themes to identify colors in the JSON.
-const StringToIntTable kColorTable[] = {
+constexpr StringToIntTable kOverwritableColorTable[] = {
     {"frame", TP::COLOR_FRAME},
     {"frame_inactive", TP::COLOR_FRAME_INACTIVE},
     {"frame_incognito", TP::COLOR_FRAME_INCOGNITO},
@@ -255,7 +256,23 @@
     {"ntp_header", TP::COLOR_NTP_HEADER},
     {"button_background", TP::COLOR_BUTTON_BACKGROUND},
 };
-const size_t kColorTableLength = arraysize(kColorTable);
+constexpr size_t kOverwritableColorTableLength =
+    base::size(kOverwritableColorTable);
+
+// Colors generated based on the theme, but not overwritable in the theme file.
+constexpr int kNonOverwritableColorTable[] = {
+    TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE,
+    TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
+    TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
+    TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
+};
+constexpr size_t kNonOverwritableColorTableLength =
+    base::size(kNonOverwritableColorTable);
+
+// The maximum number of colors we may need to store (includes ones that can be
+// specified by the theme, and ones that we calculate but can't be specified).
+constexpr size_t kColorsArrayLength =
+    kOverwritableColorTableLength + kNonOverwritableColorTableLength;
 
 // Strings used by themes to identify display properties keys in JSON.
 const StringToIntTable kDisplayProperties[] = {
@@ -515,6 +532,32 @@
   DISALLOW_COPY_AND_ASSIGN(TabBackgroundImageSource);
 };
 
+class ControlButtonBackgroundImageSource : public gfx::CanvasImageSource {
+ public:
+  ControlButtonBackgroundImageSource(SkColor background_color,
+                                     const gfx::ImageSkia& bg_image)
+      : gfx::CanvasImageSource(
+            bg_image.isNull() ? gfx::Size(1, 1) : bg_image.size(),
+            false),
+        background_color_(background_color),
+        bg_image_(bg_image) {}
+
+  ~ControlButtonBackgroundImageSource() override = default;
+
+  void Draw(gfx::Canvas* canvas) override {
+    canvas->DrawColor(background_color_);
+
+    if (!bg_image_.isNull())
+      canvas->TileImageInt(bg_image_, 0, 0, size().width(), size().height());
+  }
+
+ private:
+  const SkColor background_color_;
+  const gfx::ImageSkia bg_image_;
+
+  DISALLOW_COPY_AND_ASSIGN(ControlButtonBackgroundImageSource);
+};
+
 }  // namespace
 
 BrowserThemePack::~BrowserThemePack() {
@@ -531,7 +574,7 @@
   DCHECK(colors_);
 
   int first_available_color = -1;
-  for (size_t i = 0; i < kColorTableLength; ++i) {
+  for (size_t i = 0; i < kColorsArrayLength; ++i) {
     if (colors_[i].id == id) {
       colors_[i].color = color;
       return;
@@ -595,6 +638,11 @@
   // generated.
   pack->GenerateFrameColors();
 
+  // Generate background color information for window control buttons.  This
+  // must be done after frame colors are set, since they are used when
+  // determining window control button colors.
+  pack->GenerateWindowControlButtonColor(&pack->images_);
+
   // Create the tab background images, and generate colors where relevant.  This
   // must be done after all frame colors are set, since they are used when
   // creating these.
@@ -731,9 +779,9 @@
   resources[kTintsID] = base::StringPiece(
       reinterpret_cast<const char*>(tints_),
       sizeof(TintEntry[kTintTableLength]));
-  resources[kColorsID] = base::StringPiece(
-      reinterpret_cast<const char*>(colors_),
-      sizeof(ColorPair[kColorTableLength]));
+  resources[kColorsID] =
+      base::StringPiece(reinterpret_cast<const char*>(colors_),
+                        sizeof(ColorPair[kColorsArrayLength]));
   resources[kDisplayPropertiesID] = base::StringPiece(
       reinterpret_cast<const char*>(display_properties_),
       sizeof(DisplayPropertyPair[kDisplayPropertiesSize]));
@@ -798,7 +846,7 @@
           }));
 
   if (colors_) {
-    for (size_t i = 0; i < kColorTableLength; ++i) {
+    for (size_t i = 0; i < kColorsArrayLength; ++i) {
       if (colors_[i].id == id) {
         *color = colors_[i].color;
         if (base::ContainsKey(*kOpaqueColors, id))
@@ -958,8 +1006,8 @@
 
 void BrowserThemePack::BuildColorsFromJSON(
     const base::DictionaryValue* colors_value) {
-  colors_ = new ColorPair[kColorTableLength];
-  for (size_t i = 0; i < kColorTableLength; ++i) {
+  colors_ = new ColorPair[kColorsArrayLength];
+  for (size_t i = 0; i < kColorsArrayLength; ++i) {
     colors_[i].id = -1;
     colors_[i].color = SkColorSetRGB(0, 0, 0);
   }
@@ -971,7 +1019,8 @@
   // Copy data from the intermediary data structure to the array.
   size_t count = 0;
   for (std::map<int, SkColor>::const_iterator it = temp_colors.begin();
-       it != temp_colors.end() && count < kColorTableLength; ++it, ++count) {
+       it != temp_colors.end() && count < kOverwritableColorTableLength;
+       ++it, ++count) {
     colors_[count].id = it->first;
     colors_[count].color = it->second;
   }
@@ -1014,7 +1063,8 @@
           if (!temp_colors->count(TP::COLOR_NTP_HEADER))
             (*temp_colors)[TP::COLOR_NTP_HEADER] = color;
         } else {
-          int id = GetIntForString(iter.key(), kColorTable, kColorTableLength);
+          int id = GetIntForString(iter.key(), kOverwritableColorTable,
+                                   kOverwritableColorTableLength);
           if (id != -1)
             (*temp_colors)[id] = color;
         }
@@ -1301,6 +1351,70 @@
   }
 }
 
+void BrowserThemePack::GenerateWindowControlButtonColor(ImageCache* images) {
+  static constexpr struct ControlBGValue {
+    // The color to compute and store.
+    int color_id;
+
+    // The frame color to use as the base of this button background.
+    int frame_color_id;
+  } kControlButtonBackgroundMap[] = {
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE, TP::COLOR_FRAME},
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
+       TP::COLOR_FRAME_INACTIVE},
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
+       TP::COLOR_FRAME_INCOGNITO},
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
+       TP::COLOR_FRAME_INCOGNITO_INACTIVE},
+  };
+
+  // Get data related to the control button background image and color first,
+  // since they are shared by all variants.
+  gfx::ImageSkia bg_image;
+  ImageCache::const_iterator bg_img_it =
+      images->find(PRS_THEME_WINDOW_CONTROL_BACKGROUND);
+  if (bg_img_it != images->end())
+    bg_image = bg_img_it->second.AsImageSkia();
+
+  SkColor button_bg_color;
+  SkAlpha button_bg_alpha = SK_AlphaTRANSPARENT;
+  if (GetColor(TP::COLOR_BUTTON_BACKGROUND, &button_bg_color))
+    button_bg_alpha = SkColorGetA(button_bg_color);
+
+  button_bg_alpha =
+      WindowFrameUtil::CalculateWindows10GlassCaptionButtonBackgroundAlpha(
+          button_bg_alpha);
+
+  // Determine what portion of the image to use in our calculations (we won't
+  // use more along the X-axis than the width of the caption buttons).  This
+  // should theoretically be the maximum of the size of the caption button area
+  // on the glass frame and opaque frame, but it would be rather complicated to
+  // determine the size of the opaque frame's caption button area at pack
+  // processing time (as it is determined by the size of icons, which we don't
+  // have easy access to here), so we use the glass frame area as an
+  // approximation.
+  gfx::Size dest_size =
+      WindowFrameUtil::GetWindows10GlassCaptionButtonAreaSize();
+
+  for (const ControlBGValue& bg_pair : kControlButtonBackgroundMap) {
+    SkColor frame_color;
+    GetColor(bg_pair.frame_color_id, &frame_color);
+    SkColor base_color =
+        color_utils::AlphaBlend(button_bg_color, frame_color, button_bg_alpha);
+
+    if (bg_image.isNull()) {
+      SetColor(bg_pair.color_id, base_color);
+      continue;
+    }
+
+    auto source = std::make_unique<ControlButtonBackgroundImageSource>(
+        base_color, bg_image);
+    const gfx::Image dest_image(gfx::ImageSkia(std::move(source), dest_size));
+
+    ComputeColorFromImage(bg_pair.color_id, dest_size.height(), dest_image);
+  }
+}
+
 void BrowserThemePack::CreateTabBackgroundImagesAndColors(ImageCache* images) {
   static constexpr struct TabValues {
     // The background image to create/update.
@@ -1367,7 +1481,8 @@
           frame_color, image_to_tint, overlay,
           GetTintInternal(TP::TINT_BACKGROUND_TAB), TP::kFrameHeightAboveTabs);
       gfx::Size dest_size = image_to_tint.size();
-      dest_size.SetToMax(gfx::Size(0, kTallestTabHeight));
+      dest_size.SetToMax(overlay.size());
+      dest_size.set_height(kTallestTabHeight);
       const gfx::Image dest_image(gfx::ImageSkia(std::move(source), dest_size));
       temp_output[tab_id] = dest_image;
 
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h
index 2e9a36f5..56909a3 100644
--- a/chrome/browser/themes/browser_theme_pack.h
+++ b/chrome/browser/themes/browser_theme_pack.h
@@ -170,6 +170,12 @@
   // Generates any frame colors which have not already been set.
   void GenerateFrameColors();
 
+  // Generates background color information for the background of window control
+  // buttons.  This can be used when drawing the window control/caption buttons
+  // to determine what color to draw the symbol, ensuring that it contrasts
+  // sufficiently with the background of the button.
+  void GenerateWindowControlButtonColor(ImageCache* images);
+
   // Creates the semi-transparent tab background images, putting the results
   // in |images|.  Also sets colors corresponding to these images if no explicit
   // color has been specified.  Must be called after GenerateFrameImages().
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index 79a6c37..7d7f198 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/frame/window_frame_util.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/grit/theme_resources.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -64,6 +65,12 @@
   static void BuildFromUnpackedExtension(const base::FilePath& extension_path,
                                          scoped_refptr<BrowserThemePack>* pack);
 
+  // Builds the theme represented by an unpacked extension (located in
+  // {DIR_TEST_DATA}/extensions/|theme_folder|).
+  // The BrowserThemePack is returned in |pack|.
+  static void BuildTestExtensionTheme(const base::StringPiece theme_folder,
+                                      scoped_refptr<BrowserThemePack>* pack);
+
   static base::FilePath GetTestExtensionThemePath(
       base::StringPiece theme_folder);
   static base::FilePath GetStarGazingPath();
@@ -79,8 +86,8 @@
   // Verify that the colors in the theme for |color_id_a| and |color_id_b| are
   // the same.
   static void VerifyColorsMatch(BrowserThemePack* pack,
-                                TP::OverwritableByUserThemeProperty color_id_a,
-                                TP::OverwritableByUserThemeProperty color_id_b);
+                                int color_id_a,
+                                int color_id_b);
 
   const BrowserThemePack& theme_pack() const { return *theme_pack_; }
 
@@ -223,6 +230,14 @@
 }
 
 // static
+void BrowserThemePackTest::BuildTestExtensionTheme(
+    const base::StringPiece theme_folder,
+    scoped_refptr<BrowserThemePack>* pack) {
+  base::FilePath contrast_theme_path = GetTestExtensionThemePath(theme_folder);
+  BuildFromUnpackedExtension(contrast_theme_path, pack);
+}
+
+// static
 base::FilePath BrowserThemePackTest::GetTestExtensionThemePath(
     base::StringPiece theme_folder) {
   base::FilePath test_path;
@@ -433,10 +448,9 @@
 }
 
 // static
-void BrowserThemePackTest::VerifyColorsMatch(
-    BrowserThemePack* pack,
-    TP::OverwritableByUserThemeProperty color_id_a,
-    TP::OverwritableByUserThemeProperty color_id_b) {
+void BrowserThemePackTest::VerifyColorsMatch(BrowserThemePack* pack,
+                                             int color_id_a,
+                                             int color_id_b) {
   SkColor color_a;
   SkColor color_b;
 
@@ -742,11 +756,8 @@
 // are too similar, the importing process modifies the text color so that it
 // maintains a minimum readable contrast ratio with the background.
 TEST_F(BrowserThemePackTest, TestBackgroundTabTextMinimumContrast) {
-  // Build a theme from test file (theme_tabcontrast).
-  base::FilePath contrast_theme_path =
-      GetTestExtensionThemePath("theme_tabcontrast");
   scoped_refptr<BrowserThemePack> pack;
-  BuildFromUnpackedExtension(contrast_theme_path, &pack);
+  BuildTestExtensionTheme("theme_tabcontrast", &pack);
 
   // Check the contrast ratio of text/tab color pairs to make sure that they
   // meet the minimum criteria for readable contrast ratio.
@@ -805,13 +816,8 @@
 // COLOR_BACKGROUND_TAB_TEXT, that color is used for the other variants of
 // background tab text (inactive, incognito, and incognito+inactive).
 TEST_F(BrowserThemePackTest, TestBGTabTextColorAutoAssign) {
-  // Build a theme from the test file (theme_testinherittextcolor)
-  // This theme specifies a color for background_tab_text, but none of its
-  // variants.
-  base::FilePath contrast_theme_path =
-      GetTestExtensionThemePath("theme_testinherittextcolor");
   scoped_refptr<BrowserThemePack> pack;
-  BuildFromUnpackedExtension(contrast_theme_path, &pack);
+  BuildTestExtensionTheme("theme_testinherittextcolor", &pack);
 
   // Verify that all background tab text colors match the color for background
   // tab text.
@@ -828,13 +834,8 @@
 // COLOR_BACKGROUND_TAB_TEXT and COLOR_BACKGROUND_TAB_TEXT_INCOGNITO, those
 // colors are also used for their respective inactive variants.
 TEST_F(BrowserThemePackTest, TestBGTabTextColorAutoAssign_WithIncognito) {
-  // Build a theme from the test file (theme_testinherittextcolor_withincog)
-  // This theme specifies a color for background_tab_text and
-  // background_tab_text_incognito, but neither of their inactive variants.
-  base::FilePath contrast_theme_path =
-      GetTestExtensionThemePath("theme_testinherittextcolor_withincog");
   scoped_refptr<BrowserThemePack> pack;
-  BuildFromUnpackedExtension(contrast_theme_path, &pack);
+  BuildTestExtensionTheme("theme_testinherittextcolor_withincog", &pack);
 
   // Verify that background_inactive is getting its color from background, and
   // background_incognito_inactive is getting its color from
@@ -870,3 +871,95 @@
   VerifyColorsMatch(pack_ptr, TP::COLOR_BACKGROUND_TAB_TEXT_INCOGNITO_INACTIVE,
                     TP::COLOR_BACKGROUND_TAB_TEXT);
 }
+
+// Ensure that, given a theme which only specifies a frame color, the calculated
+// caption button background colors appropriately match the frame color.
+TEST_F(BrowserThemePackTest, TestWindowControlButtonBGColor_FrameColor) {
+  scoped_refptr<BrowserThemePack> pack;
+  BuildTestExtensionTheme("theme_test_captionbutton_framecolor", &pack);
+
+  // Verify that control button background colors are matching the frame colors.
+  BrowserThemePack* pack_ptr = pack.get();
+  VerifyColorsMatch(pack_ptr, TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE,
+                    TP::COLOR_FRAME);
+  VerifyColorsMatch(pack_ptr,
+                    TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
+                    TP::COLOR_FRAME_INACTIVE);
+  VerifyColorsMatch(pack_ptr,
+                    TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
+                    TP::COLOR_FRAME_INCOGNITO);
+  VerifyColorsMatch(
+      pack_ptr, TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
+      TP::COLOR_FRAME_INCOGNITO_INACTIVE);
+}
+
+// Ensure that, given a theme which specifies a button background color, the
+// calculated caption button background colors appropriately match the button
+// background color blended with the frame color.
+TEST_F(BrowserThemePackTest, TestWindowControlButtonBGColor_ButtonBGColor) {
+  scoped_refptr<BrowserThemePack> pack;
+  BuildTestExtensionTheme("theme_test_captionbutton_buttoncolor", &pack);
+
+  SkColor button_bg_color;
+  const bool has_button_bg_color =
+      pack->GetColor(TP::COLOR_BUTTON_BACKGROUND, &button_bg_color);
+  ASSERT_TRUE(has_button_bg_color);
+  SkAlpha button_bg_alpha = SkColorGetA(button_bg_color);
+
+  // Account for the alpha modification that happens in Windows10CaptionButton.
+  button_bg_alpha =
+      WindowFrameUtil::CalculateWindows10GlassCaptionButtonBackgroundAlpha(
+          button_bg_alpha);
+
+  struct CaptionButtonColorPair {
+    int caption_button_bg_color_id;
+    int frame_color_id;
+  };
+  const CaptionButtonColorPair color_pairs_to_check[] = {
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE, TP::COLOR_FRAME},
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
+       TP::COLOR_FRAME_INACTIVE},
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
+       TP::COLOR_FRAME_INCOGNITO},
+      {TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
+       TP::COLOR_FRAME_INCOGNITO_INACTIVE},
+  };
+
+  for (const CaptionButtonColorPair& current_pair : color_pairs_to_check) {
+    SkColor calculated_button_bg_color;
+    SkColor frame_color;
+
+    pack->GetColor(current_pair.caption_button_bg_color_id,
+                   &calculated_button_bg_color);
+    pack->GetColor(current_pair.frame_color_id, &frame_color);
+
+    SkColor result_color =
+        color_utils::AlphaBlend(button_bg_color, frame_color, button_bg_alpha);
+
+    EXPECT_EQ(calculated_button_bg_color, result_color);
+  }
+}
+
+// Ensure that, given a theme which specifies a light frame color, but a dark
+// caption button image, the calculated caption button background color is dark
+// (to match the bg image).
+TEST_F(BrowserThemePackTest, TestWindowControlButtonBGColor_ButtonBGImage) {
+  scoped_refptr<BrowserThemePack> pack;
+  BuildTestExtensionTheme("theme_test_captionbutton_buttonimage", &pack);
+
+  // Verify that all of the calculated button background colors are on the
+  // 'dark' end of the spectrum.
+  int colors_to_check[] = {
+      TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE,
+      TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
+      TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
+      TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
+  };
+  for (int color_id : colors_to_check) {
+    SkColor control_button_color;
+    const bool has_color = pack->GetColor(color_id, &control_button_color);
+    EXPECT_TRUE(has_color);
+    EXPECT_EQ(SkColorGetA(control_button_color), SK_AlphaOPAQUE);
+    EXPECT_TRUE(color_utils::IsDark(control_button_color));
+  }
+}
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h
index f6aea0d..d8300aa3 100644
--- a/chrome/browser/themes/theme_properties.h
+++ b/chrome/browser/themes/theme_properties.h
@@ -137,6 +137,13 @@
     COLOR_TAB_PIP_PLAYING,
     COLOR_TAB_ALERT_CAPTURING,
 
+    // Calculated representative colors for the background of window control
+    // buttons.
+    COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE,
+    COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
+    COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
+    COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
+
     // These colors don't have constant default values. They are derived from
     // the runtime value of other colors.
     COLOR_NTP_TEXT_LIGHT,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 695409bc..bc352908 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2197,6 +2197,8 @@
 
   if (is_win || is_mac || is_desktop_linux || is_chromeos) {
     sources += [
+      "frame/window_frame_util.cc",
+      "frame/window_frame_util.h",
       "signin_view_controller.cc",
       "signin_view_controller.h",
       "signin_view_controller_delegate.cc",
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 65188b4..c74f993c 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -61,6 +61,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -1053,7 +1054,7 @@
   browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
   browser_shortcut.id = ash::ShelfID(kChromeAppId);
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
+  browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_CHROME_APP_ICON_192);
   browser_shortcut.title = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
   std::unique_ptr<BrowserShortcutLauncherItemController> item_delegate =
       std::make_unique<BrowserShortcutLauncherItemController>(model_);
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
index 4365933..7f3fb1b 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
@@ -219,16 +219,8 @@
     // end of a word so the editing word range is [word start, word end].
     if (iter.IsWord()) {
       location = iter.prev();
-      length = iter.pos() - iter.prev();
+      length = cursor - iter.prev();
     }
-
-    // The suggestion text returned by AppKit has the necessary trailing
-    // whitespace which should replace the existing trailing whitespace.
-    // If the BreakIterator just iterated over whitespace or iterates over
-    // whitespace when it advances, modify the length of the editing word
-    // range to include the whitespace.
-    if ((iter.pos() && !iter.IsWord()) || (iter.Advance() && !iter.IsWord()))
-      length = iter.pos() - location;
   }
 
   return NSMakeRange(location, length);
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
index b1e4f640..bc5949f 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
@@ -318,7 +318,7 @@
                                          range:gfx::Range(1, 7)
                                         offset:kOffset];
     if (@available(macOS 10.12.2, *))
-      EXPECT_EQ(kOffsetRange, [touch_bar_controller_ selectionRange]);
+      EXPECT_EQ(gfx::Range(0, 6), [touch_bar_controller_ selectionRange]);
     else
       EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]);
   }
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
index d6bc8fe..feb982f 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
@@ -61,10 +61,10 @@
 TEST_F(TextSuggestionsTouchBarControllerTest, WordEditingWordRange) {
   if (@available(macOS 10.12.2, *)) {
     EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kWord, 0));
-    EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kWord, 1));
-    EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kWord, 2));
-    EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kWord, 3));
-    EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kWord, 4));
+    EXPECT_EQ(gfx::Range(0, 1), GetEditingWordRange(kWord, 1));
+    EXPECT_EQ(gfx::Range(0, 2), GetEditingWordRange(kWord, 2));
+    EXPECT_EQ(gfx::Range(0, 3), GetEditingWordRange(kWord, 3));
+    EXPECT_EQ(gfx::Range(0, 4), GetEditingWordRange(kWord, 4));
   }
 }
 
@@ -72,11 +72,11 @@
 // through non-word characters.
 TEST_F(TextSuggestionsTouchBarControllerTest, WhitespaceEditingWordRange) {
   if (@available(macOS 10.12.2, *)) {
-    EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kWhitespace, 0));
-    EXPECT_EQ(gfx::Range(1, 5), GetEditingWordRange(kWhitespace, 1));
-    EXPECT_EQ(gfx::Range(2, 5), GetEditingWordRange(kWhitespace, 2));
-    EXPECT_EQ(gfx::Range(3, 5), GetEditingWordRange(kWhitespace, 3));
-    EXPECT_EQ(gfx::Range(4, 5), GetEditingWordRange(kWhitespace, 4));
+    EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kWhitespace, 0));
+    EXPECT_EQ(gfx::Range(1, 1), GetEditingWordRange(kWhitespace, 1));
+    EXPECT_EQ(gfx::Range(2, 2), GetEditingWordRange(kWhitespace, 2));
+    EXPECT_EQ(gfx::Range(3, 3), GetEditingWordRange(kWhitespace, 3));
+    EXPECT_EQ(gfx::Range(4, 4), GetEditingWordRange(kWhitespace, 4));
     EXPECT_EQ(gfx::Range(5, 5), GetEditingWordRange(kWhitespace, 5));
   }
 }
@@ -88,15 +88,15 @@
   if (@available(macOS 10.12.2, *)) {
     EXPECT_EQ(gfx::Range(0, 0),
               GetEditingWordRange(kWordWithTrailingWhitespace, 0));
-    EXPECT_EQ(gfx::Range(0, 6),
+    EXPECT_EQ(gfx::Range(0, 1),
               GetEditingWordRange(kWordWithTrailingWhitespace, 1));
-    EXPECT_EQ(gfx::Range(0, 6),
+    EXPECT_EQ(gfx::Range(0, 2),
               GetEditingWordRange(kWordWithTrailingWhitespace, 2));
-    EXPECT_EQ(gfx::Range(0, 6),
+    EXPECT_EQ(gfx::Range(0, 3),
               GetEditingWordRange(kWordWithTrailingWhitespace, 3));
-    EXPECT_EQ(gfx::Range(0, 6),
+    EXPECT_EQ(gfx::Range(0, 4),
               GetEditingWordRange(kWordWithTrailingWhitespace, 4));
-    EXPECT_EQ(gfx::Range(0, 6),
+    EXPECT_EQ(gfx::Range(0, 5),
               GetEditingWordRange(kWordWithTrailingWhitespace, 5));
     EXPECT_EQ(gfx::Range(6, 6),
               GetEditingWordRange(kWordWithTrailingWhitespace, 6));
@@ -108,17 +108,17 @@
 TEST_F(TextSuggestionsTouchBarControllerTest,
        LeadingWhitespaceEditingWordRange) {
   if (@available(macOS 10.12.2, *)) {
-    EXPECT_EQ(gfx::Range(0, 1),
+    EXPECT_EQ(gfx::Range(0, 0),
               GetEditingWordRange(kWordWithLeadingWhitespace, 0));
     EXPECT_EQ(gfx::Range(1, 1),
               GetEditingWordRange(kWordWithLeadingWhitespace, 1));
-    EXPECT_EQ(gfx::Range(1, 6),
+    EXPECT_EQ(gfx::Range(1, 2),
               GetEditingWordRange(kWordWithLeadingWhitespace, 2));
-    EXPECT_EQ(gfx::Range(1, 6),
+    EXPECT_EQ(gfx::Range(1, 3),
               GetEditingWordRange(kWordWithLeadingWhitespace, 3));
-    EXPECT_EQ(gfx::Range(1, 6),
+    EXPECT_EQ(gfx::Range(1, 4),
               GetEditingWordRange(kWordWithLeadingWhitespace, 4));
-    EXPECT_EQ(gfx::Range(1, 6),
+    EXPECT_EQ(gfx::Range(1, 5),
               GetEditingWordRange(kWordWithLeadingWhitespace, 5));
     EXPECT_EQ(gfx::Range(1, 6),
               GetEditingWordRange(kWordWithLeadingWhitespace, 6));
@@ -130,16 +130,16 @@
 TEST_F(TextSuggestionsTouchBarControllerTest, MultipleWordsEditingWordRange) {
   if (@available(macOS 10.12.2, *)) {
     EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kMultipleWords, 0));
-    EXPECT_EQ(gfx::Range(0, 6), GetEditingWordRange(kMultipleWords, 1));
-    EXPECT_EQ(gfx::Range(0, 6), GetEditingWordRange(kMultipleWords, 2));
-    EXPECT_EQ(gfx::Range(0, 6), GetEditingWordRange(kMultipleWords, 3));
-    EXPECT_EQ(gfx::Range(0, 6), GetEditingWordRange(kMultipleWords, 4));
-    EXPECT_EQ(gfx::Range(0, 6), GetEditingWordRange(kMultipleWords, 5));
+    EXPECT_EQ(gfx::Range(0, 1), GetEditingWordRange(kMultipleWords, 1));
+    EXPECT_EQ(gfx::Range(0, 2), GetEditingWordRange(kMultipleWords, 2));
+    EXPECT_EQ(gfx::Range(0, 3), GetEditingWordRange(kMultipleWords, 3));
+    EXPECT_EQ(gfx::Range(0, 4), GetEditingWordRange(kMultipleWords, 4));
+    EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kMultipleWords, 5));
     EXPECT_EQ(gfx::Range(6, 6), GetEditingWordRange(kMultipleWords, 6));
-    EXPECT_EQ(gfx::Range(6, 11), GetEditingWordRange(kMultipleWords, 7));
-    EXPECT_EQ(gfx::Range(6, 11), GetEditingWordRange(kMultipleWords, 8));
-    EXPECT_EQ(gfx::Range(6, 11), GetEditingWordRange(kMultipleWords, 9));
-    EXPECT_EQ(gfx::Range(6, 11), GetEditingWordRange(kMultipleWords, 10));
+    EXPECT_EQ(gfx::Range(6, 7), GetEditingWordRange(kMultipleWords, 7));
+    EXPECT_EQ(gfx::Range(6, 8), GetEditingWordRange(kMultipleWords, 8));
+    EXPECT_EQ(gfx::Range(6, 9), GetEditingWordRange(kMultipleWords, 9));
+    EXPECT_EQ(gfx::Range(6, 10), GetEditingWordRange(kMultipleWords, 10));
     EXPECT_EQ(gfx::Range(6, 11), GetEditingWordRange(kMultipleWords, 11));
   }
 }
diff --git a/chrome/browser/ui/frame/OWNERS b/chrome/browser/ui/frame/OWNERS
new file mode 100644
index 0000000..0cc2a401
--- /dev/null
+++ b/chrome/browser/ui/frame/OWNERS
@@ -0,0 +1,6 @@
+bsep@chromium.org
+pkasting@chromium.org
+sky@chromium.org
+rameier@chromium.org
+
+# COMPONENT: UI>Browser
diff --git a/chrome/browser/ui/frame/window_frame_util.cc b/chrome/browser/ui/frame/window_frame_util.cc
new file mode 100644
index 0000000..d50ad176
--- /dev/null
+++ b/chrome/browser/ui/frame/window_frame_util.cc
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/frame/window_frame_util.h"
+
+#include "ui/gfx/geometry/size.h"
+
+// static
+SkAlpha WindowFrameUtil::CalculateWindows10GlassCaptionButtonBackgroundAlpha(
+    SkAlpha theme_alpha) {
+  return theme_alpha == SK_AlphaOPAQUE ? 0xCC : theme_alpha;
+}
+
+// static
+gfx::Size WindowFrameUtil::GetWindows10GlassCaptionButtonAreaSize() {
+  constexpr int kNumButtons = 3;
+
+  return gfx::Size(
+      (kNumButtons * kWindows10GlassCaptionButtonWidth) +
+          ((kNumButtons - 1) * kWindows10GlassCaptionButtonVisualSpacing),
+      kWindows10GlassCaptionButtonHeightRestored);
+}
diff --git a/chrome/browser/ui/frame/window_frame_util.h b/chrome/browser/ui/frame/window_frame_util.h
new file mode 100644
index 0000000..954e7394
--- /dev/null
+++ b/chrome/browser/ui/frame/window_frame_util.h
@@ -0,0 +1,38 @@
+// 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_FRAME_WINDOW_FRAME_UTIL_H_
+#define CHROME_BROWSER_UI_FRAME_WINDOW_FRAME_UTIL_H_
+
+#include "base/macros.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace gfx {
+class Size;
+}
+
+// Static-only class containing values and helper functions for frame classes
+// that need to be accessible outside of /browser/ui/views.
+class WindowFrameUtil {
+ public:
+  static constexpr int kWindows10GlassCaptionButtonWidth = 45;
+  static constexpr int kWindows10GlassCaptionButtonHeightRestored = 29;
+  static constexpr int kWindows10GlassCaptionButtonVisualSpacing = 1;
+
+  // Returns the alpha that the Windows10CaptionButton should use to blend the
+  // color provided by the theme in determining the button's 'base color'.
+  static SkAlpha CalculateWindows10GlassCaptionButtonBackgroundAlpha(
+      SkAlpha theme_alpha);
+
+  // Returns the size of the area occupied by the caption buttons in the glass
+  // browser frame view.
+  static gfx::Size GetWindows10GlassCaptionButtonAreaSize();
+
+ private:
+  WindowFrameUtil() {}
+
+  DISALLOW_COPY_AND_ASSIGN(WindowFrameUtil);
+};
+
+#endif  // CHROME_BROWSER_UI_FRAME_WINDOW_FRAME_UTIL_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
index 868d28e..318ede5e 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -70,20 +69,11 @@
         "www.google.com/search?q=tractor+supply",
         "google.com/search?q=tractor+supply",
     },
-#if defined(OS_ANDROID)
-    {
-        GURL("https://m.google.ca/search?q=tractor+supply"),
-        "https://m.google.ca/search?q=tractor+supply",
-        "google.ca/search?q=tractor+supply",
-    },
-#else  // !defined(OS_ANDROID)
-    // 'm' is not elided on Desktop.
     {
         GURL("https://m.google.ca/search?q=tractor+supply"),
         "https://m.google.ca/search?q=tractor+supply",
         "m.google.ca/search?q=tractor+supply",
     },
-#endif
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index b8662398..e884240 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #include "chrome/browser/ui/autofill/autofill_popup_layout_model.h"
 #include "chrome/browser/ui/autofill/popup_view_common.h"
+#include "chrome/browser/ui/views/autofill/view_util.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/chrome_typography_provider.h"
@@ -448,21 +449,21 @@
       popup_view_->controller()->GetElidedValueAt(line_number_);
   if (popup_view_->controller()
           ->GetSuggestionAt(line_number_)
-          .is_value_secondary)
+          .is_value_secondary) {
     return CreateSecondaryLabel(text);
+  }
 
-  gfx::FontList font_list = views::style::GetFont(
-      ChromeTextContext::CONTEXT_BODY_TEXT_LARGE, GetPrimaryTextStyle());
-  gfx::Font::Weight font_weight;
-  views::Label* text_label = new views::Label(
+  views::Label* text_label = CreateLabelWithColorReadabilityDisabled(
       popup_view_->controller()->GetElidedValueAt(line_number_),
-      {ShouldUseCustomFontWeightForPrimaryInfo(&font_weight)
-           ? font_list.DeriveWithWeight(font_weight)
-           : font_list});
-  text_label->SetEnabledColor(
-      views::style::GetColor(*this, ChromeTextContext::CONTEXT_BODY_TEXT_LARGE,
-                             GetPrimaryTextStyle()));
+      ChromeTextContext::CONTEXT_BODY_TEXT_LARGE, GetPrimaryTextStyle());
+
+  gfx::Font::Weight font_weight;
+  if (ShouldUseCustomFontWeightForPrimaryInfo(&font_weight)) {
+    text_label->SetFontList(
+        text_label->font_list().DeriveWithWeight(font_weight));
+  }
   text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+
   return text_label;
 }
 
@@ -478,12 +479,9 @@
 
 views::Label* AutofillPopupItemView::CreateSecondaryLabel(
     const base::string16& text) const {
-  views::Label* subtext_label = new views::Label(
-      text, {views::style::GetFont(ChromeTextContext::CONTEXT_BODY_TEXT_LARGE,
-                                   ChromeTextStyle::STYLE_SECONDARY)});
-  subtext_label->SetEnabledColor(
-      views::style::GetColor(*this, ChromeTextContext::CONTEXT_BODY_TEXT_LARGE,
-                             ChromeTextStyle::STYLE_SECONDARY));
+  views::Label* subtext_label = CreateLabelWithColorReadabilityDisabled(
+      text, ChromeTextContext::CONTEXT_BODY_TEXT_LARGE,
+      ChromeTextStyle::STYLE_SECONDARY);
   subtext_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
 
   return subtext_label;
@@ -719,10 +717,9 @@
   SetBorder(views::CreateEmptyBorder(
       gfx::Insets(vertical_margin, horizontal_margin)));
 
-  views::Label* text_label = new views::Label(
+  views::Label* text_label = CreateLabelWithColorReadabilityDisabled(
       controller->GetElidedValueAt(line_number_),
-      {views::style::GetFont(ChromeTextContext::CONTEXT_BODY_TEXT_LARGE,
-                             ChromeTextStyle::STYLE_RED)});
+      ChromeTextContext::CONTEXT_BODY_TEXT_LARGE, ChromeTextStyle::STYLE_RED);
   text_label->SetEnabledColor(AutofillPopupBaseView::kWarningColor);
   text_label->SetMultiLine(true);
   int max_width =
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
index 52389d2..e4e2bab 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
@@ -114,11 +114,10 @@
 }
 
 views::View* LocalCardMigrationDialogView::CreateExtraView() {
-  close_migration_dialog_button_.reset(
-      views::MdTextButton::CreateSecondaryUiButton(
-          this, l10n_util::GetStringUTF16(IDS_CLOSE)));
+  close_migration_dialog_button_ = views::MdTextButton::CreateSecondaryUiButton(
+      this, l10n_util::GetStringUTF16(IDS_CLOSE));
   close_migration_dialog_button_->SetVisible(false);
-  return close_migration_dialog_button_.get();
+  return close_migration_dialog_button_;
 }
 
 bool LocalCardMigrationDialogView::ShouldShowCloseButton() const {
@@ -171,7 +170,7 @@
                                                  const ui::Event& event) {
   // If button clicked is the |close_migration_dialog_button_|, close the
   // dialog.
-  if (sender == close_migration_dialog_button_.get()) {
+  if (sender == close_migration_dialog_button_) {
     CloseDialog();
   } else {
     // Checkbox is clicked.
@@ -199,27 +198,26 @@
 
   // Set up main contents container.
   std::unique_ptr<views::View> main_container = std::make_unique<views::View>();
-  constexpr int kMigrationDialogUnrelatedControlVerticalDistance = 24;
+  constexpr int kMainContainerChildSpacing = 24;
   main_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::kVertical, gfx::Insets(),
-      kMigrationDialogUnrelatedControlVerticalDistance));
+      views::BoxLayout::kVertical, gfx::Insets(), kMainContainerChildSpacing));
 
   std::unique_ptr<views::View> image_container =
       std::make_unique<views::View>();
   image_container->SetLayoutManager(
       std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
-  constexpr int kMigrationDialogImageBorderBottom = 16;
+  constexpr int kImageBorderBottom = 16;
   image_container->SetBorder(
-      views::CreateEmptyBorder(0, 0, kMigrationDialogImageBorderBottom, 0));
+      views::CreateEmptyBorder(0, 0, kImageBorderBottom, 0));
   std::unique_ptr<views::ImageView> image =
       std::make_unique<views::ImageView>();
   image->SetImage(rb.GetImageSkiaNamed(GetHeaderImageId()));
   image_container->AddChildView(image.release());
   main_container->AddChildView(image_container.release());
 
-  title_ = std::make_unique<views::Label>(GetDialogTitle(),
-                                          views::style::CONTEXT_DIALOG_TITLE);
-  main_container->AddChildView(title_.get());
+  title_ =
+      new views::Label(GetDialogTitle(), views::style::CONTEXT_DIALOG_TITLE);
+  main_container->AddChildView(title_);
 
   std::unique_ptr<views::View> contents_container =
       std::make_unique<views::View>();
@@ -231,14 +229,14 @@
   contents_container->SetBorder(
       views::CreateEmptyBorder(migration_dialog_insets));
 
-  explanation_text_ = std::make_unique<views::Label>(
-      GetDialogInstruction(), CONTEXT_BODY_TEXT_LARGE,
-      ChromeTextStyle::STYLE_SECONDARY);
+  explanation_text_ =
+      new views::Label(GetDialogInstruction(), CONTEXT_BODY_TEXT_LARGE,
+                       ChromeTextStyle::STYLE_SECONDARY);
   explanation_text_->SetMultiLine(true);
   explanation_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  contents_container->AddChildView(explanation_text_.get());
+  contents_container->AddChildView(explanation_text_);
 
-  card_list_view_ = std::make_unique<views::View>();
+  card_list_view_ = new views::View();
   const std::vector<MigratableCreditCard>& migratable_credit_cards =
       controller_->GetCardList();
   views::BoxLayout* card_list_view_layout_ =
@@ -249,33 +247,30 @@
   card_list_view_layout_->set_main_axis_alignment(
       views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
   for (size_t index = 0; index < migratable_credit_cards.size(); index++) {
-    card_list_view_->AddChildView(
-        std::make_unique<MigratableCardView>(migratable_credit_cards[index],
-                                             this, static_cast<int>(index))
-            .release());
+    card_list_view_->AddChildView(new MigratableCardView(
+        migratable_credit_cards[index], this, static_cast<int>(index)));
   }
 
   std::unique_ptr<views::ScrollView> card_list_scroll_bar =
       std::make_unique<views::ScrollView>();
   card_list_scroll_bar->set_hide_horizontal_scrollbar(true);
-  card_list_scroll_bar->SetContents(card_list_view_.get());
+  card_list_scroll_bar->SetContents(card_list_view_);
   card_list_scroll_bar->set_draw_overflow_indicator(false);
   constexpr int kCardListScrollViewHeight = 140;
   card_list_scroll_bar->ClipHeightTo(0, kCardListScrollViewHeight);
   contents_container->AddChildView(card_list_scroll_bar.release());
   main_container->AddChildView(contents_container.release());
 
-  separator_ = std::make_unique<views::Separator>();
-  main_container->AddChildView(separator_.get());
+  separator_ = new views::Separator();
+  main_container->AddChildView(separator_);
 
-  legal_message_container_ = std::make_unique<LegalMessageView>(
-      controller_->GetLegalMessageLines(), this);
-  constexpr int kMigrationDialogContentMarginBottomText = 48;
-  legal_message_container_->SetBorder(
-      views::CreateEmptyBorder(0, migration_dialog_insets.left(),
-                               kMigrationDialogContentMarginBottomText,
-                               migration_dialog_insets.right()));
-  main_container->AddChildView(legal_message_container_.get());
+  legal_message_container_ =
+      new LegalMessageView(controller_->GetLegalMessageLines(), this);
+  constexpr int kContentBottomMargin = 48;
+  legal_message_container_->SetBorder(views::CreateEmptyBorder(
+      0, migration_dialog_insets.left(), kContentBottomMargin,
+      migration_dialog_insets.right()));
+  main_container->AddChildView(legal_message_container_);
 
   AddChildView(main_container.release());
 }
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
index 13d4f52..aa57b56 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
+++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
@@ -84,27 +84,29 @@
 
   content::WebContents* web_contents_;
 
-  std::unique_ptr<views::Label> title_;
+  views::Label* title_ = nullptr;
 
-  std::unique_ptr<views::Label> explanation_text_;
+  views::Label* explanation_text_ = nullptr;
 
   // A list of MigratableCardView.
-  std::unique_ptr<views::View> card_list_view_;
+  views::View* card_list_view_ = nullptr;
 
   // Separates the card scroll bar view and the legal message.
-  std::unique_ptr<views::Separator> separator_;
+  views::Separator* separator_ = nullptr;
 
   // The button displays "Close". If clicked, will close the dialog
   // in pending state.
-  std::unique_ptr<views::View> close_migration_dialog_button_;
+  views::View* close_migration_dialog_button_ = nullptr;
+
+  // The view that contains legal message and handles legal message links
+  // clicking.
+  LegalMessageView* legal_message_container_ = nullptr;
 
   // Timer that will call ShowCloseButton() after the migration process
   // has started and is pending for acertain amount of time which can be
   // configured through Finch.
   base::OneShotTimer show_close_button_timer_;
 
-  std::unique_ptr<LegalMessageView> legal_message_container_;
-
   // Whether the uploading is in progress and results are
   // pending.
   bool migration_pending_ = false;
diff --git a/chrome/browser/ui/views/autofill/view_util.cc b/chrome/browser/ui/views/autofill/view_util.cc
index 2afec20a..fce5c7cf 100644
--- a/chrome/browser/ui/views/autofill/view_util.cc
+++ b/chrome/browser/ui/views/autofill/view_util.cc
@@ -117,6 +117,20 @@
   return textfield;
 }
 
+views::Label* CreateLabelWithColorReadabilityDisabled(
+    const base::string16& text,
+    int text_context,
+    int text_style) {
+  views::Label* label = new views::Label(text, text_context, text_style);
+  label->SetAutoColorReadabilityEnabled(false);
+  // Forces the color for the required context and style to be applied. It may
+  // have been overridden by the default theme's color before auto-color
+  // readability was disabled.
+  label->SetEnabledColor(
+      views::style::GetColor(*label, text_context, text_style));
+  return label;
+}
+
 LegalMessageView::LegalMessageView(const LegalMessageLines& legal_message_lines,
                                    views::StyledLabelListener* listener)
     : legal_message_lines_(legal_message_lines) {
@@ -133,8 +147,8 @@
 LegalMessageView::CreateLegalMessageLineLabel(
     const LegalMessageLine& line,
     views::StyledLabelListener* listener) {
-  std::unique_ptr<views::StyledLabel> label(
-      new views::StyledLabel(line.text(), listener));
+  std::unique_ptr<views::StyledLabel> label =
+      std::make_unique<views::StyledLabel>(line.text(), listener);
   label->SetTextContext(CONTEXT_BODY_TEXT_LARGE);
   label->SetDefaultTextStyle(ChromeTextStyle::STYLE_SECONDARY);
   for (const LegalMessageLine::Link& link : line.links()) {
diff --git a/chrome/browser/ui/views/autofill/view_util.h b/chrome/browser/ui/views/autofill/view_util.h
index be21bd1..25fe675 100644
--- a/chrome/browser/ui/views/autofill/view_util.h
+++ b/chrome/browser/ui/views/autofill/view_util.h
@@ -8,10 +8,13 @@
 #include "base/strings/string16.h"
 #include "components/autofill/core/browser/legal_message_line.h"
 #include "content/public/browser/web_contents.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/view.h"
 
 namespace views {
+class Label;
 class StyledLabel;
 class Textfield;
 }  // namespace views
@@ -34,6 +37,14 @@
 // Creates and returns a small Textfield intended to be used for CVC entry.
 views::Textfield* CreateCvcTextfield();
 
+// Returns a new label with auto-color readability disabled to ensure consistent
+// colors in the title when a dark native theme is applied
+// (https://crbug.com/881514).
+views::Label* CreateLabelWithColorReadabilityDisabled(
+    const base::string16& text,
+    int text_context,
+    int text_style);
+
 // Defines a view with legal message. This class handles the legal message
 // parsing and the links clicking events.
 class LegalMessageView : public views::View {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 8fc3a87..ecd4f6e6 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -162,6 +162,7 @@
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/window_properties.h"
 #include "chrome/browser/ui/views/location_bar/intent_picker_view.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
 #else
 #include "chrome/browser/ui/signin_view_controller.h"
 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
@@ -1929,7 +1930,7 @@
 #if defined(OS_CHROMEOS)
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   if (browser_->is_type_tabbed()) {
-    return rb.GetImageNamed(IDR_PRODUCT_LOGO_32).AsImageSkia();
+    return rb.GetImageNamed(IDR_CHROME_APP_ICON_192).AsImageSkia();
   }
   auto* window = GetNativeWindow();
   int override_window_icon_resource_id =
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 35f74469..a872014 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -34,9 +34,12 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/path.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/resources/grit/views_resources.h"
@@ -59,6 +62,50 @@
 
 constexpr SkColor kTitleBarFeatureColor = SK_ColorWHITE;
 
+class CaptionButtonBackgroundImageSource : public gfx::CanvasImageSource {
+ public:
+  CaptionButtonBackgroundImageSource(const gfx::ImageSkia& bg_image,
+                                     int source_x,
+                                     int source_y,
+                                     int dest_width,
+                                     int dest_height,
+                                     bool draw_mirrored)
+      : gfx::CanvasImageSource(
+            bg_image.isNull() ? gfx::Size(1, 1) : bg_image.size(),
+            false),
+        bg_image_(bg_image),
+        source_x_(source_x),
+        source_y_(source_y),
+        dest_width_(dest_width),
+        dest_height_(dest_height),
+        draw_mirrored_(draw_mirrored) {}
+
+  ~CaptionButtonBackgroundImageSource() override = default;
+
+  void Draw(gfx::Canvas* canvas) override {
+    if (bg_image_.isNull())
+      return;
+
+    gfx::ScopedCanvas scoped_canvas(canvas);
+
+    if (draw_mirrored_) {
+      canvas->Translate(gfx::Vector2d(dest_width_, 0));
+      canvas->Scale(-1, 1);
+    }
+
+    canvas->TileImageInt(bg_image_, source_x_, source_y_, 0, 0, dest_width_,
+                         dest_height_);
+  }
+
+ private:
+  const gfx::ImageSkia bg_image_;
+  int source_x_, source_y_;
+  int dest_width_, dest_height_;
+  bool draw_mirrored_;
+
+  DISALLOW_COPY_AND_ASSIGN(CaptionButtonBackgroundImageSource);
+};
+
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -577,18 +624,84 @@
   button->SetImage(views::Button::STATE_PRESSED,
                    tp->GetImageSkiaNamed(pushed_image_id));
   if (browser_view()->IsBrowserTypeNormal()) {
+    // Get a custom processed version of the theme's background image so that it
+    // appears to draw contiguously across all of the caption buttons.
+    const gfx::Size normal_image_size = GetThemeImageSize(normal_image_id);
+    const gfx::ImageSkia processed_bg_image =
+        GetProcessedBackgroundImageForCaptionButon(view_id, normal_image_size);
+
+    // SetBackgroundImage immediately uses the provided ImageSkia pointer
+    // (&processed_bg_image) to create a local copy, so it's safe for this to be
+    // locally scoped.
     button->SetBackgroundImage(
         tp->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND),
-        tp->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND),
+        (processed_bg_image.isNull() ? nullptr : &processed_bg_image),
         tp->GetImageSkiaNamed(mask_image_id));
   }
-  button->SetAccessibleName(
-      l10n_util::GetStringUTF16(accessibility_string_id));
+  button->SetAccessibleName(l10n_util::GetStringUTF16(accessibility_string_id));
   button->set_id(view_id);
   AddChildView(button);
   return button;
 }
 
+gfx::Size OpaqueBrowserFrameView::GetThemeImageSize(int image_id) {
+  const ui::ThemeProvider* tp = frame()->GetThemeProvider();
+  const gfx::ImageSkia* image = tp->GetImageSkiaNamed(image_id);
+
+  return (image ? image->size() : gfx::Size());
+}
+
+int OpaqueBrowserFrameView::CalculateCaptionButtonBackgroundXOffset(
+    ViewID view_id) {
+  const int minimize_width = GetThemeImageSize(IDR_MINIMIZE).width();
+  const int maximize_restore_width = GetThemeImageSize(IDR_MAXIMIZE).width();
+  const int close_width = GetThemeImageSize(IDR_CLOSE).width();
+
+  const bool is_rtl = base::i18n::IsRTL();
+
+  switch (view_id) {
+    case VIEW_ID_MINIMIZE_BUTTON:
+      return (is_rtl ? close_width + maximize_restore_width : 0);
+    case VIEW_ID_MAXIMIZE_BUTTON:
+    case VIEW_ID_RESTORE_BUTTON:
+      return (is_rtl ? close_width : minimize_width);
+    case VIEW_ID_CLOSE_BUTTON:
+      return (is_rtl ? 0 : minimize_width + maximize_restore_width);
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+gfx::ImageSkia
+OpaqueBrowserFrameView::GetProcessedBackgroundImageForCaptionButon(
+    ViewID view_id,
+    const gfx::Size& desired_size) {
+  // We want the background image to tile contiguously across all of the
+  // caption buttons, so we need to draw a subset of the background image,
+  // with source offsets based on where this button is located relative to the
+  // other caption buttons.  We also have to account for the image mirroring
+  // that happens in RTL mode.  This is accomplished using a custom
+  // ImageSource (defined at the top of the file).
+
+  const ui::ThemeProvider* tp = frame()->GetThemeProvider();
+  const gfx::ImageSkia* bg_image =
+      tp->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND);
+
+  if (!bg_image)
+    return gfx::ImageSkia();
+
+  const bool is_rtl = base::i18n::IsRTL();
+  const int bg_x_offset = CalculateCaptionButtonBackgroundXOffset(view_id);
+  const int bg_y_offset = 0;
+  std::unique_ptr<CaptionButtonBackgroundImageSource> source =
+      std::make_unique<CaptionButtonBackgroundImageSource>(
+          *bg_image, bg_x_offset, bg_y_offset, desired_size.width(),
+          desired_size.height(), is_rtl);
+
+  return gfx::ImageSkia(std::move(source), desired_size);
+}
+
 int OpaqueBrowserFrameView::FrameBorderThickness(bool restored) const {
   return layout_->FrameBorderThickness(restored);
 }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
index bcabf1951..cb3b8d8 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -138,6 +138,24 @@
                                               int accessibility_string_id,
                                               ViewID view_id);
 
+  // Returns the size of the custom image specified by |image_id| in the frame's
+  // ThemeProvider.
+  gfx::Size GetThemeImageSize(int image_id);
+
+  // Returns the amount by which the background image of a caption button
+  // (specified by |view_id|) should be offset on the X-axis.
+  int CalculateCaptionButtonBackgroundXOffset(ViewID view_id);
+
+  // Returns an image to be used as the background image for the caption button
+  // specified by |view_id|.  The returned image is based on the control button
+  // background image specified by the current theme, and processed to handle
+  // size, source offset, tiling, and mirroring for the specified caption
+  // button.  This is done to provide the effect that the background image
+  // appears to draw contiguously across all 3 caption buttons.
+  gfx::ImageSkia GetProcessedBackgroundImageForCaptionButon(
+      ViewID view_id,
+      const gfx::Size& desired_size);
+
   // Returns the thickness of the border that makes up the window frame edges.
   // This does not include any client edge.  If |restored| is true, this is
   // calculated as if the window was restored, regardless of its current
diff --git a/chrome/browser/ui/views/frame/windows_10_caption_button.cc b/chrome/browser/ui/views/frame/windows_10_caption_button.cc
index 45a3a5a..6dff965 100644
--- a/chrome/browser/ui/views/frame/windows_10_caption_button.cc
+++ b/chrome/browser/ui/views/frame/windows_10_caption_button.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/windows_10_caption_button.h"
 
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/frame/window_frame_util.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h"
 #include "chrome/grit/theme_resources.h"
@@ -25,18 +26,10 @@
   SetAccessibleName(accessible_name);
 }
 
-int Windows10CaptionButton::GetBetweenButtonSpacing() const {
-  constexpr int kCaptionButtonVisualSpacing = 1;
-  const ViewID leftmost_button =
-      base::i18n::IsRTL() ? VIEW_ID_CLOSE_BUTTON : VIEW_ID_MINIMIZE_BUTTON;
-  return button_type_ == leftmost_button ? 0 : kCaptionButtonVisualSpacing;
-}
-
 gfx::Size Windows10CaptionButton::CalculatePreferredSize() const {
   // TODO(bsep): The sizes in this function are for 1x device scale and don't
   // match Windows button sizes at hidpi.
-  constexpr int kButtonHeightRestored = 29;
-  int height = kButtonHeightRestored;
+  int height = WindowFrameUtil::kWindows10GlassCaptionButtonHeightRestored;
   if (frame_view_->IsMaximized()) {
     int maximized_height =
         frame_view_->browser_view()->IsTabStripVisible()
@@ -46,27 +39,26 @@
     maximized_height -= kMaximizedBottomMargin;
     height = std::min(height, maximized_height);
   }
-  constexpr int kButtonWidth = 45;
-  return gfx::Size(kButtonWidth + GetBetweenButtonSpacing(), height);
-}
-
-namespace {
-SkAlpha ButtonBackgroundAlpha(SkAlpha theme_alpha) {
-  return theme_alpha == SK_AlphaOPAQUE ? 0xCC : theme_alpha;
-}
+  int base_width = WindowFrameUtil::kWindows10GlassCaptionButtonWidth;
+  return gfx::Size(base_width + GetBetweenButtonSpacing(), height);
 }
 
 SkColor Windows10CaptionButton::GetBaseColor() const {
-  const SkColor titlebar_color = frame_view_->GetTitlebarColor();
+  // Get the theme's calculated custom control button background color
+  // (as it takes into account images, etc).  If none is specified (likely when
+  // there is no theme active), fall back to the titlebar color.
+  const int control_button_bg_color_id =
+      (frame_view_->ShouldPaintAsActive()
+           ? ThemeProperties::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE
+           : ThemeProperties::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE);
+  const ui::ThemeProvider* theme_provider = GetThemeProvider();
+  const bool has_custom_color =
+      theme_provider->HasCustomColor(control_button_bg_color_id);
   const SkColor bg_color =
-      GetThemeProvider()->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND);
-  const SkAlpha theme_alpha = SkColorGetA(bg_color);
-  const SkColor blend_color =
-      theme_alpha > 0 ? color_utils::AlphaBlend(
-                            SkColorSetA(bg_color, SK_AlphaOPAQUE),
-                            titlebar_color, ButtonBackgroundAlpha(theme_alpha))
-                      : titlebar_color;
-  return GlassBrowserFrameView::GetReadableFeatureColor(blend_color);
+      (has_custom_color ? theme_provider->GetColor(control_button_bg_color_id)
+                        : frame_view_->GetTitlebarColor());
+
+  return GlassBrowserFrameView::GetReadableFeatureColor(bg_color);
 }
 
 void Windows10CaptionButton::OnPaintBackground(gfx::Canvas* canvas) {
@@ -80,13 +72,27 @@
   bounds.Inset(GetBetweenButtonSpacing(), 0, 0, 0);
 
   if (theme_alpha > 0) {
-    canvas->FillRect(bounds,
-                     SkColorSetA(bg_color, ButtonBackgroundAlpha(theme_alpha)));
+    canvas->FillRect(
+        bounds,
+        SkColorSetA(bg_color,
+                    WindowFrameUtil::
+                        CalculateWindows10GlassCaptionButtonBackgroundAlpha(
+                            theme_alpha)));
   }
   if (theme_provider->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND)) {
+    // Figure out what portion of the background image to display
+    const int button_display_order = GetButtonDisplayOrderIndex();
+    const int base_button_width =
+        WindowFrameUtil::kWindows10GlassCaptionButtonWidth;
+    const int base_visual_spacing =
+        WindowFrameUtil::kWindows10GlassCaptionButtonVisualSpacing;
+    const int src_x =
+        button_display_order * (base_button_width + base_visual_spacing);
+    const int src_y = 0;
+
     canvas->TileImageInt(
         *theme_provider->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND),
-        bounds.x(), bounds.y(), bounds.width(), bounds.height());
+        src_x, src_y, bounds.x(), bounds.y(), bounds.width(), bounds.height());
   }
 
   SkColor base_color;
@@ -123,6 +129,38 @@
   PaintSymbol(canvas);
 }
 
+int Windows10CaptionButton::GetBetweenButtonSpacing() const {
+  const int display_order_index = GetButtonDisplayOrderIndex();
+  return display_order_index == 0
+             ? 0
+             : WindowFrameUtil::kWindows10GlassCaptionButtonVisualSpacing;
+}
+
+int Windows10CaptionButton::GetButtonDisplayOrderIndex() const {
+  int button_display_order = 0;
+  switch (button_type_) {
+    case VIEW_ID_MINIMIZE_BUTTON:
+      button_display_order = 0;
+      break;
+    case VIEW_ID_MAXIMIZE_BUTTON:
+    case VIEW_ID_RESTORE_BUTTON:
+      button_display_order = 1;
+      break;
+    case VIEW_ID_CLOSE_BUTTON:
+      button_display_order = 2;
+      break;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+
+  // Reverse the ordering if we're in RTL mode
+  if (base::i18n::IsRTL())
+    button_display_order = 2 - button_display_order;
+
+  return button_display_order;
+}
+
 namespace {
 
 // Canvas::DrawRect's stroke can bleed out of |rect|'s bounds, so this draws a
diff --git a/chrome/browser/ui/views/frame/windows_10_caption_button.h b/chrome/browser/ui/views/frame/windows_10_caption_button.h
index 8ef364f..ec5301d1 100644
--- a/chrome/browser/ui/views/frame/windows_10_caption_button.h
+++ b/chrome/browser/ui/views/frame/windows_10_caption_button.h
@@ -28,6 +28,11 @@
   // buttons to avoid the sliver of deadspace that would result.
   int GetBetweenButtonSpacing() const;
 
+  // Returns the order in which this button will be displayed (with 0 being
+  // drawn farthest to the left, and larger indices being drawn to the right of
+  // smaller indices).
+  int GetButtonDisplayOrderIndex() const;
+
   // The base color to use for the button symbols and background blending. Uses
   // the more readable of black and white.
   SkColor GetBaseColor() const;
diff --git a/chrome/browser/ui/views/media_router/media_router_views_ui.cc b/chrome/browser/ui/views/media_router/media_router_views_ui.cc
index a2c0177..34382a41 100644
--- a/chrome/browser/ui/views/media_router/media_router_views_ui.cc
+++ b/chrome/browser/ui/views/media_router/media_router_views_ui.cc
@@ -19,12 +19,21 @@
 namespace {
 
 // Returns true if |issue| is associated with |ui_sink|.
-bool IssueMatches(const Issue& issue, const UIMediaSink ui_sink) {
+bool IssueMatches(const Issue& issue, const UIMediaSink& ui_sink) {
   return issue.info().sink_id == ui_sink.id ||
          (!issue.info().route_id.empty() &&
           issue.info().route_id == ui_sink.route_id);
 }
 
+base::string16 GetSinkFriendlyName(const MediaSink& sink) {
+  // Use U+2010 (HYPHEN) instead of ASCII hyphen to avoid problems with RTL
+  // languages.
+  const char* separator = u8" \u2010 ";
+  return base::UTF8ToUTF16(sink.description() ? sink.name() + separator +
+                                                    sink.description().value()
+                                              : sink.name());
+}
+
 }  // namespace
 
 MediaRouterViewsUI::MediaRouterViewsUI() = default;
@@ -121,7 +130,7 @@
     const base::Optional<Issue>& issue) {
   UIMediaSink ui_sink;
   ui_sink.id = sink.sink.id();
-  ui_sink.friendly_name = base::UTF8ToUTF16(sink.sink.name());
+  ui_sink.friendly_name = GetSinkFriendlyName(sink.sink);
   ui_sink.icon_type = sink.sink.icon_type();
 
   if (route) {
diff --git a/chrome/browser/ui/views/media_router/media_router_views_ui.h b/chrome/browser/ui/views/media_router/media_router_views_ui.h
index 6d5c6a61..a9a8286 100644
--- a/chrome/browser/ui/views/media_router/media_router_views_ui.h
+++ b/chrome/browser/ui/views/media_router/media_router_views_ui.h
@@ -32,6 +32,7 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, NotifyObserver);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, SinkFriendlyName);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, RemovePseudoSink);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, ConnectingState);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, DisconnectingState);
diff --git a/chrome/browser/ui/views/media_router/media_router_views_ui_unittest.cc b/chrome/browser/ui/views/media_router/media_router_views_ui_unittest.cc
index 0635fbc..fe5fdecb 100644
--- a/chrome/browser/ui/views/media_router/media_router_views_ui_unittest.cc
+++ b/chrome/browser/ui/views/media_router/media_router_views_ui_unittest.cc
@@ -28,6 +28,7 @@
 
 constexpr char kPseudoSinkId[] = "pseudo:sink";
 constexpr char kRouteId[] = "route1";
+constexpr char kSinkDescription[] = "description";
 constexpr char kSinkId[] = "sink1";
 constexpr char kSinkName[] = "sink name";
 constexpr char kSourceId[] = "source1";
@@ -122,6 +123,24 @@
   ui_.reset();
 }
 
+TEST_F(MediaRouterViewsUITest, SinkFriendlyName) {
+  MockControllerObserver observer;
+  ui_->AddObserver(&observer);
+
+  MediaSink sink(kSinkId, kSinkName, SinkIconType::CAST);
+  sink.set_description(kSinkDescription);
+  MediaSinkWithCastModes sink_with_cast_modes(sink);
+  const char* separator = u8" \u2010 ";
+  EXPECT_CALL(observer, OnModelUpdated(_))
+      .WillOnce(Invoke([&](const CastDialogModel& model) {
+        EXPECT_EQ(base::UTF8ToUTF16(sink.name() + separator +
+                                    sink.description().value()),
+                  model.media_sinks()[0].friendly_name);
+      }));
+  ui_->OnResultsUpdated({sink_with_cast_modes});
+  ui_->RemoveObserver(&observer);
+}
+
 TEST_F(MediaRouterViewsUITest, StartCasting) {
   MediaSource media_source =
       MediaSourceForTab(SessionTabHelper::IdForTab(web_contents()).id());
diff --git a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
index d7c4a59..187774f 100644
--- a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
+++ b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
@@ -8,6 +8,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_controller.h"
+#include "chrome/browser/ui/views/autofill/view_util.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -51,15 +52,14 @@
     BuildColumnSet(layout);
     layout->StartRow(views::GridLayout::kFixedSize, 0);
 
-    views::Label* suggestion_label = new views::Label(
+    layout->AddView(autofill::CreateLabelWithColorReadabilityDisabled(
         suggestion, ChromeTextContext::CONTEXT_BODY_TEXT_LARGE,
         state == PasswordGenerationPopupController::kOfferGeneration
             ? views::style::STYLE_PRIMARY
-            : STYLE_SECONDARY);
-    layout->AddView(suggestion_label);
+            : STYLE_SECONDARY));
 
     DCHECK(!password_label_);
-    password_label_ = new views::Label(
+    password_label_ = autofill::CreateLabelWithColorReadabilityDisabled(
         password, ChromeTextContext::CONTEXT_BODY_TEXT_LARGE, STYLE_SECONDARY);
     layout->AddView(password_label_);
   }
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index f1ea308..42fed24 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -331,6 +331,15 @@
     force_new_tab = true;
   }
 
+  ProfileSyncService* service = GetSyncService();
+  if (service && service->HasUnrecoverableError()) {
+    // When the user has an unrecoverable error, they first have to sign out and
+    // then sign in again.
+    SigninManagerFactory::GetForProfile(browser->profile())
+        ->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS,
+                  signin_metrics::SignoutDelete::IGNORE_METRIC);
+  }
+
   // If the signin manager already has an authenticated username, this is a
   // re-auth scenario, and we need to ensure that the user signs in with the
   // same email address.
@@ -622,18 +631,14 @@
 
   ProfileSyncService* service = GetSyncService();
 
-  // Just let the page open for now, even when the user's not signed in or sync
-  // is disabled.
-  // TODO(scottchen): finish the UI for signed-out users
-  //    (https://crbug.com/800972).
   if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
     if (service && !sync_blocker_)
       sync_blocker_ = service->GetSetupInProgressHandle();
 
-    // Preemptively mark login UI as active, because the user could potentially
-    // sign-in directly from this UI without triggering handleShowSetupUI again.
     GetLoginUIService()->SetLoginUI(this);
-    FireWebUIListener("sync-prefs-changed", base::DictionaryValue());
+
+    PushSyncPrefs();
+    // Always let the page open when unified consent is enabled.
     return;
   }
 
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
index 8dfe388..2ab0b17 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
@@ -19,6 +19,7 @@
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "components/keep_alive_registry/scoped_keep_alive.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/views/bubble/bubble_border.h"
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_controller.h"
 #include "ui/views/view.h"
@@ -71,17 +72,25 @@
   // Chrome replies to Ash with the context menu items to display.
   ChromeLauncherController::instance()->FlushForTesting();
 
+  const views::MenuConfig& menu_config = views::MenuConfig::instance();
   // Move the cursor up to the "New window" menu option - assumes menu content.
-  const int offset =
+  const int y_offset =
       // Top half of the button we just clicked on.
       ash::ShelfConstants::button_size() / 2 +
       // Space between shelf top and menu bottom. Here we get this menu with
       // a right-click but long-pressing yields the same result. All menus
       // here use a touchable layout.
-      views::MenuConfig::instance().touchable_anchor_offset +
+      menu_config.touchable_anchor_offset +
       // 2 menu items we don't want, and go over part of the one we want.
-      2.2 * views::MenuConfig::instance().touchable_menu_height;
-  generator.MoveMouseBy(0, -offset);
+      2.2 * menu_config.touchable_menu_height;
+  const int x_offset =
+      // Skip over the left edge border inset.
+      views::BubbleBorder::GetBorderAndShadowInsets(
+          menu_config.touchable_menu_shadow_elevation)
+          .left() +
+      // Space between the left edge and the item content.
+      menu_config.item_horizontal_padding;
+  generator.MoveMouseBy(x_offset, -y_offset);
   generator.ReleaseRightButton();
 
   // Ash notifies Chrome's ShelfItemDelegate that the menu item was selected.
diff --git a/chrome/browser/usb/usb_browsertest.cc b/chrome/browser/usb/usb_browsertest.cc
index f09f46d..9682989 100644
--- a/chrome/browser/usb/usb_browsertest.cc
+++ b/chrome/browser/usb/usb_browsertest.cc
@@ -258,8 +258,6 @@
   EXPECT_EQ("123456", result);
 
   RemoveMockDevice();
-  base::RunLoop().RunUntilIdle();
-
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       web_contents,
       "if (deviceRemoved === null) {"
@@ -271,8 +269,6 @@
   EXPECT_EQ("123456", result);
 
   AddMockDevice("123456");
-  base::RunLoop().RunUntilIdle();
-
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       web_contents,
       "if (deviceAdded === null) {"
@@ -291,7 +287,6 @@
   // Replace the default mock device with one that has no serial number.
   RemoveMockDevice();
   AddMockDevice("");
-  base::RunLoop().RunUntilIdle();
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
@@ -309,8 +304,6 @@
   EXPECT_EQ("", result);
 
   RemoveMockDevice();
-  base::RunLoop().RunUntilIdle();
-
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       web_contents,
       "if (deviceRemoved === null) {"
diff --git a/chrome/browser/usb/usb_chooser_context.cc b/chrome/browser/usb/usb_chooser_context.cc
index 0474556..718fc737 100644
--- a/chrome/browser/usb/usb_chooser_context.cc
+++ b/chrome/browser/usb/usb_chooser_context.cc
@@ -12,7 +12,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/usb/usb_blocklist.h"
 #include "device/base/device_client.h"
 #include "device/usb/mojo/type_converters.h"
 #include "device/usb/public/mojom/device.mojom.h"
@@ -73,46 +72,19 @@
 
 }  // namespace
 
-UsbChooserContext::Observer::~Observer() = default;
-
-void UsbChooserContext::Observer::OnDeviceAdded(
-    device::mojom::UsbDeviceInfoPtr device_info) {}
-
-void UsbChooserContext::Observer::OnDeviceRemoved(
-    device::mojom::UsbDeviceInfoPtr device_info) {}
-
-void UsbChooserContext::Observer::OnDeviceManagerConnectionError() {}
-
 UsbChooserContext::UsbChooserContext(Profile* profile)
     : ChooserContextBase(profile,
                          CONTENT_SETTINGS_TYPE_USB_GUARD,
                          CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA),
       is_incognito_(profile->IsOffTheRecord()),
-      client_binding_(this),
-      weak_factory_(this) {}
-
-void UsbChooserContext::EnsureConnectionWithDeviceManager() {
-  if (device_manager_)
-    return;
-
-  // TODO(donna.wu@intel.com): Request UsbDeviceManagerPtr from DeviceService
-  // after moving //device/usb to //services/device.
-  device_manager_instance_ = device::usb::DeviceManagerImpl::Create(
-      mojo::MakeRequest(&device_manager_));
-  device_manager_.set_connection_error_handler(
-      base::BindOnce(&UsbChooserContext::OnDeviceManagerConnectionError,
-                     base::Unretained(this)));
-
-  // Listen for added/removed device events.
-  DCHECK(!client_binding_);
-  device::mojom::UsbDeviceManagerClientPtr client;
-  client_binding_.Bind(mojo::MakeRequest(&client));
-  device_manager_->SetClient(std::move(client));
+      observer_(this),
+      weak_factory_(this) {
+  usb_service_ = device::DeviceClient::Get()->GetUsbService();
+  if (usb_service_)
+    observer_.Add(usb_service_);
 }
 
-UsbChooserContext::~UsbChooserContext() {
-  OnDeviceManagerConnectionError();
-}
+UsbChooserContext::~UsbChooserContext() {}
 
 std::vector<std::unique_ptr<base::DictionaryValue>>
 UsbChooserContext::GetGrantedObjects(const GURL& requesting_origin,
@@ -206,9 +178,6 @@
     const GURL& requesting_origin,
     const GURL& embedding_origin,
     const device::mojom::UsbDeviceInfo& device_info) {
-  if (UsbBlocklist::Get().IsExcluded(device_info))
-    return false;
-
   if (!CanRequestObjectPermission(requesting_origin, embedding_origin))
     return false;
 
@@ -253,29 +222,6 @@
   return HasDevicePermission(requesting_origin, embedding_origin, *device_info);
 }
 
-void UsbChooserContext::GetDevices(
-    device::mojom::UsbDeviceManager::GetDevicesCallback callback) {
-  EnsureConnectionWithDeviceManager();
-  device_manager_->GetDevices(nullptr, std::move(callback));
-}
-
-void UsbChooserContext::GetDevice(
-    const std::string& guid,
-    device::mojom::UsbDeviceRequest device_request,
-    device::mojom::UsbDeviceClientPtr device_client) {
-  EnsureConnectionWithDeviceManager();
-  device_manager_->GetDevice(guid, std::move(device_request),
-                             std::move(device_client));
-}
-
-void UsbChooserContext::AddObserver(Observer* observer) {
-  observer_list_.AddObserver(observer);
-}
-
-void UsbChooserContext::RemoveObserver(Observer* observer) {
-  observer_list_.RemoveObserver(observer);
-}
-
 base::WeakPtr<UsbChooserContext> UsbChooserContext::AsWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
@@ -295,41 +241,10 @@
   return name;
 }
 
-void UsbChooserContext::OnDeviceAdded(
-    device::mojom::UsbDeviceInfoPtr device_info) {
-  DCHECK(device_info);
-
-  // Notify all observers.
-  for (auto& observer : observer_list_)
-    observer.OnDeviceAdded(device_info->Clone());
-}
-
-void UsbChooserContext::OnDeviceRemoved(
-    device::mojom::UsbDeviceInfoPtr device_info) {
-  DCHECK(device_info);
-
-  // Notify all observers.
-  for (auto& observer : observer_list_)
-    observer.OnDeviceRemoved(device_info->Clone());
-
+void UsbChooserContext::OnDeviceRemovedCleanup(
+    scoped_refptr<UsbDevice> device) {
   for (auto& map_entry : ephemeral_devices_)
-    map_entry.second.erase(device_info->guid);
+    map_entry.second.erase(device->guid());
 
-  ephemeral_dicts_.erase(device_info->guid);
-}
-
-void UsbChooserContext::OnDeviceManagerConnectionError() {
-  device_manager_.reset();
-  client_binding_.Close();
-
-  // Notify all observers.
-  for (auto& observer : observer_list_)
-    observer.OnDeviceManagerConnectionError();
-
-  ephemeral_devices_.clear();
-  ephemeral_dicts_.clear();
-}
-
-void UsbChooserContext::DestroyDeviceManagerForTesting() {
-  device_manager_instance_.reset();
+  ephemeral_dicts_.erase(device->guid());
 }
diff --git a/chrome/browser/usb/usb_chooser_context.h b/chrome/browser/usb/usb_chooser_context.h
index af785e6..355ce85 100644
--- a/chrome/browser/usb/usb_chooser_context.h
+++ b/chrome/browser/usb/usb_chooser_context.h
@@ -13,12 +13,10 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/observer_list.h"
+#include "base/scoped_observer.h"
 #include "base/values.h"
 #include "chrome/browser/permissions/chooser_context_base.h"
-#include "device/usb/mojo/device_manager_impl.h"
-#include "device/usb/public/mojom/device_manager.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "device/usb/usb_service.h"
 
 namespace device {
 class UsbDevice;
@@ -29,19 +27,11 @@
 }
 
 class UsbChooserContext : public ChooserContextBase,
-                          public device::mojom::UsbDeviceManagerClient {
+                          public device::UsbService::Observer {
  public:
   explicit UsbChooserContext(Profile* profile);
   ~UsbChooserContext() override;
 
-  class Observer {
-   public:
-    virtual ~Observer();
-    virtual void OnDeviceAdded(device::mojom::UsbDeviceInfoPtr);
-    virtual void OnDeviceRemoved(device::mojom::UsbDeviceInfoPtr);
-    virtual void OnDeviceManagerConnectionError();
-  };
-
   // These methods from ChooserContextBase are overridden in order to expose
   // ephemeral devices through the public interface.
   std::vector<std::unique_ptr<base::DictionaryValue>> GetGrantedObjects(
@@ -68,44 +58,21 @@
                            const GURL& embedding_origin,
                            scoped_refptr<const device::UsbDevice> device);
 
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-
-  // Forward UsbDeviceManager methods.
-  void GetDevices(device::mojom::UsbDeviceManager::GetDevicesCallback callback);
-  void GetDevice(const std::string& guid,
-                 device::mojom::UsbDeviceRequest device_request,
-                 device::mojom::UsbDeviceClientPtr device_client);
-
   base::WeakPtr<UsbChooserContext> AsWeakPtr();
 
-  void DestroyDeviceManagerForTesting();
-
  private:
   // ChooserContextBase implementation.
   bool IsValidObject(const base::DictionaryValue& object) override;
   std::string GetObjectName(const base::DictionaryValue& object) override;
 
-  // device::mojom::UsbDeviceManagerClient implementation.
-  void OnDeviceAdded(device::mojom::UsbDeviceInfoPtr device_info) override;
-  void OnDeviceRemoved(device::mojom::UsbDeviceInfoPtr device_info) override;
-
-  void OnDeviceManagerConnectionError();
-  void EnsureConnectionWithDeviceManager();
+  // device::UsbService::Observer implementation.
+  void OnDeviceRemovedCleanup(scoped_refptr<device::UsbDevice> device) override;
 
   bool is_incognito_;
   std::map<std::pair<GURL, GURL>, std::set<std::string>> ephemeral_devices_;
+  device::UsbService* usb_service_;
   std::map<std::string, base::DictionaryValue> ephemeral_dicts_;
-
-  // TODO(donna.wu@intel.com): Have the Device Service own this instance in the
-  // near future.
-  std::unique_ptr<device::usb::DeviceManagerImpl> device_manager_instance_;
-
-  // Used to bind with UsbDeviceManager.
-  device::mojom::UsbDeviceManagerPtr device_manager_;
-  mojo::Binding<device::mojom::UsbDeviceManagerClient> client_binding_;
-  base::ObserverList<Observer, true>::Unchecked observer_list_;
-
+  ScopedObserver<device::UsbService, device::UsbService::Observer> observer_;
   base::WeakPtrFactory<UsbChooserContext> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UsbChooserContext);
diff --git a/chrome/browser/usb/usb_chooser_context_unittest.cc b/chrome/browser/usb/usb_chooser_context_unittest.cc
index 20930b6..cc493cc 100644
--- a/chrome/browser/usb/usb_chooser_context_unittest.cc
+++ b/chrome/browser/usb/usb_chooser_context_unittest.cc
@@ -4,7 +4,6 @@
 
 #include <vector>
 
-#include "base/run_loop.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
@@ -20,8 +19,6 @@
 using device::MockUsbDevice;
 using device::UsbDevice;
 
-namespace {
-
 class UsbChooserContextTest : public testing::Test {
  public:
   UsbChooserContextTest() {}
@@ -37,20 +34,6 @@
   TestingProfile profile_;
 };
 
-void ExpectDevicesAndThen(
-    const std::set<std::string>& expected_guids,
-    base::OnceClosure continuation,
-    std::vector<device::mojom::UsbDeviceInfoPtr> results) {
-  EXPECT_EQ(expected_guids.size(), results.size());
-  std::set<std::string> actual_guids;
-  for (size_t i = 0; i < results.size(); ++i)
-    actual_guids.insert(results[i]->guid);
-  EXPECT_EQ(expected_guids, actual_guids);
-  std::move(continuation).Run();
-}
-
-}  // namespace
-
 TEST_F(UsbChooserContextTest, CheckGrantAndRevokePermission) {
   GURL origin("https://www.google.com");
   scoped_refptr<UsbDevice> device =
@@ -140,16 +123,6 @@
 
   device_client_.usb_service()->AddDevice(device);
   UsbChooserContext* store = UsbChooserContextFactory::GetForProfile(profile());
-  {
-    // Call GetDevices once to make sure the connection with DeviceManager has
-    // been set up, so that it can be notified when device is removed.
-    std::set<std::string> guids;
-    guids.insert(device->guid());
-    base::RunLoop loop;
-    store->GetDevices(
-        base::BindOnce(&ExpectDevicesAndThen, guids, loop.QuitClosure()));
-    loop.Run();
-  }
 
   EXPECT_FALSE(store->HasDevicePermission(origin, origin, *device_info));
   store->GrantDevicePermission(origin, origin, *device_info);
@@ -162,8 +135,6 @@
   EXPECT_EQ(1u, all_origin_objects.size());
 
   device_client_.usb_service()->RemoveDevice(device);
-  base::RunLoop().RunUntilIdle();
-
   EXPECT_TRUE(store->HasDevicePermission(origin, origin, *device_info));
   objects = store->GetGrantedObjects(origin, origin);
   EXPECT_EQ(1u, objects.size());
@@ -194,16 +165,6 @@
 
   device_client_.usb_service()->AddDevice(device);
   UsbChooserContext* store = UsbChooserContextFactory::GetForProfile(profile());
-  {
-    // Call GetDevices once to make sure the connection with DeviceManager has
-    // been set up, so that it can be notified when device is removed.
-    std::set<std::string> guids;
-    guids.insert(device->guid());
-    base::RunLoop loop;
-    store->GetDevices(
-        base::BindOnce(&ExpectDevicesAndThen, guids, loop.QuitClosure()));
-    loop.Run();
-  }
 
   EXPECT_FALSE(store->HasDevicePermission(origin, origin, *device_info));
   store->GrantDevicePermission(origin, origin, *device_info);
@@ -216,8 +177,6 @@
   EXPECT_EQ(1u, all_origin_objects.size());
 
   device_client_.usb_service()->RemoveDevice(device);
-  base::RunLoop().RunUntilIdle();
-
   EXPECT_FALSE(store->HasDevicePermission(origin, origin, *device_info));
   objects = store->GetGrantedObjects(origin, origin);
   EXPECT_EQ(0u, objects.size());
diff --git a/chrome/browser/usb/usb_chooser_controller.cc b/chrome/browser/usb/usb_chooser_controller.cc
index 1dcd0456..d8bc43f2 100644
--- a/chrome/browser/usb/usb_chooser_controller.cc
+++ b/chrome/browser/usb/usb_chooser_controller.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
 #include "chrome/browser/usb/web_usb_histograms.h"
+#include "chrome/browser/usb/web_usb_service_impl.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/render_frame_host.h"
@@ -131,12 +132,12 @@
 }
 
 bool UsbChooserController::IsPaired(size_t index) const {
-  auto& device_info = *devices_[index].first;
   if (!chooser_context_)
     return false;
 
-  return chooser_context_->HasDevicePermission(requesting_origin_,
-                                               embedding_origin_, device_info);
+  return WebUsbServiceImpl::HasDevicePermission(
+      chooser_context_.get(), requesting_origin_, embedding_origin_,
+      *devices_[index].first);
 }
 
 void UsbChooserController::Select(const std::vector<size_t>& indices) {
diff --git a/chrome/browser/usb/web_usb_service_impl.cc b/chrome/browser/usb/web_usb_service_impl.cc
index 0b5ee7e..8c51c131 100644
--- a/chrome/browser/usb/web_usb_service_impl.cc
+++ b/chrome/browser/usb/web_usb_service_impl.cc
@@ -9,10 +9,29 @@
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/usb/usb_blocklist.h"
+#include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
 #include "chrome/browser/usb/usb_tab_helper.h"
 #include "content/public/browser/browser_thread.h"
+#include "device/base/device_client.h"
+#include "device/usb/mojo/device_manager_impl.h"
 #include "device/usb/mojo/type_converters.h"
+#include "device/usb/usb_device.h"
+
+// static
+bool WebUsbServiceImpl::HasDevicePermission(
+    UsbChooserContext* chooser_context,
+    const GURL& requesting_origin,
+    const GURL& embedding_origin,
+    const device::mojom::UsbDeviceInfo& device_info) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (UsbBlocklist::Get().IsExcluded(device_info))
+    return false;
+
+  return chooser_context->HasDevicePermission(requesting_origin,
+                                              embedding_origin, device_info);
+}
 
 WebUsbServiceImpl::WebUsbServiceImpl(
     content::RenderFrameHost* render_frame_host,
@@ -21,13 +40,13 @@
       usb_chooser_(std::move(usb_chooser)),
       observer_(this),
       weak_factory_(this) {
-  DCHECK(render_frame_host_);
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(render_frame_host_);
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  chooser_context_ =
-      UsbChooserContextFactory::GetForProfile(profile)->AsWeakPtr();
+  // Bind |device_manager_| to UsbDeviceManager and set error handler.
+  // TODO(donna.wu@intel.com): Request UsbDeviceManagerPtr from the Device
+  // Service after moving //device/usb to //services/device.
+  device::usb::DeviceManagerImpl::Create(mojo::MakeRequest(&device_manager_));
+  device_manager_.set_connection_error_handler(
+      base::BindOnce(&WebUsbServiceImpl::OnDeviceManagerConnectionError,
+                     base::Unretained(this)));
 
   bindings_.set_connection_error_handler(base::BindRepeating(
       &WebUsbServiceImpl::OnBindingConnectionError, base::Unretained(this)));
@@ -39,38 +58,40 @@
     blink::mojom::WebUsbServiceRequest request) {
   bindings_.AddBinding(this, std::move(request));
 
-  // Listen to UsbChooserContext for add/remove device events from UsbService.
+  // Listen for add/remove device events from UsbService.
+  // TODO(donna.wu@intel.com): Listen to |device_manager_| in the future.
   // We can't set WebUsbServiceImpl as a UsbDeviceManagerClient because
   // the OnDeviceRemoved event will be delivered here after it is delivered
   // to UsbChooserContext, meaning that all ephemeral permission checks in
   // OnDeviceRemoved() will fail.
-  if (!observer_.IsObservingSources() && chooser_context_)
-    observer_.Add(chooser_context_.get());
+  if (!observer_.IsObservingSources()) {
+    auto* usb_service = device::DeviceClient::Get()->GetUsbService();
+    if (usb_service)
+      observer_.Add(usb_service);
+  }
 }
 
 bool WebUsbServiceImpl::HasDevicePermission(
     const device::mojom::UsbDeviceInfo& device_info) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(render_frame_host_);
-  if (!chooser_context_)
-    return false;
 
   content::WebContents* web_contents =
       content::WebContents::FromRenderFrameHost(render_frame_host_);
   content::RenderFrameHost* main_frame = web_contents->GetMainFrame();
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
 
-  return chooser_context_->HasDevicePermission(
+  return HasDevicePermission(
+      UsbChooserContextFactory::GetForProfile(profile),
       render_frame_host_->GetLastCommittedURL().GetOrigin(),
       main_frame->GetLastCommittedURL().GetOrigin(), device_info);
 }
 
 void WebUsbServiceImpl::GetDevices(GetDevicesCallback callback) {
-  if (!chooser_context_)
-    std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
-
-  chooser_context_->GetDevices(base::BindOnce(&WebUsbServiceImpl::OnGetDevices,
-                                              weak_factory_.GetWeakPtr(),
-                                              std::move(callback)));
+  device_manager_->GetDevices(
+      nullptr, base::BindOnce(&WebUsbServiceImpl::OnGetDevices,
+                              weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void WebUsbServiceImpl::OnGetDevices(
@@ -87,16 +108,13 @@
 void WebUsbServiceImpl::GetDevice(
     const std::string& guid,
     device::mojom::UsbDeviceRequest device_request) {
-  if (!chooser_context_)
-    return;
-
   // Try to bind with the new device to be created for DeviceOpened/Closed
-  // events. It is safe to pass this request directly to UsbDeviceManager
+  // events. It is safe to pass this request directly to |device_manager_|
   // because |guid| is unguessable.
   device::mojom::UsbDeviceClientPtr device_client;
   device_client_bindings_.AddBinding(this, mojo::MakeRequest(&device_client));
-  chooser_context_->GetDevice(guid, std::move(device_request),
-                              std::move(device_client));
+  device_manager_->GetDevice(guid, std::move(device_request),
+                             std::move(device_client));
 }
 
 void WebUsbServiceImpl::GetPermission(
@@ -113,8 +131,8 @@
   clients_.AddPtr(std::move(client));
 }
 
-void WebUsbServiceImpl::OnDeviceAdded(
-    device::mojom::UsbDeviceInfoPtr device_info) {
+void WebUsbServiceImpl::OnDeviceAdded(scoped_refptr<device::UsbDevice> device) {
+  auto device_info = device::mojom::UsbDeviceInfo::From(*device);
   DCHECK(device_info);
   if (!HasDevicePermission(*device_info))
     return;
@@ -126,7 +144,8 @@
 }
 
 void WebUsbServiceImpl::OnDeviceRemoved(
-    device::mojom::UsbDeviceInfoPtr device_info) {
+    scoped_refptr<device::UsbDevice> device) {
+  auto device_info = device::mojom::UsbDeviceInfo::From(*device);
   DCHECK(device_info);
   if (!HasDevicePermission(*device_info))
     return;
@@ -137,15 +156,6 @@
       });
 }
 
-void WebUsbServiceImpl::OnDeviceManagerConnectionError() {
-  // Close the connection with blink.
-  clients_.CloseAll();
-  bindings_.CloseAllBindings();
-
-  // Remove itself from UsbChooserContext's ObserverList.
-  observer_.RemoveAll();
-}
-
 // device::mojom::UsbDeviceClient implementation:
 void WebUsbServiceImpl::OnDeviceOpened() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -163,7 +173,20 @@
   tab_helper->DecrementConnectionCount(render_frame_host_);
 }
 
+void WebUsbServiceImpl::OnDeviceManagerConnectionError() {
+  device_manager_.reset();
+
+  // Close the connection with blink.
+  clients_.CloseAll();
+  bindings_.CloseAllBindings();
+  observer_.RemoveAll();
+}
+
 void WebUsbServiceImpl::OnBindingConnectionError() {
   if (bindings_.empty())
     observer_.RemoveAll();
 }
+
+void WebUsbServiceImpl::WillDestroyUsbService() {
+  OnDeviceManagerConnectionError();
+}
diff --git a/chrome/browser/usb/web_usb_service_impl.h b/chrome/browser/usb/web_usb_service_impl.h
index ccd1e59..a7fe2dc 100644
--- a/chrome/browser/usb/web_usb_service_impl.h
+++ b/chrome/browser/usb/web_usb_service_impl.h
@@ -11,9 +11,10 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
-#include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/web_usb_chooser.h"
 #include "device/usb/public/mojom/device.mojom.h"
+#include "device/usb/public/mojom/device_manager.mojom.h"
+#include "device/usb/usb_service.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
@@ -22,6 +23,11 @@
 class RenderFrameHost;
 }
 
+namespace device {
+class UsbDevice;
+}
+
+class GURL;
 class UsbChooserContext;
 
 // Implements a restricted device::mojom::UsbDeviceManager interface by wrapping
@@ -29,9 +35,15 @@
 // permission model as well as permission granted by the user through a device
 // chooser UI.
 class WebUsbServiceImpl : public blink::mojom::WebUsbService,
-                          public UsbChooserContext::Observer,
+                          public device::UsbService::Observer,
                           public device::mojom::UsbDeviceClient {
  public:
+  static bool HasDevicePermission(
+      UsbChooserContext* chooser_context,
+      const GURL& requesting_origin,
+      const GURL& embedding_origin,
+      const device::mojom::UsbDeviceInfo& device_info);
+
   WebUsbServiceImpl(content::RenderFrameHost* render_frame_host,
                     base::WeakPtr<WebUsbChooser> usb_chooser);
   ~WebUsbServiceImpl() override;
@@ -55,20 +67,21 @@
       GetDevicesCallback callback,
       std::vector<device::mojom::UsbDeviceInfoPtr> device_info_list);
 
-  // UsbChooserContext::Observer implementation:
-  void OnDeviceAdded(device::mojom::UsbDeviceInfoPtr device_info) override;
-  void OnDeviceRemoved(device::mojom::UsbDeviceInfoPtr device_info) override;
-  void OnDeviceManagerConnectionError() override;
+  // device::UsbService::Observer implementation:
+  void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override;
+  void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override;
 
   // device::mojom::UsbDeviceClient implementation:
   void OnDeviceOpened() override;
   void OnDeviceClosed() override;
 
+  void WillDestroyUsbService() override;
+
+  void OnDeviceManagerConnectionError();
   void OnBindingConnectionError();
 
   content::RenderFrameHost* const render_frame_host_;
   base::WeakPtr<WebUsbChooser> usb_chooser_;
-  base::WeakPtr<UsbChooserContext> chooser_context_;
 
   // Used to bind with Blink.
   mojo::BindingSet<blink::mojom::WebUsbService> bindings_;
@@ -77,7 +90,8 @@
   // Binding used to connect with USB devices for opened/closed events.
   mojo::BindingSet<device::mojom::UsbDeviceClient> device_client_bindings_;
 
-  ScopedObserver<UsbChooserContext, UsbChooserContext::Observer> observer_;
+  device::mojom::UsbDeviceManagerPtr device_manager_;
+  ScopedObserver<device::UsbService, device::UsbService::Observer> observer_;
 
   base::WeakPtrFactory<WebUsbServiceImpl> weak_factory_;
 
diff --git a/chrome/browser/usb/web_usb_service_impl_unittest.cc b/chrome/browser/usb/web_usb_service_impl_unittest.cc
index c59285c..428749a 100644
--- a/chrome/browser/usb/web_usb_service_impl_unittest.cc
+++ b/chrome/browser/usb/web_usb_service_impl_unittest.cc
@@ -61,15 +61,18 @@
   }
 
  protected:
-  void ConnectToService(blink::mojom::WebUsbServiceRequest request) {
-    if (!web_usb_service_)
-      web_usb_service_.reset(new WebUsbServiceImpl(main_rfh(), nullptr));
-
-    web_usb_service_->BindRequest(std::move(request));
+  WebUsbServicePtr ConnectToService() {
+    WebUsbServicePtr servicePtr;
+    web_usb_service_.reset(new WebUsbServiceImpl(main_rfh(), nullptr));
+    web_usb_service_->BindRequest(mojo::MakeRequest(&servicePtr));
+    return servicePtr;
   }
 
-  UsbChooserContext* GetChooserContext() {
-    return UsbChooserContextFactory::GetForProfile(profile());
+  void GrantDevicePermission(const GURL& requesting_origin,
+                             const GURL& embedding_origin,
+                             const device::mojom::UsbDeviceInfo& device_info) {
+    UsbChooserContextFactory::GetForProfile(profile())->GrantDevicePermission(
+        requesting_origin, embedding_origin, device_info);
   }
 
   device::MockDeviceClient device_client_;
@@ -87,8 +90,6 @@
   UsbDeviceManagerClientPtr CreateInterfacePtrAndBind() {
     UsbDeviceManagerClientPtr client;
     binding_.Bind(mojo::MakeRequest(&client));
-    binding_.set_connection_error_handler(base::BindRepeating(
-        &MockDeviceManagerClient::OnConnectionError, base::Unretained(this)));
     return client;
   }
 
@@ -102,12 +103,6 @@
     DoOnDeviceRemoved(device_info.get());
   }
 
-  MOCK_METHOD0(ConnectionError, void());
-  void OnConnectionError() {
-    binding_.Close();
-    ConnectionError();
-  }
-
  private:
   mojo::Binding<UsbDeviceManagerClient> binding_;
 };
@@ -141,11 +136,10 @@
   auto device_info_1 = device::mojom::UsbDeviceInfo::From(*device1);
 
   device_client_.usb_service()->AddDevice(device0);
-  GetChooserContext()->GrantDevicePermission(origin, origin, *device_info_0);
+  GrantDevicePermission(origin, origin, *device_info_0);
   device_client_.usb_service()->AddDevice(no_permission_device1);
 
-  WebUsbServicePtr web_usb_service;
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
+  WebUsbServicePtr web_usb_service = ConnectToService();
   MockDeviceManagerClient mock_client;
   web_usb_service->SetClient(mock_client.CreateInterfacePtrAndBind());
 
@@ -163,7 +157,7 @@
   }
 
   device_client_.usb_service()->AddDevice(device1);
-  GetChooserContext()->GrantDevicePermission(origin, origin, *device_info_1);
+  GrantDevicePermission(origin, origin, *device_info_1);
   device_client_.usb_service()->AddDevice(no_permission_device2);
   device_client_.usb_service()->RemoveDevice(device0);
   device_client_.usb_service()->RemoveDevice(device1);
@@ -197,87 +191,3 @@
     loop.Run();
   }
 }
-
-TEST_F(WebUsbServiceImplTest, ReconnectDeviceManager) {
-  GURL origin(kDefaultTestUrl);
-
-  auto* context = GetChooserContext();
-  scoped_refptr<UsbDevice> device =
-      new MockUsbDevice(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF");
-  scoped_refptr<UsbDevice> ephemeral_device =
-      new MockUsbDevice(0, 0, "ACME", "Frobinator II", "");
-
-  auto device_info = device::mojom::UsbDeviceInfo::From(*device);
-  auto ephemeral_device_info =
-      device::mojom::UsbDeviceInfo::From(*ephemeral_device);
-
-  device_client_.usb_service()->AddDevice(device);
-  context->GrantDevicePermission(origin, origin, *device_info);
-  device_client_.usb_service()->AddDevice(ephemeral_device);
-  context->GrantDevicePermission(origin, origin, *ephemeral_device_info);
-
-  WebUsbServicePtr web_usb_service;
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
-  MockDeviceManagerClient mock_client;
-  web_usb_service->SetClient(mock_client.CreateInterfacePtrAndBind());
-
-  {
-    std::set<std::string> guids;
-    guids.insert(device->guid());
-    guids.insert(ephemeral_device->guid());
-    base::RunLoop loop;
-    web_usb_service->GetDevices(
-        base::BindOnce(&ExpectDevicesAndThen, guids, loop.QuitClosure()));
-    loop.Run();
-  }
-
-  EXPECT_TRUE(context->HasDevicePermission(origin, origin, *device_info));
-  EXPECT_TRUE(
-      context->HasDevicePermission(origin, origin, *ephemeral_device_info));
-
-  context->DestroyDeviceManagerForTesting();
-  EXPECT_CALL(mock_client, ConnectionError()).Times(1);
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(context->HasDevicePermission(origin, origin, *device_info));
-  EXPECT_FALSE(
-      context->HasDevicePermission(origin, origin, *ephemeral_device_info));
-
-  // Although a new device added, as the Device manager has been destroyed, no
-  // event will be triggered.
-  scoped_refptr<UsbDevice> another_device =
-      new MockUsbDevice(0x1234, 0x5679, "ACME", "Frobinator+", "GHIJKL");
-  device_client_.usb_service()->AddDevice(another_device);
-  auto another_device_info =
-      device::mojom::UsbDeviceInfo::From(*another_device);
-
-  EXPECT_CALL(mock_client, DoOnDeviceAdded(_)).Times(0);
-  base::RunLoop().RunUntilIdle();
-
-  // Grant permission to the new device when service is off.
-  context->GrantDevicePermission(origin, origin, *another_device_info);
-
-  device_client_.usb_service()->RemoveDevice(device);
-  EXPECT_CALL(mock_client, DoOnDeviceRemoved(_)).Times(0);
-  base::RunLoop().RunUntilIdle();
-
-  // Reconnect the service.
-  web_usb_service.reset();
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
-  web_usb_service->SetClient(mock_client.CreateInterfacePtrAndBind());
-
-  {
-    std::set<std::string> guids;
-    guids.insert(another_device->guid());
-    base::RunLoop loop;
-    web_usb_service->GetDevices(
-        base::BindOnce(&ExpectDevicesAndThen, guids, loop.QuitClosure()));
-    loop.Run();
-  }
-
-  EXPECT_TRUE(context->HasDevicePermission(origin, origin, *device_info));
-  EXPECT_TRUE(
-      context->HasDevicePermission(origin, origin, *another_device_info));
-  EXPECT_FALSE(
-      context->HasDevicePermission(origin, origin, *ephemeral_device_info));
-}
diff --git a/chrome/chrome_cleaner/settings/BUILD.gn b/chrome/chrome_cleaner/settings/BUILD.gn
index 28a1c541..549872d 100644
--- a/chrome/chrome_cleaner/settings/BUILD.gn
+++ b/chrome/chrome_cleaner/settings/BUILD.gn
@@ -62,7 +62,6 @@
 
   sources = [
     "cleaner_settings_unittest.cc",
-    "other_settings_definitions.cc",
     "reporter_settings_unittest.cc",
     "settings_unittest.cc",
   ]
diff --git a/chrome/common/extensions/api/tab_capture.idl b/chrome/common/extensions/api/tab_capture.idl
index ae0f0b25..5dd0e6c 100644
--- a/chrome/common/extensions/api/tab_capture.idl
+++ b/chrome/common/extensions/api/tab_capture.idl
@@ -42,11 +42,41 @@
     [nodoc] DOMString? presentationId;
   };
 
+  dictionary GetMediaStreamOptions {
+    // Optional tab id of the tab which will later invoke
+    // <code>getUserMedia()</code> to consume the stream. If not specified
+    // then the resulting stream can be used only by the calling extension.
+    // The stream can only be used by frames in the given tab whose security
+    // origin matches the consumber tab's origin. The tab's origin must be a
+    // secure origin, e.g. HTTPS.
+    long? consumerTabId;
+
+    // Optional tab id of the tab which will be captured. If not specified
+    // then the current active tab will be selected. Only tabs for which the
+    // extension has been granted the <code>activeTab</code> permission can be
+    // used as the target tab.
+    long? targetTabId;
+  };
+
   callback GetTabMediaCallback =
       void ([instanceOf=LocalMediaStream] object stream);
 
   callback GetCapturedTabsCallback = void (CaptureInfo[] result);
 
+  // To assemble MediaConstraints with this |streamId|, source type must be
+  // assigned as 'tab'. For example:
+  // <code>
+  //   const constraints = {
+  //     mandatory: {
+  //       chromeMediaSource: 'tab',
+  //       chromeMediaSourceId: streamId
+  //     }
+  //   };
+  //   navigator.getUserMedia({audio: constraints, video: constraints},
+  //                          successCallback, failCallback);
+  // </code>
+  callback GetMediaStreamIdCallback = void (DOMString streamId);
+
   interface Functions {
     // Captures the visible area of the currently active tab.  Capture can
     // only be started on the currently active tab after the extension has been
@@ -101,6 +131,19 @@
     static void captureOffscreenTab(DOMString startUrl,
                                     CaptureOptions options,
                                     GetTabMediaCallback callback);
+
+    // Creates a stream ID to capture the target tab.
+    // Similar to chrome.tabCapture.capture() method, but returns a media
+    // stream ID, instead of a media stream, to the consumer tab.
+    //
+    // |GetMediaStreamOptions| : Options for the media stream id to retrieve.
+    // |callback| : Callback to invoke with the result. If successful, the
+    // result is an opaque string that can be passed to the
+    // <code>getUserMedia()</code> API to generate a media stream that
+    // corresponds to the target tab. The created <code>streamId</code> can
+    // only be used once and expires after a few seconds if it is not used.
+    static void getMediaStreamId(optional GetMediaStreamOptions options,
+                                 GetMediaStreamIdCallback callback);
   };
 
   interface Events {
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index ad814492..326aa2e2 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -27,8 +27,6 @@
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/arc/arc_service_launcher.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/chrome_history_client.h"
@@ -125,6 +123,11 @@
 #include "content/public/browser/zoom_level_delegate.h"
 #endif  // defined(OS_ANDROID)
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/arc/arc_service_launcher.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#endif
+
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
 #include "chrome/browser/supervised_user/supervised_user_pref_store.h"
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index c0dad18..f9a602cb 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -15,9 +15,6 @@
     # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=528
     'PageLoadingTest.testShouldDoNothingIfThereIsNothingToGoBackTo',
 
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2480
-    'PageLoadingTest.testShouldTimeoutIfAPageTakesTooLongToRefresh',
-
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532
     'SlowLoadingPageTest.testRefreshShouldBlockUntilPageLoads',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2572
diff --git a/chrome/test/data/extensions/api_test/metrics/test.js b/chrome/test/data/extensions/api_test/metrics/test.js
index 29527e3..bbdb964 100644
--- a/chrome/test/data/extensions/api_test/metrics/test.js
+++ b/chrome/test/data/extensions/api_test/metrics/test.js
@@ -145,17 +145,16 @@
     chrome.metricsPrivate.recordValue(linear1, 42);
     // This one should be rejected because the bucket count is different.
     // We check for sample count == 2 in metrics_apitest.cc
-    chrome.metricsPrivate.recordValue(linear2, 42);
+    // chrome.metricsPrivate.recordValue(linear2, 42);  disabled for field test
     chrome.metricsPrivate.recordValue(linear1, 42);
 
     chrome.metricsPrivate.recordValue(log1, 42);
     // This one should be rejected because the bucket count is different.
     // We check for sample count == 2 in metrics_apitest.cc
-    chrome.metricsPrivate.recordValue(log2, 42);
+    // chrome.metricsPrivate.recordValue(log2, 42);  disabled for field test
     chrome.metricsPrivate.recordValue(log1, 42);
 
     chrome.test.succeed();
   },
-
 ]);
 
diff --git a/chrome/test/data/extensions/api_test/tab_capture/api_tests.js b/chrome/test/data/extensions/api_test/tab_capture/api_tests.js
index 3a90989..5240b5c 100644
--- a/chrome/test/data/extensions/api_test/tab_capture/api_tests.js
+++ b/chrome/test/data/extensions/api_test/tab_capture/api_tests.js
@@ -19,6 +19,44 @@
   }
 }
 
+function assertIsValidStreamId(streamId) {
+  chrome.test.assertTrue(typeof streamId == 'string');
+  navigator.webkitGetUserMedia({
+    audio: false,
+    video: {
+      mandatory: {
+        chromeMediaSource: 'tab',
+        chromeMediaSourceId: streamId
+      }
+    }
+  }, function(stream) {
+    chrome.test.assertTrue(!!stream);
+    stream.getVideoTracks()[0].stop();
+    chrome.test.succeed();
+  }, function(error) {
+    chrome.test.fail(error);
+  });
+}
+
+function assertGetUserMediaError(streamId) {
+  chrome.test.assertTrue(typeof streamId == 'string');
+  navigator.webkitGetUserMedia({
+    audio: false,
+    video: {
+      mandatory: {
+        chromeMediaSource: 'tab',
+        chromeMediaSourceId: streamId
+      }
+    }
+  }, function(stream) {
+    chrome.test.assertTrue(!!stream);
+    stream.getVideoTracks()[0].stop();
+    chrome.test.fail('Should not get stream.');
+  }, function(error) {
+    chrome.test.succeed();
+  });
+}
+
 var testsToRun = [
   function captureTabAndVerifyStateTransitions() {
     // Tab capture events in the order they happen.
@@ -171,7 +209,76 @@
             });
           });
     });
-  }
+  },
+
+  function getMediaStreamIdWithCallerTab() {
+    chrome.tabs.getCurrent(function(tab) {
+      tabCapture.getMediaStreamId({consumerTabId: tab.id}, function(streamId) {
+        assertIsValidStreamId(streamId);
+      });
+    });
+  },
+
+  function getMediaStreamIdWithTargetTab() {
+    chrome.tabs.getCurrent(function(tab) {
+      tabCapture.getMediaStreamId({targetTabId: tab.id}, function(streamId) {
+        assertIsValidStreamId(streamId);
+      });
+    });
+  },
+
+  function getMediaStreamIdWithoutTabIds() {
+    tabCapture.getMediaStreamId(function(streamId) {
+      assertIsValidStreamId(streamId);
+    });
+  },
+
+  // Test that if calling getMediaStreamId() with consumber tab specified,
+  // then calling getUserMedia() on another tab will fail to get the stream.
+  function getMediaStreamIdAndGetUserMediaOnDifferentTabs() {
+    var currentTabId;
+    var secondTabId;
+
+    var listener = function(tabId, changeInfo, tab) {
+      if (changeInfo.status == 'complete') {
+        chrome.tabs.onUpdated.removeListener(listener);
+        tabCapture.getMediaStreamId(
+            {consumerTabId: secondTabId},
+            function(streamId) {
+              chrome.tabs.get(currentTabId, function(tab) {
+                assertGetUserMediaError(streamId);
+                chrome.tabs.remove(secondTabId);
+              });
+            });
+      }
+    };
+
+    chrome.tabs.onUpdated.addListener(listener);
+    chrome.tabs.getCurrent(function(tab) {
+      currentTabId = tab.id;
+      chrome.tabs.create({}, function(tab) {
+        secondTabId = tab.id;
+      });
+    });
+  },
+
+  function getMediaStreamIdWithCallerTabWithoutSecuredUrl() {
+    var listener = function(tabId, changeInfo, tab) {
+      if (changeInfo.status == 'complete') {
+        chrome.tabs.onUpdated.removeListener(listener);
+        tabCapture.getMediaStreamId({consumerTabId: tabId}, function(streamId) {
+          chrome.test.assertTrue(typeof streamId == 'undefined');
+          chrome.test.assertLastError(
+              'URL scheme for the specified tab is not secure.');
+          chrome.test.succeed();
+          chrome.tabs.remove(tab.id);
+        });
+      }
+    };
+
+    chrome.tabs.onUpdated.addListener(listener);
+    chrome.tabs.create({url: 'http://example.com/fun.html'});
+  },
 ];
 
 chrome.test.runTests(testsToRun);
diff --git a/chrome/test/data/extensions/theme_test_captionbutton_buttoncolor/manifest.json b/chrome/test/data/extensions/theme_test_captionbutton_buttoncolor/manifest.json
new file mode 100644
index 0000000..214c579
--- /dev/null
+++ b/chrome/test/data/extensions/theme_test_captionbutton_buttoncolor/manifest.json
@@ -0,0 +1,13 @@
+{
+   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA86mhrLvksz5gZCoPPfkXNV1y77ii+ecyGLsvQk8zY7MbLezwdpqbX9DKmz+63kEp6A4ck7Kk+utUG6qDSTsUjDTZuHhVOasA5BLKF23CVvrpvyka72fTjrA1LmyKkVlLAfAaQwYg/XcXHp54AdclMaaVD/J1TbyTeqZ7a2bM7+Lh4MAJW3DrgjFk9SiL+mqI6zw4rGPYHYUOmkfoJ7ffS4z8dOP81c6X95LVjWeIPYlpCRHN0OOtEMHr2JuH38fNZ3v1mFyNueRb/iOupoVwn2a1W7jVbnCTQFiP1gsgHiySmk/LoQZLX+KiboG4Wcim/Xtxt8agbgRmlppNYIbblQIDAQAB",
+   "manifest_version": 2,
+   "name": "test_captionbuttons_buttoncolor",
+   "theme": {
+      "colors": {
+         "frame": [255, 255, 255],
+         "frame_inactive": [255, 255, 255],
+         "button_background": [15, 25, 20]
+      }
+   },
+   "version": "0.0.1"
+}
diff --git a/chrome/test/data/extensions/theme_test_captionbutton_buttonimage/images/control_button_bg.png b/chrome/test/data/extensions/theme_test_captionbutton_buttonimage/images/control_button_bg.png
new file mode 100644
index 0000000..9d8b074
--- /dev/null
+++ b/chrome/test/data/extensions/theme_test_captionbutton_buttonimage/images/control_button_bg.png
Binary files differ
diff --git a/chrome/test/data/extensions/theme_test_captionbutton_buttonimage/manifest.json b/chrome/test/data/extensions/theme_test_captionbutton_buttonimage/manifest.json
new file mode 100644
index 0000000..e8c8fbf
--- /dev/null
+++ b/chrome/test/data/extensions/theme_test_captionbutton_buttonimage/manifest.json
@@ -0,0 +1,15 @@
+{
+   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArRdLT8rOFOhqED9zNVlmywZ5CCYCkVozs0u1+R8taTdSvUiiwavqt6Nqkk6N98Dj7uzBz43pdoqPbFoisu78ggPL+oRLGbQrejzc9dqf5VKvx3cnDlKX+AekZqWAj6QCFWN7kP+rgqqvelDHbhEEUYTVcNwjuSDqVDcgQmJuH2OmfUjdV9EmmRKOqUAPmxsx9u77IT/2cbGyA4oGaKnMSP5lFukmxmKTUyxROuL1ePIhprAr510MDdR6CIONwpF+g32UpXJswcEJ+SG4HuHMKwu0nVRcz4v0Av8dKv7PyShBifspyr1zJXKhTYnI87c7U/7zCeoICWDFq+WGSMrbQwIDAQAB",
+   "manifest_version": 2,
+   "name": "test_captionbutton_buttonimage",
+   "theme": {
+      "colors": {
+         "frame": [240, 235, 244],
+         "frame_inactive": [240, 235, 244]
+      },
+    "images": {
+         "theme_window_control_background": "images/control_button_bg.png"
+      }
+   },
+   "version": "0.0.1"
+}
diff --git a/chrome/test/data/extensions/theme_test_captionbutton_framecolor/manifest.json b/chrome/test/data/extensions/theme_test_captionbutton_framecolor/manifest.json
new file mode 100644
index 0000000..989eadd
--- /dev/null
+++ b/chrome/test/data/extensions/theme_test_captionbutton_framecolor/manifest.json
@@ -0,0 +1,12 @@
+{
+   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0BdvE6gv1tzGF9ksfAwBtqZpkNj/AncX058sNiw0fXTv0qxKZzvxtsYZQh+vSHrZRiKPABekNlvimsN/3RwDoP0Ln1pGrgZN6jZFlQucVHlcviIS564DXAUHACSmMhakF+RTcaTaWwoEliDBJimYwi4LpV93STG95TtHfHNytyV2Vl5HGFyZlXSfKTEqPGik54nnjBJaoaYJON+9E1Z7ntYgxBw3c0YMe859BpdpsMa2aj7imUlIwvlKXxTJcvw+Xg/LevpgtKcbBGMuIzlfWMmQu22ggcpdcw7Xmyg2hdlj6tz6Y++beAJjx6bNOROgIpIH4CterRWDgnVB3TrZJQIDAQAB",
+   "manifest_version": 2,
+   "name": "test_captionbuttons_framecolor",
+   "theme": {
+      "colors": {
+         "frame": [220, 235, 210],
+         "frame_inactive": [30, 40, 35]
+      }
+   },
+   "version": "0.0.1"
+}
diff --git a/chrome/test/data/extensions/theme_testinherittextcolor_withincog/manifest.json b/chrome/test/data/extensions/theme_testinherittextcolor_withincog/manifest.json
index 16d91f21..b2119b1 100644
--- a/chrome/test/data/extensions/theme_testinherittextcolor_withincog/manifest.json
+++ b/chrome/test/data/extensions/theme_testinherittextcolor_withincog/manifest.json
@@ -8,7 +8,7 @@
         "tab_background_text": [0,255,0],
         "background_tab_inactive": [0,0,0],
         "background_tab_incognito": [0,0,0],
-		"tab_background_text_incognito": [0,0,255],
+        "tab_background_text_incognito": [0,0,255],
         "background_tab_incognito_inactive": [0,0,0]
       }
    },
diff --git a/chrome/test/data/webui/settings/autofill_section_test.js b/chrome/test/data/webui/settings/autofill_section_test.js
index 0bc77ab..f806533 100644
--- a/chrome/test/data/webui/settings/autofill_section_test.js
+++ b/chrome/test/data/webui/settings/autofill_section_test.js
@@ -329,7 +329,10 @@
 
             // Default country is 'US' expecting: Name, Organization,
             // Street address, City, State, ZIP code, Phone, and Email.
-            assertEquals(8, testElements.length);
+            // Unless Company name is disabled.
+            const company_enabled =
+                loadTimeData.getBoolean('EnableCompanyName');
+            assertEquals(company_enabled ? 8 : 7, testElements.length);
 
             return asyncForEach(testElements, function(element) {
               return expectEvent(
@@ -386,7 +389,7 @@
     // Test will timeout if save-address event is not fired.
     test('verifyDefaultCountryIsAppliedWhenSaving', function() {
       const address = FakeDataMaker.emptyAddressEntry();
-      address.companyName = 'Google';
+      address.fullNames = ['Name'];
       return createAddressDialog(address).then(function(dialog) {
         return expectEvent(dialog, 'save-address', function() {
                  // Verify |countryCode| is not set.
@@ -432,7 +435,7 @@
     // US address has 3 fields on the same line.
     test('verifyEditingUSAddress', function() {
       const address = FakeDataMaker.emptyAddressEntry();
-
+      const company_enabled = loadTimeData.getBoolean('EnableCompanyName');
       address.fullNames = ['Name'];
       address.companyName = 'Organization';
       address.addressLines = 'Street address';
@@ -445,39 +448,47 @@
 
       return createAddressDialog(address).then(function(dialog) {
         const rows = dialog.$.dialog.querySelectorAll('.address-row');
-        assertEquals(6, rows.length);
+        assertEquals(company_enabled ? 6 : 5, rows.length);
 
+        let index = 0;
         // Name
-        let row = rows[0];
+        let row = rows[index];
         let cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.fullNames[0], cols[0].value);
+        index++;
         // Organization
-        row = rows[1];
-        cols = row.querySelectorAll('.address-column');
-        assertEquals(1, cols.length);
-        assertEquals(address.companyName, cols[0].value);
+        if (company_enabled) {
+          row = rows[index];
+          cols = row.querySelectorAll('.address-column');
+          assertEquals(1, cols.length);
+          assertEquals(address.companyName, cols[0].value);
+          index++;
+        }
         // Street address
-        row = rows[2];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.addressLines, cols[0].value);
+        index++;
         // City, State, ZIP code
-        row = rows[3];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(3, cols.length);
         assertEquals(address.addressLevel2, cols[0].value);
         assertEquals(address.addressLevel1, cols[1].value);
         assertEquals(address.postalCode, cols[2].value);
+        index++;
         // Country
-        row = rows[4];
+        row = rows[index];
         const countrySelect = row.querySelector('select');
         assertTrue(!!countrySelect);
         assertEquals(
             'United States',
             countrySelect.selectedOptions[0].textContent.trim());
+        index++;
         // Phone, Email
-        row = rows[5];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(2, cols.length);
         assertEquals(address.phoneNumbers[0], cols[0].value);
@@ -488,6 +499,7 @@
     // GB address has 1 field per line for all lines that change.
     test('verifyEditingGBAddress', function() {
       const address = FakeDataMaker.emptyAddressEntry();
+      const company_enabled = loadTimeData.getBoolean('EnableCompanyName');
 
       address.fullNames = ['Name'];
       address.companyName = 'Organization';
@@ -500,42 +512,51 @@
 
       return createAddressDialog(address).then(function(dialog) {
         const rows = dialog.$.dialog.querySelectorAll('.address-row');
-        assertEquals(7, rows.length);
+        assertEquals(company_enabled ? 7 : 6, rows.length);
 
+        let index = 0;
         // Name
-        let row = rows[0];
+        let row = rows[index];
         let cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.fullNames[0], cols[0].value);
+        index++;
         // Organization
-        row = rows[1];
-        cols = row.querySelectorAll('.address-column');
-        assertEquals(1, cols.length);
-        assertEquals(address.companyName, cols[0].value);
+        if (company_enabled) {
+          row = rows[index];
+          cols = row.querySelectorAll('.address-column');
+          assertEquals(1, cols.length);
+          assertEquals(address.companyName, cols[0].value);
+          index++;
+        }
         // Street address
-        row = rows[2];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.addressLines, cols[0].value);
+        index++;
         // Post Town
-        row = rows[3];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.addressLevel2, cols[0].value);
+        index++;
         // Postal code
-        row = rows[4];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.postalCode, cols[0].value);
+        index++;
         // Country
-        row = rows[5];
+        row = rows[index];
         const countrySelect = row.querySelector('select');
         assertTrue(!!countrySelect);
         assertEquals(
             'United Kingdom',
             countrySelect.selectedOptions[0].textContent.trim());
+        index++;
         // Phone, Email
-        row = rows[6];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(2, cols.length);
         assertEquals(address.phoneNumbers[0], cols[0].value);
@@ -547,6 +568,7 @@
     // RTL locale shouldn't affect this test.
     test('verifyEditingILAddress', function() {
       const address = FakeDataMaker.emptyAddressEntry();
+      const company_enabled = loadTimeData.getBoolean('EnableCompanyName');
 
       address.fullNames = ['Name'];
       address.companyName = 'Organization';
@@ -559,37 +581,46 @@
 
       return createAddressDialog(address).then(function(dialog) {
         const rows = dialog.$.dialog.querySelectorAll('.address-row');
-        assertEquals(6, rows.length);
+        assertEquals(company_enabled ? 6 : 5, rows.length);
 
+        let index = 0;
         // Name
-        let row = rows[0];
+        let row = rows[index];
         let cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.fullNames[0], cols[0].value);
+        index++;
         // Organization
-        row = rows[1];
-        cols = row.querySelectorAll('.address-column');
-        assertEquals(1, cols.length);
-        assertEquals(address.companyName, cols[0].value);
+
+        if (company_enabled) {
+          row = rows[index];
+          cols = row.querySelectorAll('.address-column');
+          assertEquals(1, cols.length);
+          assertEquals(address.companyName, cols[0].value);
+          index++;
+        }
         // Street address
-        row = rows[2];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(1, cols.length);
         assertEquals(address.addressLines, cols[0].value);
+        index++;
         // City, Postal code
-        row = rows[3];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(2, cols.length);
         assertEquals(address.addressLevel2, cols[0].value);
         assertEquals(address.postalCode, cols[1].value);
+        index++;
         // Country
-        row = rows[4];
+        row = rows[index];
         const countrySelect = row.querySelector('select');
         assertTrue(!!countrySelect);
         assertEquals(
             'Israel', countrySelect.selectedOptions[0].textContent.trim());
+        index++;
         // Phone, Email
-        row = rows[5];
+        row = rows[index];
         cols = row.querySelectorAll('.address-column');
         assertEquals(2, cols.length);
         assertEquals(address.phoneNumbers[0], cols[0].value);
@@ -601,6 +632,7 @@
     // persisted when switching to IL then back to US.
     test('verifyAddressPersistanceWhenSwitchingCountries', function() {
       const address = FakeDataMaker.emptyAddressEntry();
+      const company_enabled = loadTimeData.getBoolean('EnableCompanyName');
       address.countryCode = 'US';
 
       return createAddressDialog(address).then(function(dialog) {
@@ -615,10 +647,10 @@
                      // US:
                      const rows =
                          dialog.$.dialog.querySelectorAll('.address-row');
-                     assertEquals(6, rows.length);
+                     assertEquals(company_enabled ? 6 : 5, rows.length);
 
                      // City, State, ZIP code
-                     const row = rows[3];
+                     const row = rows[company_enabled ? 3 : 2];
                      const cols = row.querySelectorAll('.address-column');
                      assertEquals(3, cols.length);
                      cols[0].value = city;
@@ -633,10 +665,10 @@
                   dialog, 'on-update-address-wrapper', function() {
                     // IL:
                     rows = dialog.$.dialog.querySelectorAll('.address-row');
-                    assertEquals(6, rows.length);
+                    assertEquals(company_enabled ? 6 : 5, rows.length);
 
                     // City, Postal code
-                    row = rows[3];
+                    row = rows[company_enabled ? 3 : 2];
                     cols = row.querySelectorAll('.address-column');
                     assertEquals(2, cols.length);
                     assertEquals(city, cols[0].value);
@@ -649,10 +681,10 @@
             .then(function() {
               // US:
               const rows = dialog.$.dialog.querySelectorAll('.address-row');
-              assertEquals(6, rows.length);
+              assertEquals(company_enabled ? 6 : 5, rows.length);
 
               // City, State, ZIP code
-              row = rows[3];
+              row = rows[company_enabled ? 3 : 2];
               cols = row.querySelectorAll('.address-column');
               assertEquals(3, cols.length);
               assertEquals(city, cols[0].value);
diff --git a/chrome/test/data/webui/settings/people_page_sync_page_test.js b/chrome/test/data/webui/settings/people_page_sync_page_test.js
index fa496728..04139d1 100644
--- a/chrome/test/data/webui/settings/people_page_sync_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_sync_page_test.js
@@ -224,6 +224,15 @@
         statusAction: settings.StatusAction.REAUTHENTICATE
       };
       assertTrue(ironCollapse.hidden);
+
+      // Test passphrase error state.
+      syncPage.syncStatus = {
+        signedIn: true,
+        disabled: false,
+        hasError: true,
+        statusAction: settings.StatusAction.ENTER_PASSPHRASE
+      };
+      assertFalse(ironCollapse.hidden);
     });
 
     test('SyncSectionLayout_UnifiedConsentEnabled_SignoutCollapse', function() {
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index ea542152..4358b4f 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -29,10 +29,10 @@
     "cast_browser_process.h",
     "cast_content_browser_client.cc",
     "cast_content_browser_client.h",
+    "cast_content_gesture_handler.cc",
+    "cast_content_gesture_handler.h",
     "cast_download_manager_delegate.cc",
     "cast_download_manager_delegate.h",
-    "cast_gesture_dispatcher.cc",
-    "cast_gesture_dispatcher.h",
     "cast_http_user_agent_settings.cc",
     "cast_http_user_agent_settings.h",
     "cast_media_blocker.cc",
@@ -445,7 +445,7 @@
 cast_source_set("browsertests") {
   testonly = true
   sources = [
-    "cast_gesture_dispatcher_test.cc",
+    "cast_content_gesture_handler_test.cc",
     "cast_media_blocker_browsertest.cc",
     "renderer_prelauncher_test.cc",
     "test/cast_features_browsertest.cc",
diff --git a/chromecast/browser/cast_gesture_dispatcher.cc b/chromecast/browser/cast_content_gesture_handler.cc
similarity index 78%
rename from chromecast/browser/cast_gesture_dispatcher.cc
rename to chromecast/browser/cast_content_gesture_handler.cc
index 2bd080a9..7df5fe9 100644
--- a/chromecast/browser/cast_gesture_dispatcher.cc
+++ b/chromecast/browser/cast_content_gesture_handler.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 "chromecast/browser/cast_gesture_dispatcher.h"
+#include "chromecast/browser/cast_content_gesture_handler.h"
 
 #include "chromecast/base/chromecast_switches.h"
 
@@ -13,7 +13,7 @@
 constexpr int kDefaultBackGestureHorizontalThreshold = 80;
 }  // namespace
 
-CastGestureDispatcher::CastGestureDispatcher(
+CastContentGestureHandler::CastContentGestureHandler(
     CastContentWindow::Delegate* delegate,
     bool enable_top_drag_gesture)
     : priority_(Priority::NONE),
@@ -25,25 +25,27 @@
   DCHECK(delegate_);
 }
 
-CastGestureDispatcher::CastGestureDispatcher(
+CastContentGestureHandler::CastContentGestureHandler(
     CastContentWindow::Delegate* delegate)
-    : CastGestureDispatcher(
+    : CastContentGestureHandler(
           delegate,
           GetSwitchValueBoolean(switches::kEnableTopDragGesture, false)) {}
 
-void CastGestureDispatcher::SetPriority(CastGestureHandler::Priority priority) {
+void CastContentGestureHandler::SetPriority(
+    CastGestureHandler::Priority priority) {
   priority_ = priority;
 }
 
-CastGestureHandler::Priority CastGestureDispatcher::GetPriority() {
+CastGestureHandler::Priority CastContentGestureHandler::GetPriority() {
   return priority_;
 }
 
-bool CastGestureDispatcher::CanHandleSwipe(CastSideSwipeOrigin swipe_origin) {
+bool CastContentGestureHandler::CanHandleSwipe(
+    CastSideSwipeOrigin swipe_origin) {
   return delegate_->CanHandleGesture(GestureForSwipeOrigin(swipe_origin));
 }
 
-GestureType CastGestureDispatcher::GestureForSwipeOrigin(
+GestureType CastContentGestureHandler::GestureForSwipeOrigin(
     CastSideSwipeOrigin swipe_origin) {
   switch (swipe_origin) {
     case CastSideSwipeOrigin::LEFT:
@@ -56,9 +58,10 @@
   }
 }
 
-void CastGestureDispatcher::HandleSideSwipe(CastSideSwipeEvent event,
-                                            CastSideSwipeOrigin swipe_origin,
-                                            const gfx::Point& touch_location) {
+void CastContentGestureHandler::HandleSideSwipe(
+    CastSideSwipeEvent event,
+    CastSideSwipeOrigin swipe_origin,
+    const gfx::Point& touch_location) {
   if (!CanHandleSwipe(swipe_origin)) {
     return;
   }
@@ -96,7 +99,7 @@
   }
 }
 
-void CastGestureDispatcher::HandleTapDownGesture(
+void CastContentGestureHandler::HandleTapDownGesture(
     const gfx::Point& touch_location) {
   if (!delegate_->CanHandleGesture(GestureType::TAP_DOWN)) {
     return;
@@ -104,7 +107,8 @@
   delegate_->ConsumeGesture(GestureType::TAP_DOWN);
 }
 
-void CastGestureDispatcher::HandleTapGesture(const gfx::Point& touch_location) {
+void CastContentGestureHandler::HandleTapGesture(
+    const gfx::Point& touch_location) {
   if (!delegate_->CanHandleGesture(GestureType::TAP)) {
     return;
   }
diff --git a/chromecast/browser/cast_gesture_dispatcher.h b/chromecast/browser/cast_content_gesture_handler.h
similarity index 68%
rename from chromecast/browser/cast_gesture_dispatcher.h
rename to chromecast/browser/cast_content_gesture_handler.h
index 0afc5e3..8b889e79 100644
--- a/chromecast/browser/cast_gesture_dispatcher.h
+++ b/chromecast/browser/cast_content_gesture_handler.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 CHROMECAST_BROWSER_CAST_GESTURE_DISPATCHER_H_
-#define CHROMECAST_BROWSER_CAST_GESTURE_DISPATCHER_H_
+#ifndef CHROMECAST_BROWSER_CAST_CONTENT_GESTURE_HANDLER_H_
+#define CHROMECAST_BROWSER_CAST_CONTENT_GESTURE_HANDLER_H_
 
 #include "base/macros.h"
 #include "base/timer/elapsed_timer.h"
@@ -14,11 +14,11 @@
 
 namespace shell {
 
-// Receives root window level gestures, interprets them, and dispatches them to
-// the CastContentWindow::Delegate.
-class CastGestureDispatcher : public CastGestureHandler {
+// Receives root window level gestures, interprets them, and hands them to the
+// CastContentWindow::Delegate.
+class CastContentGestureHandler : public CastGestureHandler {
  public:
-  explicit CastGestureDispatcher(CastContentWindow::Delegate* delegate);
+  explicit CastContentGestureHandler(CastContentWindow::Delegate* delegate);
 
   // CastGestureHandler implementation:
   Priority GetPriority() override;
@@ -32,9 +32,9 @@
   void SetPriority(Priority priority);
 
  private:
-  friend class CastGestureDispatcherTest;
-  CastGestureDispatcher(CastContentWindow::Delegate* delegate,
-                        bool enable_top_drag_gesture);
+  friend class CastContentGestureHandlerTest;
+  CastContentGestureHandler(CastContentWindow::Delegate* delegate,
+                            bool enable_top_drag_gesture);
   GestureType GestureForSwipeOrigin(CastSideSwipeOrigin swipe_origin);
 
   Priority priority_;
@@ -50,4 +50,4 @@
 }  // namespace shell
 }  // namespace chromecast
 
-#endif  // CHROMECAST_BROWSER_CAST_GESTURE_DISPATCHER_H_
+#endif  // CHROMECAST_BROWSER_CAST_CONTENT_GESTURE_HANDLER_H_
diff --git a/chromecast/browser/cast_gesture_dispatcher_test.cc b/chromecast/browser/cast_content_gesture_handler_test.cc
similarity index 92%
rename from chromecast/browser/cast_gesture_dispatcher_test.cc
rename to chromecast/browser/cast_content_gesture_handler_test.cc
index c62e311..c0addb7 100644
--- a/chromecast/browser/cast_gesture_dispatcher_test.cc
+++ b/chromecast/browser/cast_content_gesture_handler_test.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 "chromecast/browser/cast_gesture_dispatcher.h"
+#include "chromecast/browser/cast_content_gesture_handler.h"
 
 #include "chromecast/base/chromecast_switches.h"
 #include "content/public/test/browser_test.h"
@@ -51,18 +51,18 @@
   std::string GetId() override { return "mockContentWindowDelegate"; }
 };
 
-class CastGestureDispatcherTest : public testing::Test {
+class CastContentGestureHandlerTest : public testing::Test {
  public:
-  CastGestureDispatcherTest() : dispatcher_(&delegate_, true) {}
+  CastContentGestureHandlerTest() : dispatcher_(&delegate_, true) {}
 
  protected:
   MockCastContentWindowDelegate delegate_;
-  CastGestureDispatcher dispatcher_;
+  CastContentGestureHandler dispatcher_;
 };
 
 // Verify the simple case of a left swipe with the right horizontal leads to
 // back.
-TEST_F(CastGestureDispatcherTest, VerifySimpleBackSuccess) {
+TEST_F(CastContentGestureHandlerTest, VerifySimpleBackSuccess) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -84,7 +84,7 @@
 }
 
 // Verify that if the finger is not lifted, that's not a back gesture.
-TEST_F(CastGestureDispatcherTest, VerifyNoDispatchOnNoLift) {
+TEST_F(CastContentGestureHandlerTest, VerifyNoDispatchOnNoLift) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -107,7 +107,7 @@
 
 // Verify that multiple 'continue' events still only lead to one back
 // invocation.
-TEST_F(CastGestureDispatcherTest, VerifyOnlySingleDispatch) {
+TEST_F(CastContentGestureHandlerTest, VerifyOnlySingleDispatch) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -133,7 +133,7 @@
 
 // Verify that if the delegate says it doesn't handle back that we won't try to
 // ask them to consume it.
-TEST_F(CastGestureDispatcherTest, VerifyDelegateDoesNotConsumeUnwanted) {
+TEST_F(CastContentGestureHandlerTest, VerifyDelegateDoesNotConsumeUnwanted) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -150,7 +150,7 @@
 }
 
 // Verify that a not-left gesture doesn't lead to a swipe.
-TEST_F(CastGestureDispatcherTest, VerifyNotLeftSwipeIsNotBack) {
+TEST_F(CastContentGestureHandlerTest, VerifyNotLeftSwipeIsNotBack) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -164,7 +164,7 @@
 
 // Verify that if the gesture doesn't go far enough horizontally that we will
 // not consider it a swipe.
-TEST_F(CastGestureDispatcherTest, VerifyNotFarEnoughRightIsNotBack) {
+TEST_F(CastContentGestureHandlerTest, VerifyNotFarEnoughRightIsNotBack) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -187,7 +187,7 @@
 
 // Verify that if the gesture ends before going far enough, that's also not a
 // swipe.
-TEST_F(CastGestureDispatcherTest, VerifyNotFarEnoughRightAndEndIsNotBack) {
+TEST_F(CastContentGestureHandlerTest, VerifyNotFarEnoughRightAndEndIsNotBack) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(false));
 
@@ -209,7 +209,7 @@
 }
 
 // Verify simple top-down drag.
-TEST_F(CastGestureDispatcherTest, VerifySimpleTopSuccess) {
+TEST_F(CastContentGestureHandlerTest, VerifySimpleTopSuccess) {
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::TOP_DRAG)))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(delegate_, CanHandleGesture(Eq(GestureType::GO_BACK)))
diff --git a/chromecast/browser/cast_content_window_aura.cc b/chromecast/browser/cast_content_window_aura.cc
index ec6b03c..29b8884 100644
--- a/chromecast/browser/cast_content_window_aura.cc
+++ b/chromecast/browser/cast_content_window_aura.cc
@@ -74,7 +74,8 @@
 CastContentWindowAura::CastContentWindowAura(
     const CastContentWindow::CreateParams& params)
     : delegate_(params.delegate),
-      gesture_dispatcher_(std::make_unique<CastGestureDispatcher>(delegate_)),
+      gesture_dispatcher_(
+          std::make_unique<CastContentGestureHandler>(delegate_)),
       gesture_priority_(params.gesture_priority),
       is_touch_enabled_(params.enable_touch_input),
       window_(nullptr),
diff --git a/chromecast/browser/cast_content_window_aura.h b/chromecast/browser/cast_content_window_aura.h
index 62c0704..0548ec8a 100644
--- a/chromecast/browser/cast_content_window_aura.h
+++ b/chromecast/browser/cast_content_window_aura.h
@@ -6,8 +6,8 @@
 #define CHROMECAST_BROWSER_CAST_CONTENT_WINDOW_AURA_H_
 
 #include "base/macros.h"
+#include "chromecast/browser/cast_content_gesture_handler.h"
 #include "chromecast/browser/cast_content_window.h"
-#include "chromecast/browser/cast_gesture_dispatcher.h"
 #include "ui/aura/window_observer.h"
 
 namespace aura {
@@ -54,8 +54,8 @@
   CastContentWindow::Delegate* const delegate_;
 
   // Utility class for detecting and dispatching gestures to delegates.
-  std::unique_ptr<CastGestureDispatcher> gesture_dispatcher_;
-  CastGestureDispatcher::Priority const gesture_priority_;
+  std::unique_ptr<CastContentGestureHandler> gesture_dispatcher_;
+  CastContentGestureHandler::Priority const gesture_priority_;
 
   const bool is_touch_enabled_;
   std::unique_ptr<TouchBlocker> touch_blocker_;
diff --git a/chromecast/media/cma/backend/alsa/mixer_output_stream_alsa.cc b/chromecast/media/cma/backend/alsa/mixer_output_stream_alsa.cc
index ce57698..232b3312 100644
--- a/chromecast/media/cma/backend/alsa/mixer_output_stream_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/mixer_output_stream_alsa.cc
@@ -126,15 +126,7 @@
 }
 
 MixerOutputStreamAlsa::~MixerOutputStreamAlsa() {
-  if (pcm_) {
-    LOG(INFO) << "snd_pcm_close: handle=" << pcm_;
-    int err = alsa_->PcmClose(pcm_);
-    if (err < 0) {
-      LOG(ERROR) << "snd_pcm_close error, leaking handle: "
-                 << alsa_->StrError(err);
-    }
-    pcm_ = nullptr;
-  }
+  Stop();
 }
 
 void MixerOutputStreamAlsa::SetAlsaWrapperForTest(
@@ -270,6 +262,14 @@
       LOG(ERROR) << "snd_pcm_drop error: " << alsa_->StrError(err);
     }
   }
+
+  LOG(INFO) << "snd_pcm_close: handle=" << pcm_;
+  int err = alsa_->PcmClose(pcm_);
+  if (err < 0) {
+   LOG(ERROR) << "snd_pcm_close error, leaking handle: "
+              << alsa_->StrError(err);
+  }
+  pcm_ = nullptr;
 }
 
 int MixerOutputStreamAlsa::SetAlsaPlaybackParams(int requested_sample_rate) {
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc
index 62cc34e..2244ecbe 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/fake_session_manager_client.cc
@@ -511,6 +511,8 @@
 void FakeSessionManagerClient::StartArcMiniContainer(
     const login_manager::StartArcMiniContainerRequest& request,
     StartArcMiniContainerCallback callback) {
+  last_start_arc_mini_container_request_ = request;
+
   if (!arc_available_) {
     PostReply(FROM_HERE, std::move(callback), base::nullopt);
     return;
diff --git a/chromeos/dbus/fake_session_manager_client.h b/chromeos/dbus/fake_session_manager_client.h
index 1827b12..79775ec 100644
--- a/chromeos/dbus/fake_session_manager_client.h
+++ b/chromeos/dbus/fake_session_manager_client.h
@@ -159,6 +159,10 @@
       const {
     return last_upgrade_arc_request_;
   }
+  const login_manager::StartArcMiniContainerRequest
+  last_start_arc_mini_container_request() const {
+    return last_start_arc_mini_container_request_;
+  }
 
   // Notify observers about a property change completion.
   void OnPropertyChangeComplete(bool success);
@@ -228,6 +232,10 @@
   // Pseudo running container id. If not running, empty.
   std::string container_instance_id_;
 
+  // Contains last request passed to StartArcMiniContainer
+  login_manager::StartArcMiniContainerRequest
+      last_start_arc_mini_container_request_;
+
   // Contains last requst passed to StartArcInstance
   login_manager::UpgradeArcContainerRequest last_upgrade_arc_request_;
 
diff --git a/components/arc/arc_session.cc b/components/arc/arc_session.cc
index 83278f6..2978e54b 100644
--- a/components/arc/arc_session.cc
+++ b/components/arc/arc_session.cc
@@ -28,9 +28,10 @@
 
 // static
 std::unique_ptr<ArcSession> ArcSession::Create(
-    ArcBridgeService* arc_bridge_service) {
+    ArcBridgeService* arc_bridge_service,
+    ash::DefaultScaleFactorRetriever* retriever) {
   return std::make_unique<ArcSessionImpl>(
-      ArcSessionImpl::CreateDelegate(arc_bridge_service));
+      ArcSessionImpl::CreateDelegate(arc_bridge_service, retriever));
 }
 
 }  // namespace arc
diff --git a/components/arc/arc_session.h b/components/arc/arc_session.h
index 0538306..797684c 100644
--- a/components/arc/arc_session.h
+++ b/components/arc/arc_session.h
@@ -15,6 +15,10 @@
 #include "components/arc/arc_stop_reason.h"
 #include "components/arc/arc_supervision_transition.h"
 
+namespace ash {
+class DefaultScaleFactorRetriever;
+}
+
 namespace base {
 class FilePath;
 }
@@ -85,7 +89,8 @@
 
   // Creates a default instance of ArcSession.
   static std::unique_ptr<ArcSession> Create(
-      ArcBridgeService* arc_bridge_service);
+      ArcBridgeService* arc_bridge_service,
+      ash::DefaultScaleFactorRetriever* retriever);
   virtual ~ArcSession();
 
   // Sends D-Bus message to start a mini-container.
diff --git a/components/arc/arc_session_impl.cc b/components/arc/arc_session_impl.cc
index 3040fa7..7c9d975 100644
--- a/components/arc/arc_session_impl.cc
+++ b/components/arc/arc_session_impl.cc
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/public/cpp/default_scale_factor_retriever.h"
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/posix/eintr_wrapper.h"
@@ -25,6 +26,7 @@
 #include "chromeos/dbus/login_manager/arc.pb.h"
 #include "components/arc/arc_bridge_host_impl.h"
 #include "components/arc/arc_features.h"
+#include "components/arc/arc_util.h"
 #include "components/user_manager/user_manager.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
@@ -129,12 +131,14 @@
 // Real Delegate implementation to connect Mojo.
 class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate {
  public:
-  explicit ArcSessionDelegateImpl(ArcBridgeService* arc_bridge_service);
+  ArcSessionDelegateImpl(ArcBridgeService* arc_bridge_service,
+                         ash::DefaultScaleFactorRetriever* retriever);
   ~ArcSessionDelegateImpl() override = default;
 
   // ArcSessionImpl::Delegate override.
   base::ScopedFD ConnectMojo(base::ScopedFD socket_fd,
                              ConnectMojoCallback callback) override;
+  void GetLcdDensity(GetLcdDensityCallback callback) override;
 
  private:
   // Synchronously accepts a connection on |server_endpoint| and then processes
@@ -152,6 +156,9 @@
   // Owned by ArcServiceManager.
   ArcBridgeService* const arc_bridge_service_;
 
+  // Owned by ArcServiceLauncher.
+  ash::DefaultScaleFactorRetriever* const default_scale_factor_retriever_;
+
   // WeakPtrFactory to use callbacks.
   base::WeakPtrFactory<ArcSessionDelegateImpl> weak_factory_;
 
@@ -159,8 +166,11 @@
 };
 
 ArcSessionDelegateImpl::ArcSessionDelegateImpl(
-    ArcBridgeService* arc_bridge_service)
-    : arc_bridge_service_(arc_bridge_service), weak_factory_(this) {}
+    ArcBridgeService* arc_bridge_service,
+    ash::DefaultScaleFactorRetriever* retriever)
+    : arc_bridge_service_(arc_bridge_service),
+      default_scale_factor_retriever_(retriever),
+      weak_factory_(this) {}
 
 base::ScopedFD ArcSessionDelegateImpl::ConnectMojo(
     base::ScopedFD socket_fd,
@@ -186,6 +196,15 @@
   return return_fd;
 }
 
+void ArcSessionDelegateImpl::GetLcdDensity(GetLcdDensityCallback callback) {
+  default_scale_factor_retriever_->GetDefaultScaleFactor(base::BindOnce(
+      [](GetLcdDensityCallback callback, float default_scale_factor) {
+        std::move(callback).Run(
+            GetLcdDensityForDeviceScaleFactor(default_scale_factor));
+      },
+      std::move(callback)));
+}
+
 // static
 mojo::ScopedMessagePipeHandle ArcSessionDelegateImpl::ConnectMojoInternal(
     base::ScopedFD socket_fd,
@@ -254,8 +273,10 @@
 
 // static
 std::unique_ptr<ArcSessionImpl::Delegate> ArcSessionImpl::CreateDelegate(
-    ArcBridgeService* arc_bridge_service) {
-  return std::make_unique<ArcSessionDelegateImpl>(arc_bridge_service);
+    ArcBridgeService* arc_bridge_service,
+    ash::DefaultScaleFactorRetriever* retriever) {
+  return std::make_unique<ArcSessionDelegateImpl>(arc_bridge_service,
+                                                  retriever);
 }
 
 ArcSessionImpl::ArcSessionImpl(std::unique_ptr<Delegate> delegate)
@@ -279,12 +300,25 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK_EQ(state_, State::NOT_STARTED);
 
-  state_ = State::STARTING_MINI_INSTANCE;
-  VLOG(2) << "Starting ARC mini instance";
+  state_ = State::WAITING_FOR_LCD_DENSITY;
 
+  VLOG(2) << "Querying the lcd density to start ARC mini instance";
+
+  delegate_->GetLcdDensity(base::BindOnce(&ArcSessionImpl::OnLcdDensity,
+                                          weak_factory_.GetWeakPtr()));
+}
+
+void ArcSessionImpl::OnLcdDensity(int32_t lcd_density) {
+  DCHECK_GT(lcd_density, 0);
+  DCHECK_EQ(state_, State::WAITING_FOR_LCD_DENSITY);
+  state_ = State::STARTING_MINI_INSTANCE;
   login_manager::StartArcMiniContainerRequest request;
   request.set_native_bridge_experiment(
       base::FeatureList::IsEnabled(arc::kNativeBridgeExperimentFeature));
+  request.set_lcd_density(lcd_density);
+
+  VLOG(1) << "Starting ARC mini instance with lcd_density="
+          << request.lcd_density();
 
   chromeos::SessionManagerClient* client = GetSessionManagerClient();
   client->StartArcMiniContainer(
@@ -303,6 +337,7 @@
     case State::NOT_STARTED:
       NOTREACHED();
       break;
+    case State::WAITING_FOR_LCD_DENSITY:
     case State::STARTING_MINI_INSTANCE:
       VLOG(2) << "Requested to upgrade a starting ARC mini instance";
       // OnMiniInstanceStarted() will restart a full instance.
@@ -472,6 +507,9 @@
   arc_bridge_host_.reset();
   switch (state_) {
     case State::NOT_STARTED:
+    case State::WAITING_FOR_LCD_DENSITY:
+      // If |Stop()| is called while waiting for LCD density, it can directly
+      // move to stopped state.
       OnStopped(ArcStopReason::SHUTDOWN);
       return;
     case State::STARTING_MINI_INSTANCE:
@@ -507,7 +545,8 @@
 
 void ArcSessionImpl::StopArcInstance() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(state_ == State::STARTING_MINI_INSTANCE ||
+  DCHECK(state_ == State::WAITING_FOR_LCD_DENSITY ||
+         state_ == State::STARTING_MINI_INSTANCE ||
          state_ == State::RUNNING_MINI_INSTANCE ||
          state_ == State::STARTING_FULL_INSTANCE ||
          state_ == State::CONNECTING_MOJO ||
@@ -618,6 +657,7 @@
 
   switch (state) {
     MAP_STATE(NOT_STARTED);
+    MAP_STATE(WAITING_FOR_LCD_DENSITY);
     MAP_STATE(STARTING_MINI_INSTANCE);
     MAP_STATE(RUNNING_MINI_INSTANCE);
     MAP_STATE(STARTING_FULL_INSTANCE);
diff --git a/components/arc/arc_session_impl.h b/components/arc/arc_session_impl.h
index fbaefe93..f430526 100644
--- a/components/arc/arc_session_impl.h
+++ b/components/arc/arc_session_impl.h
@@ -20,6 +20,10 @@
 #include "chromeos/dbus/session_manager_client.h"
 #include "components/arc/arc_session.h"
 
+namespace ash {
+class DefaultScaleFactorRetriever;
+}
+
 namespace arc {
 
 namespace mojom {
@@ -33,6 +37,8 @@
   //
   // NOT_STARTED
   // -> StartMiniInstance() ->
+  // WAITING_FOR_LCD_DENSITY
+  // -> OnLcdDensity ->
   // STARTING_MINI_INSTANCE
   //   -> OnMiniInstanceStarted() ->
   // RUNNING_MINI_INSTANCE.
@@ -47,6 +53,12 @@
   // state, the state change to STARTING_FULL_INSTANCE is suspended until
   // the state becomes RUNNING_MINI_INSTANCE.
   //
+  // Upon |StartMiniInstance()| call, it queries LCD Density through
+  // Delegate::GetLcdDenstity, and moves to WAITING_FOR_LCD_DENSITY state.  The
+  // query may be made synchronlsly or asynchronosly depending on the
+  // availability of the density information. It then asks SessionManager to
+  // start mini container and moves to STARTING_MINI_INSTANCE state.
+  //
   // At any state, Stop() can be called. It may not immediately stop the
   // instance, but will eventually stop it. The actual stop will be notified
   // via ArcSession::Observer::OnSessionStopped().
@@ -92,6 +104,9 @@
     // ARC is not yet started.
     NOT_STARTED,
 
+    // It's waiting for LCD dnesity to be available.
+    WAITING_FOR_LCD_DENSITY,
+
     // The request to start a mini instance has been sent.
     STARTING_MINI_INSTANCE,
 
@@ -129,6 +144,14 @@
     // Returns a FD which cancels the current connection on close(2).
     virtual base::ScopedFD ConnectMojo(base::ScopedFD socket_fd,
                                        ConnectMojoCallback callback) = 0;
+
+    using GetLcdDensityCallback = base::OnceCallback<void(int32_t)>;
+
+    // Gets the lcd density via callback. The callback may be invoked
+    // immediately if its already available, or called asynchronosly later if
+    // it's not yet available. Calling this method while there is a pending
+    // callback will cancel the pending callback.
+    virtual void GetLcdDensity(GetLcdDensityCallback callback) = 0;
   };
 
   explicit ArcSessionImpl(std::unique_ptr<Delegate> delegate);
@@ -136,7 +159,8 @@
 
   // Returns default delegate implementation used for the production.
   static std::unique_ptr<Delegate> CreateDelegate(
-      ArcBridgeService* arc_bridge_service);
+      ArcBridgeService* arc_bridge_service,
+      ash::DefaultScaleFactorRetriever* retriever);
 
   State GetStateForTesting() { return state_; }
 
@@ -178,6 +202,9 @@
   // deleting |this| because the function calls observers' OnSessionStopped().
   void OnStopped(ArcStopReason reason);
 
+  // LCD density for the device is available.
+  void OnLcdDensity(int32_t lcd_density);
+
   // Checks whether a function runs on the thread where the instance is
   // created.
   THREAD_CHECKER(thread_checker_);
diff --git a/components/arc/arc_session_impl_unittest.cc b/components/arc/arc_session_impl_unittest.cc
index 9bd44c7..c812e39 100644
--- a/components/arc/arc_session_impl_unittest.cc
+++ b/components/arc/arc_session_impl_unittest.cc
@@ -23,6 +23,7 @@
 #include "components/arc/test/fake_arc_bridge_host.h"
 #include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace arc {
@@ -40,7 +41,8 @@
 
 class FakeDelegate : public ArcSessionImpl::Delegate {
  public:
-  FakeDelegate() = default;
+  explicit FakeDelegate(int32_t lcd_density = 160)
+      : lcd_density_(lcd_density) {}
 
   // Emulates to fail Mojo connection establishing. |callback| passed to
   // ConnectMojo will be called with nullptr.
@@ -73,6 +75,19 @@
     return base::ScopedFD(HANDLE_EINTR(open("/dev/null", O_RDONLY)));
   }
 
+  void GetLcdDensity(GetLcdDensityCallback callback) override {
+    if (lcd_density_ > 0)
+      std::move(callback).Run(lcd_density_);
+    else
+      lcd_density_callback_ = std::move(callback);
+  }
+
+  void SetLcdDensity(int32_t lcd_density) {
+    lcd_density_ = lcd_density;
+    ASSERT_TRUE(!lcd_density_callback_.is_null());
+    std::move(lcd_density_callback_).Run(lcd_density_);
+  }
+
  private:
   void PostCallback(ConnectMojoCallback callback) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -82,9 +97,11 @@
             success_ ? std::make_unique<FakeArcBridgeHost>() : nullptr));
   }
 
+  int32_t lcd_density_ = 0;
   bool success_ = true;
   bool suspend_ = false;
   ConnectMojoCallback pending_callback_;
+  GetLcdDensityCallback lcd_density_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeDelegate);
 };
@@ -177,9 +194,10 @@
   }
 
   std::unique_ptr<ArcSessionImpl, ArcSessionDeleter> CreateArcSession(
-      std::unique_ptr<ArcSessionImpl::Delegate> delegate = nullptr) {
+      std::unique_ptr<ArcSessionImpl::Delegate> delegate = nullptr,
+      int32_t lcd_density = 160) {
     if (!delegate)
-      delegate = std::make_unique<FakeDelegate>();
+      delegate = std::make_unique<FakeDelegate>(lcd_density);
     return std::unique_ptr<ArcSessionImpl, ArcSessionDeleter>(
         new ArcSessionImpl(std::move(delegate)));
   }
@@ -676,6 +694,58 @@
       GetSessionManagerClient()
           ->last_upgrade_arc_request()
           .supervision_transition());
+  EXPECT_EQ(160, GetSessionManagerClient()
+                     ->last_start_arc_mini_container_request()
+                     .lcd_density());
+}
+
+TEST_F(ArcSessionImplTest, StartArcMiniContainerWithDensity) {
+  auto arc_session = CreateArcSession(nullptr, 240);
+  arc_session->StartMiniInstance();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(ArcSessionImpl::State::RUNNING_MINI_INSTANCE,
+            arc_session->GetStateForTesting());
+  EXPECT_EQ(240, GetSessionManagerClient()
+                     ->last_start_arc_mini_container_request()
+                     .lcd_density());
+}
+
+TEST_F(ArcSessionImplTest, StartArcMiniContainerWithDensityAsync) {
+  auto delegate = std::make_unique<FakeDelegate>(0);
+  auto* delegate_ptr = delegate.get();
+  auto arc_session = CreateArcSession(std::move(delegate));
+  arc_session->StartMiniInstance();
+  EXPECT_EQ(ArcSessionImpl::State::WAITING_FOR_LCD_DENSITY,
+            arc_session->GetStateForTesting());
+  delegate_ptr->SetLcdDensity(240);
+  EXPECT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE,
+            arc_session->GetStateForTesting());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(240, GetSessionManagerClient()
+                     ->last_start_arc_mini_container_request()
+                     .lcd_density());
+}
+
+TEST_F(ArcSessionImplTest, StopWhileWaitingForLcdDensity) {
+  auto delegate = std::make_unique<FakeDelegate>(0);
+  auto arc_session = CreateArcSession(std::move(delegate));
+  arc_session->StartMiniInstance();
+  EXPECT_EQ(ArcSessionImpl::State::WAITING_FOR_LCD_DENSITY,
+            arc_session->GetStateForTesting());
+  arc_session->Stop();
+  EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting());
+}
+
+TEST_F(ArcSessionImplTest, ShutdownWhileWaitingForLcdDensity) {
+  auto delegate = std::make_unique<FakeDelegate>(0);
+  auto arc_session = CreateArcSession(std::move(delegate));
+  arc_session->StartMiniInstance();
+  EXPECT_EQ(ArcSessionImpl::State::WAITING_FOR_LCD_DENSITY,
+            arc_session->GetStateForTesting());
+  arc_session->OnShutdown();
+  EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting());
 }
 
 }  // namespace
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index d93d6df0..efc40632e 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -204,4 +204,21 @@
       chromeos::switches::kArcDataCleanupOnStart);
 }
 
+// static
+int32_t GetLcdDensityForDeviceScaleFactor(float device_scale_factor) {
+  // Keep this consistent with wayland_client.cpp on Android side.
+  // TODO(oshima): Consider sending this through wayland.
+  constexpr float kEpsilon = 0.001;
+  if (std::abs(device_scale_factor - 2.25f) < kEpsilon)
+    return 280;
+  if (std::abs(device_scale_factor - 1.6f) < kEpsilon)
+    return 213;  // TVDPI
+
+  constexpr float kChromeScaleToAndroidScaleRatio = 0.75f;
+  constexpr int32_t kDefaultDensityDpi = 160;
+  return static_cast<int32_t>(
+      std::max(1.0f, device_scale_factor * kChromeScaleToAndroidScaleRatio) *
+      kDefaultDensityDpi);
+}
+
 }  // namespace arc
diff --git a/components/arc/arc_util.h b/components/arc/arc_util.h
index 3a6c323e..cbf7656 100644
--- a/components/arc/arc_util.h
+++ b/components/arc/arc_util.h
@@ -9,6 +9,8 @@
 // outside of ARC, e.g. CommandLine flag, attribute of global data/state,
 // users' preferences, and FeatureList.
 
+#include <stdint.h>
+
 namespace aura {
 class Window;
 }  // namespace aura
@@ -112,6 +114,10 @@
 // TODO(yusukes): Use enum instead of bool.
 void SetArcCpuRestriction(bool do_restrict);
 
+// Returns the Android density that should be used for the given device scale
+// factor used on chrome.
+int32_t GetLcdDensityForDeviceScaleFactor(float device_scale_factor);
+
 }  // namespace arc
 
 #endif  // COMPONENTS_ARC_ARC_UTIL_H_
diff --git a/components/arc/arc_util_unittest.cc b/components/arc/arc_util_unittest.cc
index 3fc9482..4192eae 100644
--- a/components/arc/arc_util_unittest.cc
+++ b/components/arc/arc_util_unittest.cc
@@ -251,5 +251,20 @@
   EXPECT_FALSE(IsPlayStoreAvailable());
 }
 
+TEST_F(ArcUtilTest, ScaleFactorToDensity) {
+  // Test all standard scale factors
+  EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(1.0f));
+  EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(1.25f));
+  EXPECT_EQ(213, GetLcdDensityForDeviceScaleFactor(1.6f));
+  EXPECT_EQ(240, GetLcdDensityForDeviceScaleFactor(2.0f));
+  EXPECT_EQ(280, GetLcdDensityForDeviceScaleFactor(2.25f));
+
+  // Bad scale factors shouldn't blow up.
+  EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(0.5f));
+  EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(-0.1f));
+  EXPECT_EQ(180, GetLcdDensityForDeviceScaleFactor(1.5f));
+  EXPECT_EQ(1200, GetLcdDensityForDeviceScaleFactor(10.f));
+}
+
 }  // namespace
 }  // namespace arc
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 172d095..6393be1 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -112,15 +112,21 @@
 const base::Feature kAutofillGetPaymentsIdentityFromSync{
     "AutofillGetPaymentsIdentityFromSync", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether Autofill Local Card Migration will show result dialogs.
+// When enabled, the local card migration dialog will show the progress
+// and result of the migration after starting the migration. When disabled,
+// there is no feedback for the migration.
 const base::Feature kAutofillLocalCardMigrationShowFeedback{
     "AutofillLocalCardMigrationShowFeedback",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether the manual fill fallback will be present.
+// Controls whether the manual fallback will be present.
 const base::Feature kAutofillManualFallback{"AutofillManualFallback",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether the manual fallback will include addresses and cards.
+const base::Feature kAutofillManualFallbackPhaseTwo{
+    "AutofillManualFallbackPhaseTwo", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kAutofillPreferServerNamePredictions{
     "AutofillPreferServerNamePredictions", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index ec9befa7..08a26ba3 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -43,6 +43,7 @@
 extern const base::Feature kAutofillGetPaymentsIdentityFromSync;
 extern const base::Feature kAutofillLocalCardMigrationShowFeedback;
 extern const base::Feature kAutofillManualFallback;
+extern const base::Feature kAutofillManualFallbackPhaseTwo;
 extern const base::Feature kAutofillPreferServerNamePredictions;
 extern const base::Feature kAutofillNoLocalSaveOnUploadSuccess;
 extern const base::Feature kAutofillPrefilledFields;
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 25579b1..f33199b 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -17,10 +17,12 @@
 void Controller::CreateAndStartForWebContents(
     content::WebContents* web_contents,
     std::unique_ptr<Client> client) {
-  new Controller(web_contents, std::move(client),
-                 WebController::CreateForWebContents(web_contents),
-                 std::make_unique<Service>(client->GetApiKey(),
-                                           web_contents->GetBrowserContext()));
+  // Get the key early since |client| will be invalidated when moved below.
+  const std::string api_key = client->GetApiKey();
+  new Controller(
+      web_contents, std::move(client),
+      WebController::CreateForWebContents(web_contents),
+      std::make_unique<Service>(api_key, web_contents->GetBrowserContext()));
 }
 
 Service* Controller::GetService() {
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 7489eb5..f4d1a9b4 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -125,7 +125,8 @@
   Controller* controller_;
 };
 
-TEST_F(ControllerTest, FetchAndRunScripts) {
+// Temporarily disabled because of http://crbug/882901
+TEST_F(ControllerTest, DISABLED_FetchAndRunScripts) {
   // Going to the URL triggers a whole flow:
   // 1. loading scripts
   SupportsScriptResponseProto script_response;
@@ -159,7 +160,8 @@
   SimulateNavigateToUrl(GURL("http://a.example.com/path"));
 }
 
-TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
+// Temporarily disabled because of http://crbug/882901
+TEST_F(ControllerTest, DISABLED_RefreshScriptWhenDomainChanges) {
   EXPECT_CALL(*mock_service_,
               OnGetScriptsForUrl(Eq(GURL("http://a.example.com/path1")), _))
       .WillOnce(RunOnceCallback<1>(true, ""));
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 8fd8b65..2c077b2 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -236,7 +236,6 @@
 
 void ProfileSyncService::Initialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  sync_client_->Initialize();
 
   syncer::ModelTypeStoreService* model_type_store_service =
       sync_client_->GetModelTypeStoreService();
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc
index 8b0edef1..4902d87 100644
--- a/components/crash/content/app/crashpad_win.cc
+++ b/components/crash/content/app/crashpad_win.cc
@@ -163,20 +163,12 @@
 
 // We need to prevent ICF from folding DumpProcessForHungInputThread(),
 // together, since that makes them indistinguishable in crash dumps.
-// We do this by making the function body unique, and prevent optimization
-// from shuffling things around.
-MSVC_DISABLE_OPTIMIZE()
-MSVC_PUSH_DISABLE_WARNING(4748)
-
-DWORD WINAPI DumpProcessForHungInputThread(void* param) {
+// We do this by making the function body unique, and turning off inlining.
+NOINLINE DWORD WINAPI DumpProcessForHungInputThread(void* param) {
   DumpWithoutCrashing();
   return 0;
 }
 
-MSVC_POP_WARNING()
-MSVC_ENABLE_OPTIMIZE()
-
-
 #if defined(ARCH_CPU_X86_64)
 
 static int CrashForExceptionInNonABICompliantCodeRange(
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc
index c43881a..a6c55e4 100644
--- a/components/domain_reliability/quic_error_mapping.cc
+++ b/components/domain_reliability/quic_error_mapping.cc
@@ -289,6 +289,7 @@
     {quic::QUIC_INVALID_PATH_CHALLENGE_DATA,
      "quic.invalid.path_challenge_data"},
     {quic::QUIC_INVALID_PATH_RESPONSE_DATA, "quic.invalid.path_response_data"},
+    {quic::QUIC_INVALID_MESSAGE_DATA, "quic.invalid.message_data"},
 
     // No error. Used as bound while iterating.
     {quic::QUIC_LAST_ERROR, "quic.last_error"}};
diff --git a/components/domain_reliability/util.cc b/components/domain_reliability/util.cc
index c79802a..9d5f16cb 100644
--- a/components/domain_reliability/util.cc
+++ b/components/domain_reliability/util.cc
@@ -132,6 +132,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_42:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       return "QUIC";
     case net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS:
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index bb9a0039a..978fcf9c 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -2307,7 +2307,8 @@
   ResumeMode mode = GetResumeMode();
   if (mode == ResumeMode::IMMEDIATE_RESTART ||
       mode == ResumeMode::USER_RESTART) {
-    DCHECK(GetFullPath().empty());
+    LOG_IF(ERROR, !GetFullPath().empty())
+        << "Download full path should be empty before resumption";
     destination_info_.received_bytes = 0;
     last_modified_time_.clear();
     etag_.clear();
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index 9c88747..0c0e730 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -4241,9 +4241,9 @@
   EXPECT_EQ(base::ASCIIToUTF16("baz.com/"),
             FormatUrlForRedirectComparison(url2));
 
-  // Tests that the formatter removes repeated trivial subdomains.
+  // Tests that the formatter only removes the first subdomain.
   GURL url3("http://www.www.baz.com/");
-  EXPECT_EQ(base::ASCIIToUTF16("baz.com/"),
+  EXPECT_EQ(base::ASCIIToUTF16("www.baz.com/"),
             FormatUrlForRedirectComparison(url3));
 }
 
diff --git a/components/image_fetcher/core/BUILD.gn b/components/image_fetcher/core/BUILD.gn
index f9d5576..21373f9 100644
--- a/components/image_fetcher/core/BUILD.gn
+++ b/components/image_fetcher/core/BUILD.gn
@@ -14,7 +14,9 @@
     "request_metadata.cc",
     "request_metadata.h",
   ]
-
+  deps = [
+    "//components/image_fetcher/core/storage",
+  ]
   public_deps = [
     "//base",
     "//components/data_use_measurement/core",
@@ -34,7 +36,6 @@
     "mock_image_fetcher.cc",
     "mock_image_fetcher.h",
   ]
-
   public_deps = [
     ":core",
     "//services/network:test_support",
diff --git a/components/image_fetcher/core/storage/BUILD.gn b/components/image_fetcher/core/storage/BUILD.gn
new file mode 100644
index 0000000..c759910
--- /dev/null
+++ b/components/image_fetcher/core/storage/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+static_library("storage") {
+  sources = [
+    "image_cache.cc",
+    "image_cache.h",
+    "image_data_store.h",
+    "image_data_store_disk.cc",
+    "image_data_store_disk.h",
+    "image_metadata_store.h",
+    "image_metadata_store_leveldb.cc",
+    "image_metadata_store_leveldb.h",
+    "image_store_types.h",
+  ]
+  deps = [
+    "//components/image_fetcher/core/storage/proto",
+    "//components/leveldb_proto",
+    "//net",
+  ]
+  public_deps = [
+    "//base",
+  ]
+}
diff --git a/components/image_fetcher/core/storage/DEPS b/components/image_fetcher/core/storage/DEPS
new file mode 100644
index 0000000..ff9622f
--- /dev/null
+++ b/components/image_fetcher/core/storage/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/leveldb_proto",
+]
diff --git a/components/image_fetcher/core/storage/image_cache.cc b/components/image_fetcher/core/storage/image_cache.cc
new file mode 100644
index 0000000..e524f7d
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_cache.cc
@@ -0,0 +1,33 @@
+// 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 "components/image_fetcher/core/storage/image_cache.h"
+
+#include <utility>
+
+#include "base/time/time.h"
+#include "components/image_fetcher/core/storage/image_data_store.h"
+#include "components/image_fetcher/core/storage/image_metadata_store.h"
+
+namespace image_fetcher {
+
+// TODO(wylieb): Implement method stubs.
+// TODO(wylieb): Queue requests made before storage is ready.
+ImageCache::ImageCache(std::unique_ptr<ImageDataStore> data_store,
+                       std::unique_ptr<ImageMetadataStore> metadata_store)
+    : data_store_(std::move(data_store)),
+      metadata_store_(std::move(metadata_store)),
+      weak_ptr_factory_(this) {}
+
+ImageCache::~ImageCache() = default;
+
+void ImageCache::SaveImage(const std::string& url,
+                           const std::string& image_data) {}
+
+void ImageCache::LoadImage(const std::string& url, ImageDataCallback callback) {
+}
+
+void ImageCache::DeleteImage(const std::string& url) {}
+
+}  // namespace image_fetcher
diff --git a/components/image_fetcher/core/storage/image_cache.h b/components/image_fetcher/core/storage/image_cache.h
new file mode 100644
index 0000000..257e0ea
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_cache.h
@@ -0,0 +1,47 @@
+// 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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_CACHE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_CACHE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "components/image_fetcher/core/storage/image_store_types.h"
+
+namespace image_fetcher {
+
+class ImageDataStore;
+class ImageMetadataStore;
+
+// Persist image meta/data via the given implementations of ImageDataStore and
+// ImageMetadataStore.
+class ImageCache {
+  ImageCache(std::unique_ptr<ImageDataStore> data_storage,
+             std::unique_ptr<ImageMetadataStore> metadata_storage);
+  ~ImageCache();
+
+  // Adds or updates the image data for the |url|. If the class hasn't been
+  // initialized yet, the call is queued.
+  void SaveImage(const std::string& url, const std::string& image_data);
+
+  // Loads the image data for the |url| and passes it to |callback|.
+  void LoadImage(const std::string& url, ImageDataCallback callback);
+
+  // Deletes the image data for the |url|.
+  void DeleteImage(const std::string& url);
+
+ private:
+  std::unique_ptr<ImageDataStore> data_store_;
+  std::unique_ptr<ImageMetadataStore> metadata_store_;
+
+  base::WeakPtrFactory<ImageCache> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageCache);
+};
+
+}  // namespace image_fetcher
+
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_CACHE_H_
diff --git a/components/image_fetcher/core/storage/image_data_store.h b/components/image_fetcher/core/storage/image_data_store.h
new file mode 100644
index 0000000..39f235ad
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_data_store.h
@@ -0,0 +1,46 @@
+// 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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_H_
+
+#include <string>
+
+#include "components/image_fetcher/core/storage/image_store_types.h"
+
+namespace image_fetcher {
+
+// Interface for an object capable of saving/loading image data.
+class ImageDataStore {
+ public:
+  virtual ~ImageDataStore() = default;
+
+  // Initialize this store. If calls are made to the class before the
+  // initialization has completed, they are ignored. Ignored requests will
+  // return empty data. It's the responsibility of the caller to check for
+  // initialization before calling.
+  virtual void Initialize(base::OnceClosure callback) = 0;
+
+  // Returns true if initialization has finished successfully, else false.
+  // While this is false, initialization may have already started.
+  virtual bool IsInitialized() = 0;
+
+  // Adds or updates the image data for the |key|.
+  virtual void SaveImage(const std::string& key,
+                         const std::string& image_data) = 0;
+
+  // Loads the image data for the |key| and passes it to |callback|. If the
+  // image isn't available, empty data will be returned.
+  virtual void LoadImage(const std::string& key,
+                         ImageDataCallback callback) = 0;
+
+  // Deletes the image data for the |key|.
+  virtual void DeleteImage(const std::string& key) = 0;
+
+  // Returns all the key this store has.
+  virtual void GetAllKeys(KeysCallback callback) = 0;
+};
+}  // namespace image_fetcher
+
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_H_
diff --git a/components/image_fetcher/core/storage/image_data_store_disk.cc b/components/image_fetcher/core/storage/image_data_store_disk.cc
new file mode 100644
index 0000000..1c7c90d
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_data_store_disk.cc
@@ -0,0 +1,34 @@
+// 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 "components/image_fetcher/core/storage/image_data_store_disk.h"
+
+namespace image_fetcher {
+
+// TODO(wylieb): Implement method stubs.
+ImageDataStoreDisk::ImageDataStoreDisk(const std::string& storage_path)
+    : initialzation_status_(InitializationStatus::UNINITIALIZED),
+      storage_path_(storage_path),
+      weak_ptr_factory_(this) {}
+
+ImageDataStoreDisk::~ImageDataStoreDisk() = default;
+
+void ImageDataStoreDisk::Initialize(base::OnceClosure callback) {}
+
+bool ImageDataStoreDisk::IsInitialized() {
+  return initialzation_status_ == InitializationStatus::INITIALIZED ||
+         initialzation_status_ == InitializationStatus::INIT_FAILURE;
+}
+
+void ImageDataStoreDisk::SaveImage(const std::string& key,
+                                   const std::string& image_data) {}
+
+void ImageDataStoreDisk::LoadImage(const std::string& key,
+                                   ImageDataCallback callback) {}
+
+void ImageDataStoreDisk::DeleteImage(const std::string& key) {}
+
+void ImageDataStoreDisk::GetAllKeys(KeysCallback callback) {}
+
+}  // namespace image_fetcher
diff --git a/components/image_fetcher/core/storage/image_data_store_disk.h b/components/image_fetcher/core/storage/image_data_store_disk.h
new file mode 100644
index 0000000..f5416c4
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_data_store_disk.h
@@ -0,0 +1,44 @@
+// 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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_DISK_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_DISK_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/image_fetcher/core/storage/image_data_store.h"
+#include "components/image_fetcher/core/storage/image_store_types.h"
+
+namespace image_fetcher {
+
+// Stores image data on disk.
+class ImageDataStoreDisk : public ImageDataStore {
+ public:
+  // Stores the image data under the given |storage_path|.
+  explicit ImageDataStoreDisk(const std::string& storage_path);
+  ~ImageDataStoreDisk() override;
+
+  // ImageDataStorage:
+  void Initialize(base::OnceClosure callback) override;
+  bool IsInitialized() override;
+  void SaveImage(const std::string& key, const std::string& data) override;
+  void LoadImage(const std::string& key, ImageDataCallback callback) override;
+  void DeleteImage(const std::string& key) override;
+  void GetAllKeys(KeysCallback callback) override;
+
+ private:
+  InitializationStatus initialzation_status_;
+
+  // Path to where the image data will be stored.
+  std::string storage_path_;
+
+  base::WeakPtrFactory<ImageDataStoreDisk> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageDataStoreDisk);
+};
+}  // namespace image_fetcher
+
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_DISK_H_
diff --git a/components/image_fetcher/core/storage/image_metadata_store.h b/components/image_fetcher/core/storage/image_metadata_store.h
new file mode 100644
index 0000000..a69f5be
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_metadata_store.h
@@ -0,0 +1,61 @@
+// 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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_H_
+
+#include <string>
+
+#include "base/time/time.h"
+#include "components/image_fetcher/core/storage/image_store_types.h"
+
+namespace image_fetcher {
+
+// Interface for an object capable of saving/loading image metadata.
+class ImageMetadataStore {
+ public:
+  virtual ~ImageMetadataStore() = default;
+
+  // Initialize this store. If calls are made to the class before the
+  // initialization has completed, they are ignored. Ignored requests won't do
+  // any meaningful work. It's the responsibility of the caller to check for
+  // initialization before calling.
+  virtual void Initialize(base::OnceClosure callback) = 0;
+
+  // Returns true if initialization has finished successfully, else false.
+  // While this is false, initialization may have already started.
+  virtual bool IsInitialized() = 0;
+
+  // Adds or updates the image metadata for the |key|.
+  virtual void SaveImageMetadata(const std::string& key,
+                                 const size_t data_size) = 0;
+
+  // Deletes the image metadata for the |key|.
+  virtual void DeleteImageMetadata(const std::string& key) = 0;
+
+  // Returns true if metadata is stored for |key|. Updates |last_used_time| for
+  // the given |key| if it exists.
+  virtual void CheckExistsAndUpdate(const std::string& key,
+                                    ImageStoreOperationCallback callback) = 0;
+
+  // Returns all the keys this store has.
+  virtual void GetAllKeys(KeysCallback callback) = 0;
+
+  // Deletes all metadata that's been cached before the boundary given as
+  // |expiration_time|.
+  void EvictImageMetadata(base::Time expiration_time, KeysCallback callback) {
+    EvictImageMetadata(expiration_time, /* Max size_t */ -1,
+                       std::move(callback));
+  }
+
+  // Deletes all metadata that's been cached before the boundary given as
+  // |expiration_time|. Evicts other metadata until there are |bytes_left|
+  // in storage.
+  virtual void EvictImageMetadata(base::Time expiration_time,
+                                  const size_t bytes_left,
+                                  KeysCallback callback) = 0;
+};
+}  // namespace image_fetcher
+
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_H_
diff --git a/components/image_fetcher/core/storage/image_metadata_store_leveldb.cc b/components/image_fetcher/core/storage/image_metadata_store_leveldb.cc
new file mode 100644
index 0000000..5d8e795
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_metadata_store_leveldb.cc
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/image_fetcher/core/storage/image_metadata_store_leveldb.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "components/image_fetcher/core/storage/proto/cached_image_metadata.pb.h"
+#include "components/leveldb_proto/proto_database_impl.h"
+
+namespace image_fetcher {
+
+// TODO(wylieb): Implement method stubs.
+ImageMetadataStoreLevelDB::ImageMetadataStoreLevelDB(
+    const base::FilePath& database_dir)
+    : ImageMetadataStoreLevelDB(database_dir, nullptr) {}
+
+ImageMetadataStoreLevelDB::ImageMetadataStoreLevelDB(
+    const base::FilePath& database_dir,
+    std::unique_ptr<leveldb_proto::ProtoDatabase<CachedImageMetadataProto>>
+        database)
+    : initialzation_status_(InitializationStatus::UNINITIALIZED),
+      database_(std::move(database)),
+      weak_ptr_factory_(this) {}
+
+ImageMetadataStoreLevelDB::~ImageMetadataStoreLevelDB() = default;
+
+void ImageMetadataStoreLevelDB::Initialize(base::OnceClosure callback) {}
+
+bool ImageMetadataStoreLevelDB::IsInitialized() {
+  return initialzation_status_ == InitializationStatus::INITIALIZED ||
+         initialzation_status_ == InitializationStatus::INIT_FAILURE;
+}
+
+void ImageMetadataStoreLevelDB::SaveImageMetadata(const std::string& key,
+                                                  const size_t data_size) {}
+
+void ImageMetadataStoreLevelDB::DeleteImageMetadata(const std::string& key) {}
+
+void ImageMetadataStoreLevelDB::CheckExistsAndUpdate(
+    const std::string& key,
+    ImageStoreOperationCallback callback) {}
+
+void ImageMetadataStoreLevelDB::GetAllKeys(KeysCallback callback) {}
+
+void ImageMetadataStoreLevelDB::EvictImageMetadata(base::Time expiration_time,
+                                                   const size_t bytes_left,
+                                                   KeysCallback callback) {}
+
+}  // namespace image_fetcher
diff --git a/components/image_fetcher/core/storage/image_metadata_store_leveldb.h b/components/image_fetcher/core/storage/image_metadata_store_leveldb.h
new file mode 100644
index 0000000..56b7c77
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_metadata_store_leveldb.h
@@ -0,0 +1,62 @@
+// 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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_LEVELDB_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_LEVELDB_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "components/image_fetcher/core/storage/image_metadata_store.h"
+#include "components/image_fetcher/core/storage/image_store_types.h"
+#include "components/leveldb_proto/proto_database.h"
+
+namespace image_fetcher {
+
+class CachedImageMetadataProto;
+
+// Stores image metadata in leveldb.
+class ImageMetadataStoreLevelDB : public ImageMetadataStore {
+ public:
+  // Initializes the database with |database_dir|.
+  ImageMetadataStoreLevelDB(const base::FilePath& database_dir);
+
+  // Initializes the database with |database_dir|. Creates storage using the
+  // given |image_database| for local storage. Useful for testing.
+  ImageMetadataStoreLevelDB(
+      const base::FilePath& database_dir,
+      std::unique_ptr<leveldb_proto::ProtoDatabase<CachedImageMetadataProto>>
+          database);
+  ~ImageMetadataStoreLevelDB() override;
+
+  // ImageMetadataStorage:
+  void Initialize(base::OnceClosure callback) override;
+  bool IsInitialized() override;
+  void SaveImageMetadata(const std::string& key,
+                         const size_t data_size) override;
+  void DeleteImageMetadata(const std::string& key) override;
+  void CheckExistsAndUpdate(const std::string& key,
+                            ImageStoreOperationCallback callback) override;
+  void GetAllKeys(KeysCallback callback) override;
+  void EvictImageMetadata(base::Time expiration_time,
+                          const size_t bytes_left,
+                          KeysCallback callback) override;
+
+ private:
+  InitializationStatus initialzation_status_;
+
+  std::unique_ptr<leveldb_proto::ProtoDatabase<CachedImageMetadataProto>>
+      database_;
+
+  base::WeakPtrFactory<ImageMetadataStoreLevelDB> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageMetadataStoreLevelDB);
+};
+
+}  // namespace image_fetcher
+
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_LEVELDB_H_
diff --git a/components/image_fetcher/core/storage/image_store_types.h b/components/image_fetcher/core/storage/image_store_types.h
new file mode 100644
index 0000000..b90edacc
--- /dev/null
+++ b/components/image_fetcher/core/storage/image_store_types.h
@@ -0,0 +1,34 @@
+// 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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_STORE_TYPES_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_STORE_TYPES_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+
+namespace image_fetcher {
+
+// Represents the initialization status of a image storage module.
+enum class InitializationStatus {
+  UNINITIALIZED,
+  INITIALIZED,
+  INIT_FAILURE,
+};
+
+// Returns the resulting raw image data as a std::string. Data will be returned
+// using move semantics.
+using ImageDataCallback = base::OnceCallback<void(std::string)>;
+
+// Returns bool success when the underlying storage completes an operation.
+using ImageStoreOperationCallback = base::OnceCallback<void(bool)>;
+
+// Returns a vector of keys.
+using KeysCallback = base::OnceCallback<void(std::vector<std::string>)>;
+
+}  // namespace image_fetcher
+
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_STORE_TYPES_H_
diff --git a/components/image_fetcher/core/storage/proto/BUILD.gn b/components/image_fetcher/core/storage/proto/BUILD.gn
new file mode 100644
index 0000000..4165d22
--- /dev/null
+++ b/components/image_fetcher/core/storage/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  sources = [
+    "cached_image_metadata.proto",
+  ]
+}
diff --git a/components/image_fetcher/core/storage/proto/cached_image_metadata.proto b/components/image_fetcher/core/storage/proto/cached_image_metadata.proto
new file mode 100644
index 0000000..ac48f328
--- /dev/null
+++ b/components/image_fetcher/core/storage/proto/cached_image_metadata.proto
@@ -0,0 +1,25 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package image_fetcher;
+
+message CachedImageMetadataProto {
+  // The key for the source image.
+  optional string key = 1;
+
+  // The time which the entry was created at. Used for garbage collection.
+  optional int64 creation_time = 2;
+
+  // The time which the entry was last used. Used for LRU eviction.
+  optional int64 last_used_time = 3;
+
+  // Size of the image data. Used to decide when to stop evictions after a
+  // certain amount of space has been freed. Is not used to decide the order in
+  // which images are evicted.
+  optional int64 data_size = 4;
+}
diff --git a/components/metrics/single_sample_metrics_factory_impl_unittest.cc b/components/metrics/single_sample_metrics_factory_impl_unittest.cc
index 7362085..8af6441 100644
--- a/components/metrics/single_sample_metrics_factory_impl_unittest.cc
+++ b/components/metrics/single_sample_metrics_factory_impl_unittest.cc
@@ -125,6 +125,7 @@
   base::RunLoop().RunUntilIdle();
   tester.ExpectUniqueSample(kMetricName, kLastSample, 1);
 
+#if 0  // TODO(crbug.com/836238): Temporarily disabled for field crash test.
   // Verify construction implicitly by requesting a histogram with the same
   // parameters; this test relies on the fact that histogram objects are unique
   // per name. Different parameters will result in a Dummy histogram returned.
@@ -135,6 +136,7 @@
             base::Histogram::FactoryGet(
                 kMetricName, kMin, kMax, kBucketCount,
                 base::HistogramBase::kUmaTargetedHistogramFlag));
+#endif
 }
 
 TEST_F(SingleSampleMetricsFactoryImplTest, MultithreadedMetrics) {
diff --git a/components/neterror/resources/neterror.html b/components/neterror/resources/neterror.html
index 1aecd6812e..dc1a2e7 100644
--- a/components/neterror/resources/neterror.html
+++ b/components/neterror/resources/neterror.html
@@ -109,7 +109,7 @@
             jscontent="msg" jsvalues=".disabledText:disabledMsg">
         </button>
       </div>
-      <button id="details-button" class="text-button small-link"
+      <button id="details-button" class="secondary-button text-button small-link"
          onclick="detailsButtonClick(); toggleHelpBox()" jscontent="details"
          jsdisplay="(suggestionsDetails && suggestionsDetails.length > 0) || diagnose"
          jsvalues=".detailsText:details; .hideDetailsText:hideDetails;"></button>
diff --git a/components/offline_pages/core/prefetch/generate_page_bundle_request.cc b/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
index c0c2f351..ea2270f2 100644
--- a/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
+++ b/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
@@ -51,7 +51,7 @@
 
 void GeneratePageBundleRequest::OnCompleted(PrefetchRequestStatus status,
                                             const std::string& data) {
-  if (status != PrefetchRequestStatus::SUCCESS) {
+  if (status != PrefetchRequestStatus::kSuccess) {
     std::move(callback_).Run(status, std::string(),
                              std::vector<RenderPageInfo>());
     return;
@@ -60,12 +60,12 @@
   std::vector<RenderPageInfo> pages;
   std::string operation_name = ParseOperationResponse(data, &pages);
   if (operation_name.empty()) {
-    std::move(callback_).Run(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+    std::move(callback_).Run(PrefetchRequestStatus::kShouldRetryWithBackoff,
                              std::string(), std::vector<RenderPageInfo>());
     return;
   }
 
-  std::move(callback_).Run(PrefetchRequestStatus::SUCCESS, operation_name,
+  std::move(callback_).Run(PrefetchRequestStatus::kSuccess, operation_name,
                            pages);
 }
 
diff --git a/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc b/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
index 8e5ed31..c99ca90 100644
--- a/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
+++ b/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
@@ -118,7 +118,7 @@
   RespondWithData("");
   RunUntilIdle();
 
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, status);
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff, status);
   EXPECT_TRUE(operation_name.empty());
   EXPECT_TRUE(pages.empty());
 }
@@ -137,7 +137,7 @@
   RespondWithData("Some invalid data");
   RunUntilIdle();
 
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, status);
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff, status);
   EXPECT_TRUE(operation_name.empty());
   EXPECT_TRUE(pages.empty());
 }
diff --git a/components/offline_pages/core/prefetch/get_operation_request.cc b/components/offline_pages/core/prefetch/get_operation_request.cc
index 09465e6..df86e24 100644
--- a/components/offline_pages/core/prefetch/get_operation_request.cc
+++ b/components/offline_pages/core/prefetch/get_operation_request.cc
@@ -34,7 +34,7 @@
     const std::string& assigned_operation_name,
     PrefetchRequestStatus status,
     const std::string& data) {
-  if (status != PrefetchRequestStatus::SUCCESS) {
+  if (status != PrefetchRequestStatus::kSuccess) {
     std::move(callback_).Run(status, assigned_operation_name,
                              std::vector<RenderPageInfo>());
     return;
@@ -43,13 +43,13 @@
   std::vector<RenderPageInfo> pages;
   std::string found_operation_name = ParseOperationResponse(data, &pages);
   if (found_operation_name.empty()) {
-    std::move(callback_).Run(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+    std::move(callback_).Run(PrefetchRequestStatus::kShouldRetryWithBackoff,
                              assigned_operation_name,
                              std::vector<RenderPageInfo>());
     return;
   }
 
-  std::move(callback_).Run(PrefetchRequestStatus::SUCCESS,
+  std::move(callback_).Run(PrefetchRequestStatus::kSuccess,
                            assigned_operation_name, pages);
 }
 
diff --git a/components/offline_pages/core/prefetch/get_operation_request_unittest.cc b/components/offline_pages/core/prefetch/get_operation_request_unittest.cc
index 491de38d..5a680c4 100644
--- a/components/offline_pages/core/prefetch/get_operation_request_unittest.cc
+++ b/components/offline_pages/core/prefetch/get_operation_request_unittest.cc
@@ -101,7 +101,7 @@
   RespondWithData("");
   RunUntilIdle();
 
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, status);
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff, status);
   EXPECT_EQ(std::string(kTestOperationName), operation_name);
   EXPECT_TRUE(pages.empty());
 }
@@ -119,7 +119,7 @@
   RespondWithData("Some invalid data");
   RunUntilIdle();
 
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, status);
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff, status);
   EXPECT_EQ(std::string(kTestOperationName), operation_name);
   EXPECT_TRUE(pages.empty());
 }
diff --git a/components/offline_pages/core/prefetch/prefetch_background_task.h b/components/offline_pages/core/prefetch/prefetch_background_task.h
index 58592de..80ac974 100644
--- a/components/offline_pages/core/prefetch/prefetch_background_task.h
+++ b/components/offline_pages/core/prefetch/prefetch_background_task.h
@@ -19,6 +19,7 @@
 
   // Tells the system how to reschedule the running of next background task when
   // this background task completes.
+  // Overridden for testing only.
   virtual void SetReschedule(PrefetchBackgroundTaskRescheduleType type);
 
   PrefetchBackgroundTaskRescheduleType reschedule_type() const {
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index 53ee2ad..4681183 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -283,22 +283,24 @@
   task_queue_.AddTask(std::make_unique<PageBundleUpdateTask>(
       prefetch_store, this, operation_name, pages));
 
-  if (background_task_ && status != PrefetchRequestStatus::SUCCESS) {
+  if (background_task_ && status != PrefetchRequestStatus::kSuccess) {
     PrefetchBackgroundTaskRescheduleType reschedule_type =
         PrefetchBackgroundTaskRescheduleType::NO_RESCHEDULE;
     switch (status) {
-      case PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF:
+      case PrefetchRequestStatus::kShouldRetryWithBackoff:
         reschedule_type =
             PrefetchBackgroundTaskRescheduleType::RESCHEDULE_WITH_BACKOFF;
         break;
-      case PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF:
+      case PrefetchRequestStatus::kShouldRetryWithoutBackoff:
         reschedule_type =
             PrefetchBackgroundTaskRescheduleType::RESCHEDULE_WITHOUT_BACKOFF;
         break;
-      case PrefetchRequestStatus::SHOULD_SUSPEND:
+      case PrefetchRequestStatus::kShouldSuspendForbidden:
+      case PrefetchRequestStatus::kShouldSuspendNotImplemented:
+      case PrefetchRequestStatus::kShouldSuspendBlockedByAdministrator:
         reschedule_type = PrefetchBackgroundTaskRescheduleType::SUSPEND;
         break;
-      default:
+      case PrefetchRequestStatus::kSuccess:
         NOTREACHED();
         break;
     }
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
index a8a1932..3b7ae60 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
@@ -140,7 +140,7 @@
     }
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::BindOnce(std::move(callback), PrefetchRequestStatus::SUCCESS,
+        base::BindOnce(std::move(callback), PrefetchRequestStatus::kSuccess,
                        kOperationName, pages));
   }
 
diff --git a/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc b/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc
index 7237d7210..d0aa4c6 100644
--- a/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc
@@ -32,14 +32,12 @@
 
 void RecordGetOperationStatusUma(PrefetchRequestStatus status) {
   UMA_HISTOGRAM_ENUMERATION(
-      "OfflinePages.Prefetching.ServiceGetOperationStatus", status,
-      PrefetchRequestStatus::COUNT);
+      "OfflinePages.Prefetching.ServiceGetOperationStatus", status);
 }
 
 void RecordGeneratePageBundleStatusUma(PrefetchRequestStatus status) {
   UMA_HISTOGRAM_ENUMERATION(
-      "OfflinePages.Prefetching.ServiceGetPageBundleStatus", status,
-      PrefetchRequestStatus::COUNT);
+      "OfflinePages.Prefetching.ServiceGetPageBundleStatus", status);
 }
 
 PrefetchNetworkRequestFactoryImpl::PrefetchNetworkRequestFactoryImpl(
diff --git a/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
index 837ddab..db8aad0 100644
--- a/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
@@ -230,7 +230,7 @@
   // Ensure that the status was recorded in UMA.
   histogram_tester.ExpectUniqueSample(
       "OfflinePages.Prefetching.ServiceGetOperationStatus",
-      static_cast<int>(PrefetchRequestStatus::SHOULD_SUSPEND), 1);
+      static_cast<int>(PrefetchRequestStatus::kShouldSuspendNotImplemented), 1);
 }
 
 TEST_F(PrefetchNetworkRequestFactoryTest, GeneratePageBundleRequestDoneUMA) {
@@ -245,7 +245,7 @@
                                                    callback.Get());
 
   // Have the test framework call back into the GeneratePageBundleRequestDone
-  // method with an error code that will produce SHOULD_RETRY_WITHOUT_BACKOFF.
+  // method with an error code that will produce kShouldRetryWithoutBackoff.
   RespondWithNetError(net::ERR_NETWORK_CHANGED);
   RunUntilIdle();
 
@@ -256,7 +256,7 @@
   // Ensure that the status was recorded in UMA.
   histogram_tester.ExpectUniqueSample(
       "OfflinePages.Prefetching.ServiceGetPageBundleStatus",
-      static_cast<int>(PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF), 1);
+      static_cast<int>(PrefetchRequestStatus::kShouldRetryWithoutBackoff), 1);
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc b/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc
index eea41d9..63d2c99 100644
--- a/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc
+++ b/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc
@@ -120,26 +120,30 @@
 
   if ((response_code < 200 || response_code > 299) && response_code != -1) {
     DVLOG(1) << "HTTP status: " << response_code;
-    return (response_code == net::HTTP_NOT_IMPLEMENTED)
-               ? PrefetchRequestStatus::SHOULD_SUSPEND
-               : PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF;
+    switch (response_code) {
+      case net::HTTP_NOT_IMPLEMENTED:
+        return PrefetchRequestStatus::kShouldSuspendNotImplemented;
+      case net::HTTP_FORBIDDEN:
+        return PrefetchRequestStatus::kShouldSuspendForbidden;
+      default:
+        return PrefetchRequestStatus::kShouldRetryWithBackoff;
+    }
   }
-
   if (!response_body) {
     int net_error = url_loader_->NetError();
     DVLOG(1) << "Net error: " << net_error;
     return (net_error == net::ERR_BLOCKED_BY_ADMINISTRATOR)
-               ? PrefetchRequestStatus::SHOULD_SUSPEND
-               : PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF;
+               ? PrefetchRequestStatus::kShouldSuspendBlockedByAdministrator
+               : PrefetchRequestStatus::kShouldRetryWithoutBackoff;
   }
 
   if (response_body->empty()) {
     DVLOG(1) << "Failed to get response or empty response";
-    return PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF;
+    return PrefetchRequestStatus::kShouldRetryWithBackoff;
   }
 
   *data = *response_body;
-  return PrefetchRequestStatus::SUCCESS;
+  return PrefetchRequestStatus::kSuccess;
 }
 
-}  // offline_pages
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc b/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc
index f5d9797..493ffe6 100644
--- a/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc
@@ -87,53 +87,55 @@
 }
 
 TEST_F(PrefetchRequestFetcherTest, NetErrors) {
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_SUSPEND,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldSuspendBlockedByAdministrator,
             RunFetcherWithNetError(net::ERR_BLOCKED_BY_ADMINISTRATOR));
 
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithoutBackoff,
             RunFetcherWithNetError(net::ERR_INTERNET_DISCONNECTED));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithoutBackoff,
             RunFetcherWithNetError(net::ERR_NETWORK_CHANGED));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithoutBackoff,
             RunFetcherWithNetError(net::ERR_CONNECTION_RESET));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithoutBackoff,
             RunFetcherWithNetError(net::ERR_CONNECTION_CLOSED));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithoutBackoff,
             RunFetcherWithNetError(net::ERR_CONNECTION_REFUSED));
 }
 
 TEST_F(PrefetchRequestFetcherTest, HttpErrors) {
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_SUSPEND,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldSuspendNotImplemented,
             RunFetcherWithHttpError(net::HTTP_NOT_IMPLEMENTED));
+  EXPECT_EQ(PrefetchRequestStatus::kShouldSuspendForbidden,
+            RunFetcherWithHttpError(net::HTTP_FORBIDDEN));
 
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_BAD_REQUEST));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_UNAUTHORIZED));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_NOT_FOUND));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_CONFLICT));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_INTERNAL_SERVER_ERROR));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_BAD_GATEWAY));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_SERVICE_UNAVAILABLE));
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithHttpError(net::HTTP_GATEWAY_TIMEOUT));
 }
 
 TEST_F(PrefetchRequestFetcherTest, EmptyResponse) {
   std::string data;
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             RunFetcherWithData("", &data));
   EXPECT_TRUE(data.empty());
 }
 
 TEST_F(PrefetchRequestFetcherTest, Success) {
   std::string data;
-  EXPECT_EQ(PrefetchRequestStatus::SUCCESS,
+  EXPECT_EQ(PrefetchRequestStatus::kSuccess,
             RunFetcherWithData("Any data.", &data));
   EXPECT_FALSE(data.empty());
 }
diff --git a/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc b/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc
index 75893bb3..beccfb17 100644
--- a/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc
@@ -283,7 +283,7 @@
 TYPED_TEST_CASE(PrefetchRequestOperationResponseTest, MyTypes);
 
 TYPED_TEST(PrefetchRequestOperationResponseTest, EmptyOperation) {
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             // No error is set for OK. Thus this will cause the operation
             // being filled with only done flag.
             this->SendWithErrorResponse(proto::OK, ""));
@@ -292,21 +292,21 @@
 }
 
 TYPED_TEST(PrefetchRequestOperationResponseTest, ErrorValue) {
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithErrorResponse(proto::UNKNOWN, kErrorMessage));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
 }
 
 TYPED_TEST(PrefetchRequestOperationResponseTest, InvalidTypeUrl) {
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithAnyResponse("foo", ""));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
 }
 
 TYPED_TEST(PrefetchRequestOperationResponseTest, InvalidValue) {
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithAnyResponse(kPageBundleTypeURL, "foo"));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
@@ -314,7 +314,7 @@
 
 TYPED_TEST(PrefetchRequestOperationResponseTest, EmptyPageBundle) {
   proto::PageBundle bundle;
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithPageBundleResponse(bundle));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
@@ -323,7 +323,7 @@
 TYPED_TEST(PrefetchRequestOperationResponseTest, EmptyArchive) {
   proto::PageBundle bundle;
   bundle.add_archives();
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithPageBundleResponse(bundle));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
@@ -334,7 +334,7 @@
   proto::Archive* archive = bundle.add_archives();
   archive->set_body_name(kTestBodyName);
   archive->set_body_length(kTestBodyLength);
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithPageBundleResponse(bundle));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
@@ -345,7 +345,7 @@
   proto::Archive* archive = bundle.add_archives();
   proto::PageInfo* page_info = archive->add_page_infos();
   page_info->set_redirect_url(kTestURL);
-  EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF,
+  EXPECT_EQ(PrefetchRequestStatus::kShouldRetryWithBackoff,
             this->SendWithPageBundleResponse(bundle));
   EXPECT_EQ(this->operation_name(), this->expected_operation_name());
   EXPECT_TRUE(this->pages().empty());
@@ -365,7 +365,7 @@
   page_info->mutable_render_time()->set_seconds(ms_since_epoch / 1000);
   page_info->mutable_render_time()->set_nanos((ms_since_epoch % 1000) *
                                               1000000);
-  EXPECT_EQ(PrefetchRequestStatus::SUCCESS,
+  EXPECT_EQ(PrefetchRequestStatus::kSuccess,
             this->SendWithPageBundleResponse(bundle));
   EXPECT_EQ(kTestOperationName, this->operation_name());
   ASSERT_EQ(1u, this->pages().size());
@@ -411,7 +411,7 @@
   page_info->mutable_render_time()->set_nanos((ms_since_epoch % 1000) *
                                               1000000);
 
-  EXPECT_EQ(PrefetchRequestStatus::SUCCESS,
+  EXPECT_EQ(PrefetchRequestStatus::kSuccess,
             this->SendWithPageBundleResponse(bundle));
   EXPECT_EQ(kTestOperationName, this->operation_name());
   ASSERT_EQ(4u, this->pages().size());
diff --git a/components/offline_pages/core/prefetch/prefetch_types.cc b/components/offline_pages/core/prefetch/prefetch_types.cc
index 23b8e24..98777749 100644
--- a/components/offline_pages/core/prefetch/prefetch_types.cc
+++ b/components/offline_pages/core/prefetch/prefetch_types.cc
@@ -25,16 +25,18 @@
 
 std::string PrefetchEnumToString(PrefetchRequestStatus value) {
   switch (value) {
-    case PrefetchRequestStatus::SUCCESS:
+    case PrefetchRequestStatus::kSuccess:
       return "SUCCESS";
-    case PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF:
+    case PrefetchRequestStatus::kShouldRetryWithoutBackoff:
       return "SHOULD_RETRY_WITHOUT_BACKOFF";
-    case PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF:
+    case PrefetchRequestStatus::kShouldRetryWithBackoff:
       return "SHOULD_RETRY_WITH_BACKOFF";
-    case PrefetchRequestStatus::SHOULD_SUSPEND:
-      return "SHOULD_SUSPEND";
-    case PrefetchRequestStatus::COUNT:
-      return "COUNT";
+    case PrefetchRequestStatus::kShouldSuspendNotImplemented:
+      return "SHOULD_SUSPEND_NOT_IMPLEMENTED";
+    case PrefetchRequestStatus::kShouldSuspendForbidden:
+      return "SHOULD_SUSPEND_FORBIDDEN";
+    case PrefetchRequestStatus::kShouldSuspendBlockedByAdministrator:
+      return "SHOULD_SUSPEND_BLOCKED_BY_ADMINISTRATOR";
   }
   DCHECK(false) << static_cast<int>(value) << " not valid enum value";
 }
diff --git a/components/offline_pages/core/prefetch/prefetch_types.h b/components/offline_pages/core/prefetch/prefetch_types.h
index eedb26f..65d3e3e 100644
--- a/components/offline_pages/core/prefetch/prefetch_types.h
+++ b/components/offline_pages/core/prefetch/prefetch_types.h
@@ -39,20 +39,26 @@
 // in enums.xml which must be adjusted if we add any new values here.
 enum class PrefetchRequestStatus {
   // Request completed successfully.
-  SUCCESS = 0,
+  kSuccess = 0,
   // Request failed due to to local network problem, unrelated to server load
   // levels. The caller will simply reschedule the retry in the next available
   // WiFi window after 15 minutes have passed.
-  SHOULD_RETRY_WITHOUT_BACKOFF = 1,
+  kShouldRetryWithoutBackoff = 1,
   // Request failed probably related to transient server problems. The caller
   // will reschedule the retry with backoff included.
-  SHOULD_RETRY_WITH_BACKOFF = 2,
+  kShouldRetryWithBackoff = 2,
   // Request failed with error indicating that the server no longer knows how
   // to service a request. The caller will prevent network requests for the
   // period of 1 day.
-  SHOULD_SUSPEND = 3,
-  // MAX should always be the last type
-  COUNT = SHOULD_SUSPEND + 1
+  kShouldSuspendNotImplemented = 3,
+  // Request failed with error indicating that the client is forbidden. The
+  // caller will prevent network requests for the period of 1 day.
+  kShouldSuspendForbidden = 4,
+  // The request was blocked by a URL blacklist configured by the domain
+  // administrator.
+  kShouldSuspendBlockedByAdministrator = 5,
+  // kMaxValue should always be the last type.
+  kMaxValue = kShouldSuspendBlockedByAdministrator
 };
 
 // Status indicating the page rendering status in the server.
diff --git a/components/password_manager/sync/browser/sync_username_test_base.cc b/components/password_manager/sync/browser/sync_username_test_base.cc
index 112a5ea..877d828 100644
--- a/components/password_manager/sync/browser/sync_username_test_base.cc
+++ b/components/password_manager/sync/browser/sync_username_test_base.cc
@@ -25,7 +25,19 @@
 
 SyncUsernameTestBase::SyncUsernameTestBase()
     : signin_client_(&prefs_),
-      signin_manager_(&signin_client_, &account_tracker_) {
+#if defined(OS_CHROMEOS)
+      signin_manager_(&signin_client_,
+                      &account_tracker_,
+                      nullptr /* signin_error_controller */) {
+#else
+      token_service_(&prefs_),
+      signin_manager_(&signin_client_,
+                      &token_service_,
+                      &account_tracker_,
+                      nullptr, /* cookie_manager_service */
+                      nullptr, /* signin_error_controller */
+                      signin::AccountConsistencyMethod::kDisabled) {
+#endif
   SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
   AccountTrackerService::RegisterPrefs(prefs_.registry());
   account_tracker_.Initialize(&prefs_, base::FilePath());
@@ -37,11 +49,6 @@
   signin_manager_.SetAuthenticatedAccountInfo("12345", email);
 }
 
-void SyncUsernameTestBase::FakeSignout() {
-  signin_manager_.ClearAuthenticatedAccountId();
-  prefs_.SetString(prefs::kGoogleServicesAccountId, std::string());
-}
-
 // static
 PasswordForm SyncUsernameTestBase::SimpleGaiaForm(const char* username) {
   PasswordForm form;
diff --git a/components/password_manager/sync/browser/sync_username_test_base.h b/components/password_manager/sync/browser/sync_username_test_base.h
index 0717488..d1af98a 100644
--- a/components/password_manager/sync/browser/sync_username_test_base.h
+++ b/components/password_manager/sync/browser/sync_username_test_base.h
@@ -12,13 +12,17 @@
 
 #include "components/autofill/core/common/password_form.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/signin_manager_base.h"
+#include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/fake_sync_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if !defined(OS_CHROMEOS)
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#endif
+
 namespace password_manager {
 
 class SyncUsernameTestBase : public testing::Test {
@@ -28,7 +32,6 @@
 
   // Instruct the signin manager to sign in with |email| or out.
   void FakeSigninAs(const std::string& email);
-  void FakeSignout();
 
   // Produce a sample PasswordForm.
   static autofill::PasswordForm SimpleGaiaForm(const char* username);
@@ -61,21 +64,15 @@
     bool syncing_passwords_;
   };
 
-  class FakeSigninManagerBase : public SigninManagerBase {
-   public:
-    FakeSigninManagerBase(SigninClient* client,
-                          AccountTrackerService* account_tracker_service)
-        : SigninManagerBase(client,
-                            account_tracker_service,
-                            nullptr /* signin_error_controller */) {}
-
-    using SigninManagerBase::ClearAuthenticatedAccountId;
-  };
-
   sync_preferences::TestingPrefServiceSyncable prefs_;
   TestSigninClient signin_client_;
   AccountTrackerService account_tracker_;
-  FakeSigninManagerBase signin_manager_;
+#if defined(OS_CHROMEOS)
+  SigninManagerBase signin_manager_;
+#else
+  FakeProfileOAuth2TokenService token_service_;
+  SigninManager signin_manager_;
+#endif
   LocalFakeSyncService sync_service_;
 };
 
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 17f379e..02e6ac1 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -3064,7 +3064,9 @@
 
           For example, <ph name="EXTENSION_POLICY_EXAMPLE">gbchcmhmhahfdphkhkmpfmihenigjmpp;https://clients2.google.com/service/update2/crx</ph> installs the <ph name="EXTENSION_POLICY_EXAMPLE_EXTENSION_NAME">Chrome Remote Desktop</ph> app from the standard Chrome Web Store "update" URL. For more information about hosting extensions, see: <ph name="LINK_TO_EXTENSION_DOC2">https://developer.chrome.com/extensions/hosting</ph>.
 
-          If this policy is left not set, no apps or extensions are installed automatically and the user can uninstall any app or extension in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.''',
+          If this policy is left not set, no apps or extensions are installed automatically and the user can uninstall any app or extension in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.
+
+          Note that this policy doesn't apply to incognito mode.''',
       'label': '''Extension/App IDs and update URLs to be silently installed''',
       'arc_support': 'Android apps can be force-installed from the Google Admin console using Google Play. They do not use this policy.',
     },
diff --git a/components/security_interstitials/core/browser/resources/interstitial_large.html b/components/security_interstitials/core/browser/resources/interstitial_large.html
index d5c9989..ea36468 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_large.html
+++ b/components/security_interstitials/core/browser/resources/interstitial_large.html
@@ -47,8 +47,8 @@
     </div>
     <div class="nav-wrapper">
       <button id="primary-button">$i18n{primaryButtonText}</button>
-      <button id="proceed-button" class="small-link hidden"></button>
-      <button id="details-button" class="small-link">
+      <button id="proceed-button" class="secondary-button small-link hidden"></button>
+      <button id="details-button" class="secondary-button small-link">
         $i18n{openDetails}
       </button>
     </div>
diff --git a/components/security_interstitials/core/browser/resources/interstitial_safebrowsing.css b/components/security_interstitials/core/browser/resources/interstitial_safebrowsing.css
index e93f34a..98d78624 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_safebrowsing.css
+++ b/components/security_interstitials/core/browser/resources/interstitial_safebrowsing.css
@@ -3,27 +3,51 @@
  * found in the LICENSE file. */
 
 body.safe-browsing {
-  background-color: rgb(206, 52, 38);
+  --google-red-900: rgb(165, 14, 14);
+  --google-red-700: rgb(197, 34, 31);
+  --google-red-600: rgb(217, 48, 37);
+  --google-red-500: rgb(234, 67, 53);
+  --google-red-100: rgb(250, 210, 207);
+  --google-red-50: rgb(252, 232, 230);
+  background-color: var(--google-red-600);
   color: white;
 }
 
 .safe-browsing :-webkit-any(
-    a, #details, #details-button, h1, h2, p, .small-link) {
+    a, #details, #details-button, #proceed-button, h1, h2, p, .small-link) {
   color: white;
 }
 
 .safe-browsing button {
-  background-color: rgba(255, 255, 255, .15);
+  background: white;
+  border-color: white;
+  color: var(--google-red-700);
 }
 
 .safe-browsing button:active {
-  background-color: rgba(255, 255, 255, .25);
+  box-shadow: 0 1px 2px 0 rgba(165, 14, 14, .3),
+      0 2px 6px 2px rgba(165, 14, 14, .15);
 }
 
 .safe-browsing button:hover {
+  background: var(--google-red-50);
+}
+
+.safe-browsing .secondary-button {
+  background-color: var(--google-red-600);
+  border-color: var(--google-red-100);
+  color: white;
+}
+
+.safe-browsing .secondary-button:active {
   box-shadow: 0 2px 3px rgba(0, 0, 0, .5);
 }
 
+.safe-browsing .secondary-button:hover {
+  background-color: var(--google-red-500);
+  border-color: var(--google-red-50);
+}
+
 .safe-browsing .error-code {
   display: none;
 }
@@ -39,21 +63,11 @@
        (min-width: 421px) and (min-height: 240px) and
        (max-height: 560px) {
   body.safe-browsing .nav-wrapper {
-    background: rgb(206, 52, 38);
-    box-shadow: 0 -22px 40px rgb(206, 52, 38);
+    background: var(--google-red-600);
+    box-shadow: 0 -22px 40px var(--google-red-600);
   }
 }
 
-.safe-browsing-billing .small-link {
-  background-color: white;
-  border:none;
-  float: none;
-}
-
-.safe-browsing-billing .small-link:hover {
-  box-shadow: none;
-}
-
 .safe-browsing-billing .icon {
   background-image: -webkit-image-set(
       url(images/1x/triangle_red.png) 1x,
diff --git a/components/security_interstitials/core/common/resources/interstitial_common.css b/components/security_interstitials/core/common/resources/interstitial_common.css
index 85dc02b..e25f12a 100644
--- a/components/security_interstitials/core/common/resources/interstitial_common.css
+++ b/components/security_interstitials/core/common/resources/interstitial_common.css
@@ -11,8 +11,8 @@
   float: right;
   font-size: .875em;
   margin: 0;
-  padding: 10px 24px;
-  transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1);
+  padding: 8px 16px;
+  transition: box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1);
   user-select: none;
 }
 
@@ -36,10 +36,6 @@
   outline: 0;
 }
 
-button:hover {
-  box-shadow: 0 1px 3px rgba(0, 0, 0, .50);
-}
-
 #debugging {
   display: inline;
   overflow: auto;
@@ -63,7 +59,6 @@
 }
 
 #details {
-  color: #696969;
   margin: 0 0 50px;
 }
 
@@ -71,9 +66,16 @@
   margin-top: 20px;
 }
 
-#details-button:hover {
-  box-shadow: inherit;
-  text-decoration: underline;
+.secondary-button:active {
+  border-color: white;
+  box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .3),
+      0 2px 6px 2px rgba(60, 64, 67, .15);
+}
+
+.secondary-button:hover {
+  background: var(--google-gray-50);
+  border-color: var(--google-gray-600);
+  text-decoration: none;
 }
 
 .error-code {
@@ -88,7 +90,7 @@
 }
 
 h1 {
-  color: #333;
+  color: var(--google-gray-900);
   font-size: 1.6em;
   font-weight: normal;
   line-height: 1.25em;
@@ -218,12 +220,15 @@
   .small-link {
     float: none;
     font-size: .825em;
-    font-weight: 400;
+    font-weight: 500;
     margin: 0;
-    text-transform: uppercase;
     width: 100%;
   }
 
+  button {
+    padding: 16px 24px;
+  }
+
   #details {
     margin: 20px 0 20px 0;
   }
@@ -232,7 +237,7 @@
     margin-top: 10px;
   }
 
-  #details-button {
+  .secondary-button:not(.hidden) {
     display: block;
     margin-top: 20px;
     text-align: center;
@@ -259,14 +264,12 @@
  */
 
 @media (max-width: 420px) {
-  #details-button {
+  .nav-wrapper .secondary-button {
     border: 0;
-    margin: 8px 0 0;
-  }
-
-  .secondary-button {
+    margin: 16px 0 0;
     margin-inline-end: 0;
-    margin-top: 16px;
+    padding-bottom: 16px;
+    padding-top: 16px;
   }
 }
 
@@ -303,14 +306,6 @@
     padding-top: 5.5vh;
   }
 
-  #details-button:hover {
-    box-shadow: none;
-  }
-
-  button {
-    padding: 16px 24px;
-  }
-
   button.small-link {
     color: var(--google-blue-600);
   }
@@ -327,9 +322,7 @@
   button.small-link {
     font-family: Roboto-Regular,Helvetica;
     font-size: .933em;
-    font-weight: 600;
     margin: 6px 0;
-    text-transform: uppercase;
     transform: translatez(0);
   }
 
@@ -357,11 +350,6 @@
     transition: none;
   }
 
-  #details-button {
-    padding-bottom: 16px;
-    padding-top: 16px;
-  }
-
   h1 {
     font-size: 1.5em;
     margin-bottom: 8px;
diff --git a/components/security_interstitials/core/common/resources/interstitial_core.css b/components/security_interstitials/core/common/resources/interstitial_core.css
index ef124ab..7137e0b3ad 100644
--- a/components/security_interstitials/core/common/resources/interstitial_core.css
+++ b/components/security_interstitials/core/common/resources/interstitial_core.css
@@ -7,20 +7,24 @@
 }
 
 body {
-  --google-blue-600: #1A73E8;
-  --google-blue-700: #1967D2;
+  --google-blue-600: rgb(26, 115, 232);
+  --google-blue-700: rgb(25, 103, 210);
+  --google-gray-50: rgb(248, 249, 250);
+  --google-gray-500: rgb(154, 160, 166);
+  --google-gray-600: rgb(128, 134, 139);
+  --google-gray-700: rgb(95, 99, 105);
   background-color: #fff;
-  color: rgb(100, 100, 100);
+  color: var(--google-gray-700);
   word-wrap: break-word;
 }
 
-#details-button {
-  background: inherit;
-  border: 0;
+.nav-wrapper .secondary-button {
+  background: #fff;
+  border: 1px solid var(--google-gray-500);
+  color: var(--google-gray-700);
   float: none;
   margin: 0;
-  padding: 10px 0;
-  text-transform: uppercase;
+  padding: 8px 16px;
 }
 
 .hidden {
diff --git a/components/sync/driver/fake_sync_client.cc b/components/sync/driver/fake_sync_client.cc
index 6f67be799..012d402 100644
--- a/components/sync/driver/fake_sync_client.cc
+++ b/components/sync/driver/fake_sync_client.cc
@@ -31,8 +31,6 @@
 
 FakeSyncClient::~FakeSyncClient() {}
 
-void FakeSyncClient::Initialize() {}
-
 SyncService* FakeSyncClient::GetSyncService() {
   return sync_service_.get();
 }
diff --git a/components/sync/driver/fake_sync_client.h b/components/sync/driver/fake_sync_client.h
index 9484f3c..3765d75 100644
--- a/components/sync/driver/fake_sync_client.h
+++ b/components/sync/driver/fake_sync_client.h
@@ -24,8 +24,6 @@
   explicit FakeSyncClient(SyncApiComponentFactory* factory);
   ~FakeSyncClient() override;
 
-  void Initialize() override;
-
   SyncService* GetSyncService() override;
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h
index 6271acb..9a87945 100644
--- a/components/sync/driver/sync_client.h
+++ b/components/sync/driver/sync_client.h
@@ -60,9 +60,6 @@
   SyncClient();
   virtual ~SyncClient();
 
-  // Initializes the sync client with the specified sync service.
-  virtual void Initialize() = 0;
-
   // Returns the current SyncService instance.
   virtual SyncService* GetSyncService() = 0;
 
diff --git a/components/sync/driver/sync_client_mock.h b/components/sync/driver/sync_client_mock.h
index f995ee3a..6e27bed 100644
--- a/components/sync/driver/sync_client_mock.h
+++ b/components/sync/driver/sync_client_mock.h
@@ -16,7 +16,6 @@
   SyncClientMock();
   ~SyncClientMock() override;
 
-  MOCK_METHOD0(Initialize, void());
   MOCK_METHOD0(GetSyncService, SyncService*());
   MOCK_METHOD0(GetPrefService, PrefService*());
   MOCK_METHOD0(GetLocalSyncBackendFolder, base::FilePath());
diff --git a/components/tracing/common/native_stack_sampler_android.cc b/components/tracing/common/native_stack_sampler_android.cc
index 2d22b4f..3ab46766 100644
--- a/components/tracing/common/native_stack_sampler_android.cc
+++ b/components/tracing/common/native_stack_sampler_android.cc
@@ -4,17 +4,15 @@
 
 #include "components/tracing/common/native_stack_sampler_android.h"
 
-#include "components/tracing/common/stack_unwinder_android.h"
+#include "base/trace_event/trace_event.h"
 
 namespace tracing {
 namespace {
 constexpr size_t kMaxFrameDepth = 48;
 }  // namespace
 
-NativeStackSamplerAndroid::NativeStackSamplerAndroid(
-    base::PlatformThreadId tid,
-    const StackUnwinderAndroid* unwinder)
-    : tid_(tid), unwinder_(unwinder) {}
+NativeStackSamplerAndroid::NativeStackSamplerAndroid(base::PlatformThreadId tid)
+    : tid_(tid) {}
 
 NativeStackSamplerAndroid::~NativeStackSamplerAndroid() = default;
 
@@ -24,14 +22,20 @@
 NativeStackSamplerAndroid::RecordStackFrames(
     StackBuffer* stack_buffer,
     base::StackSamplingProfiler::ProfileBuilder* profile_builder) {
+  if (!unwinder_.is_initialized()) {
+    // May block on disk access. This function is executed on the profiler
+    // thread, so this will only block profiling execution.
+    TRACE_EVENT0("cpu_profiler", "StackUnwinderAndroid::Initialize");
+    unwinder_.Initialize();
+  }
   const void* pcs[kMaxFrameDepth];
-  size_t depth = unwinder_->TraceStack(tid_, pcs, kMaxFrameDepth);
+  size_t depth = unwinder_.TraceStack(tid_, pcs, kMaxFrameDepth);
   std::vector<base::StackSamplingProfiler::Frame> frames;
   frames.reserve(depth);
   for (size_t i = 0; i < depth; ++i) {
     // TODO(ssid): Add support for obtaining modules here.
-    frames.push_back(base::StackSamplingProfiler::Frame(
-        reinterpret_cast<uintptr_t>(pcs[i]), base::ModuleCache::Module()));
+    frames.emplace_back(reinterpret_cast<uintptr_t>(pcs[i]),
+                        base::ModuleCache::Module());
   }
   return frames;
 }
diff --git a/components/tracing/common/native_stack_sampler_android.h b/components/tracing/common/native_stack_sampler_android.h
index 26c42474..e5c49aa 100644
--- a/components/tracing/common/native_stack_sampler_android.h
+++ b/components/tracing/common/native_stack_sampler_android.h
@@ -7,21 +7,18 @@
 
 #include "base/profiler/native_stack_sampler.h"
 #include "base/threading/platform_thread.h"
+#include "components/tracing/common/stack_unwinder_android.h"
 
 namespace tracing {
 
-class StackUnwinderAndroid;
-
 // On Android the sampling implementation is delegated and this class just
 // stores a callback to the real implementation.
 class NativeStackSamplerAndroid : public base::NativeStackSampler {
  public:
-  // StackUnwinderAndroid supports sampling only one thread per process. So, the
-  // client should ensure that no other code is using the unwinder in the
-  // process. The caller must also ensure that |unwinder| is initialized for
-  // sampling.
-  NativeStackSamplerAndroid(base::PlatformThreadId thread_id,
-                            const StackUnwinderAndroid* unwinder);
+  // StackUnwinderAndroid only supports sampling one thread at a time. So, the
+  // clients of this class must ensure synchronization between multiple
+  // instances of the sampler.
+  NativeStackSamplerAndroid(base::PlatformThreadId thread_id);
   ~NativeStackSamplerAndroid() override;
 
   // StackSamplingProfiler::NativeStackSampler:
@@ -32,7 +29,7 @@
 
  private:
   base::PlatformThreadId tid_;
-  const StackUnwinderAndroid* unwinder_;
+  StackUnwinderAndroid unwinder_;
 
   DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerAndroid);
 };
diff --git a/components/tracing/common/stack_unwinder_android.cc b/components/tracing/common/stack_unwinder_android.cc
index 6e4c1d8b..c5a0e34 100644
--- a/components/tracing/common/stack_unwinder_android.cc
+++ b/components/tracing/common/stack_unwinder_android.cc
@@ -211,16 +211,12 @@
 StackUnwinderAndroid::StackUnwinderAndroid() {}
 StackUnwinderAndroid::~StackUnwinderAndroid() {}
 
-//  static
-StackUnwinderAndroid* StackUnwinderAndroid::GetInstance() {
-  static StackUnwinderAndroid* instance = new StackUnwinderAndroid();
-  return instance;
-}
-
 void StackUnwinderAndroid::Initialize() {
-  DCHECK(!is_initialized_);
   is_initialized_ = true;
 
+  // Ensure Chrome unwinder is initialized.
+  CFIBacktraceAndroid::GetInitializedInstance();
+
   // Parses /proc/self/maps.
   std::string contents;
   if (!base::debug::ReadProcMaps(&contents)) {
diff --git a/components/tracing/common/stack_unwinder_android.h b/components/tracing/common/stack_unwinder_android.h
index 135300e..f61e6d3 100644
--- a/components/tracing/common/stack_unwinder_android.h
+++ b/components/tracing/common/stack_unwinder_android.h
@@ -17,12 +17,18 @@
 // to unwind stacks based on EHABI section in Android libraries and using the
 // custom stack unwind information in Chrome. This works on top of
 // base::trace_event::CFIBacktraceAndroid, which unwinds Chrome only stacks.
+// This class does not provide any thread safety guarantees. It is also unsafe
+// to use multiple instances of this class at the same time due to signal
+// handling. So, the client must ensure synchronization between multiple
+// instances of this class.
 class TRACING_EXPORT StackUnwinderAndroid {
  public:
-  static StackUnwinderAndroid* GetInstance();
+  StackUnwinderAndroid();
+  ~StackUnwinderAndroid();
 
   // Initializes the unwinder for current process. It finds all loaded libraries
   // in current process and also initializes CFIBacktraceAndroid, with file IO.
+  // Can be called multiple times, to update the loaded modules.
   void Initialize();
 
   // Unwinds stack frames for current thread and stores the program counters in
@@ -42,10 +48,9 @@
   // process.
   bool IsAddressMapped(uintptr_t pc) const;
 
- private:
-  StackUnwinderAndroid();
-  ~StackUnwinderAndroid();
+  bool is_initialized() const { return is_initialized_; }
 
+ private:
   bool is_initialized_ = false;
 
   // Stores all the memory mapped regions in the current process, including all
diff --git a/components/tracing/common/stack_unwinder_android_unittest.cc b/components/tracing/common/stack_unwinder_android_unittest.cc
index af841a2..d0833545 100644
--- a/components/tracing/common/stack_unwinder_android_unittest.cc
+++ b/components/tracing/common/stack_unwinder_android_unittest.cc
@@ -21,14 +21,18 @@
   ~StackUnwinderTest() override {}
 
   void SetUp() override {
-    StackUnwinderAndroid::GetInstance()->Initialize();
+    unwinder_.Initialize();
     base::trace_event::CFIBacktraceAndroid::GetInitializedInstance()
         ->AllocateCacheForCurrentThread();
   }
 
+  StackUnwinderAndroid* unwinder() { return &unwinder_; }
+
  private:
-  DISALLOW_COPY_AND_ASSIGN(StackUnwinderTest);
+  StackUnwinderAndroid unwinder_;
   base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackUnwinderTest);
 };
 
 uintptr_t GetCurrentPC() {
@@ -39,8 +43,7 @@
 
 TEST_F(StackUnwinderTest, UnwindCurrentThread) {
   const void* frames[kMaxStackFrames];
-  size_t result =
-      StackUnwinderAndroid::GetInstance()->TraceStack(frames, kMaxStackFrames);
+  size_t result = unwinder()->TraceStack(frames, kMaxStackFrames);
   EXPECT_GT(result, 0u);
 
   // Since we are starting from chrome library function (this), all the unwind
@@ -57,25 +60,25 @@
   auto task_runner = base::CreateSingleThreadTaskRunnerWithTraits(
       {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
 
-  auto callback = [](base::PlatformThreadId tid,
+  auto callback = [](StackUnwinderAndroid* unwinder, base::PlatformThreadId tid,
                      base::WaitableEvent* unwind_finished_event,
                      uintptr_t test_pc) {
     const void* frames[kMaxStackFrames];
-    size_t result = StackUnwinderAndroid::GetInstance()->TraceStack(
-        tid, frames, kMaxStackFrames);
+    size_t result = unwinder->TraceStack(tid, frames, kMaxStackFrames);
     EXPECT_GT(result, 0u);
     for (size_t i = 0; i < result; ++i) {
       uintptr_t addr = reinterpret_cast<uintptr_t>(frames[i]);
-      EXPECT_TRUE(StackUnwinderAndroid::GetInstance()->IsAddressMapped(addr));
+      EXPECT_TRUE(unwinder->IsAddressMapped(addr));
     }
 
     unwind_finished_event->Signal();
   };
 
   // Post task on background thread to unwind the current thread.
-  task_runner->PostTask(
-      FROM_HERE, base::BindOnce(callback, base::PlatformThread::CurrentId(),
-                                &unwind_finished_event, GetCurrentPC()));
+  task_runner->PostTask(FROM_HERE,
+                        base::BindOnce(callback, base::Unretained(unwinder()),
+                                       base::PlatformThread::CurrentId(),
+                                       &unwind_finished_event, GetCurrentPC()));
 
   // While the background thread is trying to unwind make some slow framework
   // calls (malloc) so that the current thread can be stopped in framework
diff --git a/components/tracing/common/tracing_sampler_profiler.cc b/components/tracing/common/tracing_sampler_profiler.cc
index ba08bc45..e5720b34b 100644
--- a/components/tracing/common/tracing_sampler_profiler.cc
+++ b/components/tracing/common/tracing_sampler_profiler.cc
@@ -12,6 +12,13 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_log.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+
+#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
+    defined(OFFICIAL_BUILD)
+#include "components/tracing/common/native_stack_sampler_android.h"
+#endif
 
 namespace tracing {
 
@@ -95,8 +102,15 @@
   params.sampling_interval = base::TimeDelta::FromMilliseconds(50);
 
   // Create and start the stack sampling profiler.
+#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
+    defined(OFFICIAL_BUILD)
+  profiler_ = std::make_unique<base::StackSamplingProfiler>(
+      sampled_thread_id_, params, std::make_unique<TracingProfileBuilder>(),
+      std::make_unique<NativeStackSamplerAndroid>(sampled_thread_id_));
+#else
   profiler_ = std::make_unique<base::StackSamplingProfiler>(
       sampled_thread_id_, params, std::make_unique<TracingProfileBuilder>());
+#endif
   profiler_->Start();
 }
 
diff --git a/components/tracing/common/tracing_sampler_profiler_unittest.cc b/components/tracing/common/tracing_sampler_profiler_unittest.cc
index c24815d..53d5835 100644
--- a/components/tracing/common/tracing_sampler_profiler_unittest.cc
+++ b/components/tracing/common/tracing_sampler_profiler_unittest.cc
@@ -58,7 +58,9 @@
   // Returns whether of not the sampler profiling is able to unwind the stack
   // on this platform.
   bool IsStackUnwindingSupported() {
-#if defined(OS_MACOSX) || defined(OS_WIN) && defined(_WIN64)
+#if defined(OS_MACOSX) || defined(OS_WIN) && defined(_WIN64) ||     \
+    (defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
+     defined(OFFICIAL_BUILD))
     return true;
 #else
     return false;
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm
index 8d945b7..3549637 100644
--- a/components/translate/ios/browser/ios_translate_driver.mm
+++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -258,6 +258,7 @@
   if (error_type != TranslateErrors::NONE) {
     translate_manager_->PageTranslated(source_language_, target_language_,
                                        error_type);
+    return;
   }
 
   TranslationDidSucceed(source_language_, target_language_,
diff --git a/components/translate/ios/browser/translate_controller.h b/components/translate/ios/browser/translate_controller.h
index 886ca08d8..9dee1e8 100644
--- a/components/translate/ios/browser/translate_controller.h
+++ b/components/translate/ios/browser/translate_controller.h
@@ -82,6 +82,7 @@
                            OnTranslateScriptReadyCalled);
   FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, TranslationSuccess);
   FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, TranslationFailure);
+  FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, OnTranslateLoadJavascript);
 
   // Called when a JavaScript command is received.
   bool OnJavascriptCommandReceived(const base::DictionaryValue& command,
diff --git a/components/translate/ios/browser/translate_controller_unittest.mm b/components/translate/ios/browser/translate_controller_unittest.mm
index eacc4ece..33b0693 100644
--- a/components/translate/ios/browser/translate_controller_unittest.mm
+++ b/components/translate/ios/browser/translate_controller_unittest.mm
@@ -162,4 +162,15 @@
   EXPECT_FALSE(error_type_ == TranslateErrors::NONE);
 }
 
+// Tests that OnTranslateLoadJavaScript() is called with the right paramters
+// when a |translate.loadjavascript| message is received from the JS side.
+TEST_F(TranslateControllerTest, OnTranslateLoadJavascript) {
+  base::DictionaryValue command;
+  command.SetString("command", "translate.loadjavascript");
+  command.SetString("url", "https:///translate.googleapis.com/javascript.js");
+  EXPECT_TRUE(translate_controller_->OnJavascriptCommandReceived(
+      command, GURL("http://google.com"), /*interacting=*/false,
+      /*is_main_frame=*/true, /*sender_frame=*/nullptr));
+}
+
 }  // namespace translate
diff --git a/components/unified_consent/unified_consent_metrics.cc b/components/unified_consent/unified_consent_metrics.cc
index a72165e..153d675 100644
--- a/components/unified_consent/unified_consent_metrics.cc
+++ b/components/unified_consent/unified_consent_metrics.cc
@@ -28,6 +28,10 @@
                         eligible);
 }
 
+void RecordUnifiedConsentRevoked(UnifiedConsentRevokeReason reason) {
+  UMA_HISTOGRAM_ENUMERATION("UnifiedConsent.RevokeReason", reason);
+}
+
 }  // namespace metrics
 
 }  // namespace unified_consent
diff --git a/components/unified_consent/unified_consent_metrics.h b/components/unified_consent/unified_consent_metrics.h
index 7e476156..229c8e53 100644
--- a/components/unified_consent/unified_consent_metrics.h
+++ b/components/unified_consent/unified_consent_metrics.h
@@ -18,6 +18,14 @@
   kUnifiedConsentBumpActionMoreOptionsMax,
 };
 
+// Histogram enum: UnifiedConsentRevokeReason.
+enum class UnifiedConsentRevokeReason : int {
+  kUserSignedOut = 0,
+  kServiceWasDisabled,
+  kCustomPassphrase,
+  kMaxValue = kCustomPassphrase
+};
+
 // Records histogram action for the unified consent bump.
 void RecordConsentBumpMetric(UnifiedConsentBumpAction action);
 
@@ -25,6 +33,9 @@
 // be called at startup.
 void RecordConsentBumpEligibility(bool eligible);
 
+// Records the reason why the unified consent was revoked.
+void RecordUnifiedConsentRevoked(UnifiedConsentRevokeReason reason);
+
 }  // namespace metrics
 
 }  // namespace unified_consent
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc
index 1752f95..a26a0b6 100644
--- a/components/unified_consent/unified_consent_service.cc
+++ b/components/unified_consent/unified_consent_service.cc
@@ -157,6 +157,8 @@
   // wasn't running, disable unified consent.
   if (!AreAllNonPersonalizedServicesEnabled() && IsUnifiedConsentGiven()) {
     SetUnifiedConsentGiven(false);
+    RecordUnifiedConsentRevoked(
+        metrics::UnifiedConsentRevokeReason::kServiceWasDisabled);
   }
 
   RecordSettingsHistogram();
@@ -266,14 +268,20 @@
 void UnifiedConsentService::OnServiceStateChanged(Service service) {
   // Unified consent is disabled when any of its dependent services gets
   // disabled.
-  if (service_client_->GetServiceState(service) == ServiceState::kDisabled)
+  if (service_client_->GetServiceState(service) == ServiceState::kDisabled &&
+      IsUnifiedConsentGiven()) {
     SetUnifiedConsentGiven(false);
+    RecordUnifiedConsentRevoked(
+        metrics::UnifiedConsentRevokeReason::kServiceWasDisabled);
+  }
 }
 
 void UnifiedConsentService::OnPrimaryAccountCleared(
     const AccountInfo& account_info) {
   // When signing out, the unfied consent is revoked.
   pref_service_->SetBoolean(prefs::kUnifiedConsentGiven, false);
+  RecordUnifiedConsentRevoked(
+      metrics::UnifiedConsentRevokeReason::kUserSignedOut);
 
   // By design, signing out of Chrome automatically disables off-by-default
   // services.
@@ -307,6 +315,8 @@
   if (sync_service_->IsUsingSecondaryPassphrase() && IsUnifiedConsentGiven()) {
     // Force off unified consent given when the user sets a custom passphrase.
     SetUnifiedConsentGiven(false);
+    RecordUnifiedConsentRevoked(
+        metrics::UnifiedConsentRevokeReason::kCustomPassphrase);
   }
 
   syncer::SyncPrefs sync_prefs(pref_service_);
diff --git a/components/unified_consent/unified_consent_service_unittest.cc b/components/unified_consent/unified_consent_service_unittest.cc
index 1aaf28f..d88f5f288 100644
--- a/components/unified_consent/unified_consent_service_unittest.cc
+++ b/components/unified_consent/unified_consent_service_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/unified_consent/pref_names.h"
 #include "components/unified_consent/scoped_unified_consent.h"
+#include "components/unified_consent/unified_consent_metrics.h"
 #include "components/unified_consent/unified_consent_service_client.h"
 #include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -288,6 +289,8 @@
 }
 
 TEST_F(UnifiedConsentServiceTest, EnableUnfiedConsent_WithCustomPassphrase) {
+  base::HistogramTester histogram_tester;
+
   CreateConsentService();
   identity_test_environment_.SetPrimaryAccount("testaccount");
   EXPECT_FALSE(consent_service_->IsUnifiedConsentGiven());
@@ -304,11 +307,16 @@
 
   // Setting a custom passphrase forces off unified consent given.
   EXPECT_FALSE(consent_service_->IsUnifiedConsentGiven());
+  histogram_tester.ExpectUniqueSample(
+      "UnifiedConsent.RevokeReason",
+      metrics::UnifiedConsentRevokeReason::kCustomPassphrase, 1);
 }
 
 // Test whether unified consent is disabled when any of its dependent services
 // gets disabled.
 TEST_F(UnifiedConsentServiceTest, DisableUnfiedConsentWhenServiceIsDisabled) {
+  base::HistogramTester histogram_tester;
+
   CreateConsentService();
   identity_test_environment_.SetPrimaryAccount("testaccount");
   EXPECT_FALSE(pref_service_.GetBoolean(prefs::kUnifiedConsentGiven));
@@ -325,6 +333,9 @@
   pref_service_.SetBoolean(kSpellCheckDummyEnabled, false);
   EXPECT_FALSE(AreAllNonPersonalizedServicesEnabled());
   EXPECT_FALSE(pref_service_.GetBoolean(prefs::kUnifiedConsentGiven));
+  histogram_tester.ExpectUniqueSample(
+      "UnifiedConsent.RevokeReason",
+      metrics::UnifiedConsentRevokeReason::kServiceWasDisabled, 1);
 }
 
 // Test whether unified consent is disabled when any of its dependent services
@@ -475,6 +486,8 @@
 
 #if !defined(OS_CHROMEOS)
 TEST_F(UnifiedConsentServiceTest, ClearPrimaryAccountDisablesSomeServices) {
+  base::HistogramTester histogram_tester;
+
   CreateConsentService();
   identity_test_environment_.SetPrimaryAccount("testaccount");
 
@@ -486,6 +499,9 @@
   // non-personalized services.
   identity_test_environment_.ClearPrimaryAccount();
   EXPECT_FALSE(pref_service_.GetBoolean(prefs::kUnifiedConsentGiven));
+  histogram_tester.ExpectUniqueSample(
+      "UnifiedConsent.RevokeReason",
+      metrics::UnifiedConsentRevokeReason::kUserSignedOut, 1);
   EXPECT_FALSE(AreAllNonPersonalizedServicesEnabled());
   EXPECT_FALSE(pref_service_.GetBoolean(
       prefs::kUrlKeyedAnonymizedDataCollectionEnabled));
diff --git a/components/url_formatter/url_formatter.cc b/components/url_formatter/url_formatter.cc
index 1c12234..8f5f5e1 100644
--- a/components/url_formatter/url_formatter.cc
+++ b/components/url_formatter/url_formatter.cc
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_piece.h"
-#include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_offset_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -68,20 +67,6 @@
       : trim_trivial_subdomains_(trim_trivial_subdomains) {}
 
  private:
-  static bool IsTrivialSubdomain(base::StringPiece subdomain) {
-    if (subdomain == "www")
-      return true;
-
-#if defined(OS_ANDROID) || defined(OS_IOS)
-    // Eliding the "m" subdomain on Desktop can be confusing, since users would
-    // generally want to know if they are unintentionally on the mobile site.
-    if (subdomain == "m")
-      return true;
-#endif
-
-    return false;
-  }
-
   base::string16 Execute(
       const std::string& component_text,
       base::OffsetAdjuster::Adjustments* adjustments) const override {
@@ -102,42 +87,18 @@
       return IDNToUnicodeWithAdjustments(component_text, adjustments).result;
 
     base::OffsetAdjuster::Adjustments trivial_subdomains_adjustments;
-    base::StringTokenizer tokenizer(
-        component_text.begin(),
-        component_text.end() - domain_and_registry.length(), ".");
-    tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
-
-    bool reached_non_trivial_subdomain = false;
-    std::string transformed_subdomain;
-    while (tokenizer.GetNext()) {
-      // Record whether a trivial subdomain has been encountered.
-      if (!IsTrivialSubdomain(tokenizer.token_piece()))
-        reached_non_trivial_subdomain = true;
-
-      // Append delimiters and everything encountered at or after the first
-      // non-trivial subdomain.
-      if (tokenizer.token_is_delim() || reached_non_trivial_subdomain) {
-        transformed_subdomain += tokenizer.token();
-        continue;
-      }
-
-      // We found a trivial subdomain, so we add an adjustment accounting for
-      // the subdomain and the following consumed delimiter.
-      size_t trivial_subdomain_begin =
-          tokenizer.token_begin() - component_text.begin();
-      trivial_subdomains_adjustments.push_back(base::OffsetAdjuster::Adjustment(
-          trivial_subdomain_begin, tokenizer.token().length() + 1, 0));
-
-      // Consume the next token, which must be a delimiter.
-      bool next_delimiter_found = tokenizer.GetNext();
-      DCHECK(next_delimiter_found);
-      DCHECK(tokenizer.token_is_delim());
+    std::string transformed_host = component_text;
+    constexpr char kWww[] = "www.";
+    constexpr size_t kWwwLength = 4;
+    if (component_text.size() - domain_and_registry.length() >= kWwwLength &&
+        StartsWith(component_text, kWww, base::CompareCase::SENSITIVE)) {
+      transformed_host.erase(0, kWwwLength);
+      trivial_subdomains_adjustments.push_back(
+          base::OffsetAdjuster::Adjustment(0, kWwwLength, 0));
     }
 
     base::string16 unicode_result =
-        IDNToUnicodeWithAdjustments(transformed_subdomain + domain_and_registry,
-                                    adjustments)
-            .result;
+        IDNToUnicodeWithAdjustments(transformed_host, adjustments).result;
     base::OffsetAdjuster::MergeSequentialAdjustments(
         trivial_subdomains_adjustments, adjustments);
     return unicode_result;
diff --git a/components/url_formatter/url_formatter_unittest.cc b/components/url_formatter/url_formatter_unittest.cc
index 319db5b8..b0e58cb 100644
--- a/components/url_formatter/url_formatter_unittest.cc
+++ b/components/url_formatter/url_formatter_unittest.cc
@@ -1222,22 +1222,18 @@
        net::UnescapeRule::NORMAL, L"https://ftp.google.com/", 8},
 
       // -------- omit trivial subdomains --------
-#if defined(OS_ANDROID) || defined(OS_IOS)
-      {"omit trivial subdomains - trim leading m", "http://m.google.com/",
-      kFormatUrlOmitTrivialSubdomains, net::UnescapeRule::NORMAL,
-      L"http://google.com/", 7},
-      {"omit trivial subdomains - trim leading m and www",
-      "http://m.www.google.com/",
-      kFormatUrlOmitTrivialSubdomains, net::UnescapeRule::NORMAL,
-      L"http://google.com/", 7},
-#else  // !(defined(OS_ANDROID) || defined(OS_IOS))
-      {"omit trivial subdomains - don't trim leading m on desktop",
+      {"omit trivial subdomains - trim leading www",
+      "http://www.wikipedia.org/", kFormatUrlOmitTrivialSubdomains,
+      net::UnescapeRule::NORMAL, L"http://wikipedia.org/", 7},
+      {"omit trivial subdomains - don't trim leading m",
       "http://m.google.com/", kFormatUrlOmitTrivialSubdomains,
       net::UnescapeRule::NORMAL, L"http://m.google.com/", 7},
-      {"omit trivial subdomains - don't trim www after a leading m on desktop",
+      {"omit trivial subdomains - don't trim www after a leading m",
       "http://m.www.google.com/", kFormatUrlOmitTrivialSubdomains,
       net::UnescapeRule::NORMAL, L"http://m.www.google.com/", 7},
-#endif
+      {"omit trivial subdomains - trim first www only",
+      "http://www.www.www.wikipedia.org/", kFormatUrlOmitTrivialSubdomains,
+      net::UnescapeRule::NORMAL, L"http://www.www.wikipedia.org/", 7},
       {"omit trivial subdomains - don't trim www from middle",
       "http://en.www.wikipedia.org/", kFormatUrlOmitTrivialSubdomains,
       net::UnescapeRule::NORMAL, L"http://en.www.wikipedia.org/", 7},
@@ -1558,7 +1554,7 @@
 }
 
 TEST(UrlFormatterTest, FormatUrlWithOffsets) {
-  CheckAdjustedOffsets(std::string(),  kFormatUrlOmitNothing,
+  CheckAdjustedOffsets(std::string(), kFormatUrlOmitNothing,
                        net::UnescapeRule::NORMAL, nullptr);
 
   const size_t basic_offsets[] = {
@@ -1742,22 +1738,6 @@
       "http://www.google.com/foo/", kFormatUrlOmitTrivialSubdomains,
       net::UnescapeRule::NORMAL, strip_trivial_subdomains_offsets_1);
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
-  const size_t strip_trivial_subdomains_offsets_2[] = {
-      0,  1,  2,  3,  4,  5,  6,  7,  kNpos, 7,  8,  9,
-      10, 11, 12, 13, 14, 15, 16, 17, 18,    19, 20, 21};
-  CheckAdjustedOffsets(
-      "http://m.en.www.foo.com/", kFormatUrlOmitTrivialSubdomains,
-      net::UnescapeRule::NORMAL, strip_trivial_subdomains_offsets_2);
-#else  // !(defined(OS_ANDROID) || defined(OS_IOS))
-  const size_t strip_trivial_subdomains_offsets_2[] = {
-      0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11,
-      12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
-  CheckAdjustedOffsets(
-      "http://m.en.www.foo.com/", kFormatUrlOmitTrivialSubdomains,
-      net::UnescapeRule::NORMAL, strip_trivial_subdomains_offsets_2);
-#endif
-
   const size_t strip_trivial_subdomains_from_idn_offsets[] = {
       0,     1,     2,     3,     4,     5,     6,     7,     kNpos, kNpos,
       kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos,
diff --git a/components/url_pattern_index/url_pattern.cc b/components/url_pattern_index/url_pattern.cc
index 0c2fcd8..8589f131 100644
--- a/components/url_pattern_index/url_pattern.cc
+++ b/components/url_pattern_index/url_pattern.cc
@@ -236,6 +236,17 @@
 
 }  // namespace
 
+UrlPattern::UrlInfo::UrlInfo(const GURL& url)
+    : spec_(url.possibly_invalid_spec()),
+      lower_case_spec_(HasAnyUpperAscii(spec_) ? base::Optional<std::string>(
+                                                     base::ToLowerASCII(spec_))
+                                               : base::nullopt),
+      host_(url.parsed_for_possibly_invalid_spec().host) {
+  DCHECK(url.is_valid());
+}
+
+UrlPattern::UrlInfo::~UrlInfo() = default;
+
 UrlPattern::UrlPattern() = default;
 
 UrlPattern::UrlPattern(base::StringPiece url_pattern,
@@ -262,28 +273,21 @@
 
 UrlPattern::~UrlPattern() = default;
 
-bool UrlPattern::MatchesUrl(const GURL& url) const {
-  // Note: Empty domains are also invalid.
-  DCHECK(url.is_valid());
+bool UrlPattern::MatchesUrl(const UrlInfo& url) const {
   DCHECK(type_ == proto::URL_PATTERN_TYPE_SUBSTRING ||
          type_ == proto::URL_PATTERN_TYPE_WILDCARDED);
   DCHECK(base::IsStringASCII(url_pattern_));
-  DCHECK(base::IsStringASCII(url.possibly_invalid_spec()));
+  DCHECK(base::IsStringASCII(url.spec()));
+  DCHECK(base::IsStringASCII(url.lower_case_spec()));
 
-  if (match_case() || (!HasAnyUpperAscii(url_pattern_) &&
-                       !HasAnyUpperAscii(url.possibly_invalid_spec()))) {
+  if (match_case()) {
     return IsCaseSensitiveMatch(url_pattern_, anchor_left_, anchor_right_,
-                                url.possibly_invalid_spec(),
-                                url.parsed_for_possibly_invalid_spec().host);
+                                url.spec(), url.host());
   }
 
   // For case-insensitive matching, convert both pattern and url to lower case.
-  const std::string lower_case_url_pattern = base::ToLowerASCII(url_pattern_);
-  const std::string lower_case_url_spec =
-      base::ToLowerASCII(url.possibly_invalid_spec());
-  return IsCaseSensitiveMatch(lower_case_url_pattern, anchor_left_,
-                              anchor_right_, lower_case_url_spec,
-                              url.parsed_for_possibly_invalid_spec().host);
+  return IsCaseSensitiveMatch(base::ToLowerASCII(url_pattern_), anchor_left_,
+                              anchor_right_, url.lower_case_spec(), url.host());
 }
 
 std::ostream& operator<<(std::ostream& out, const UrlPattern& pattern) {
diff --git a/components/url_pattern_index/url_pattern.h b/components/url_pattern_index/url_pattern.h
index eb2e29b..a5d46f6 100644
--- a/components/url_pattern_index/url_pattern.h
+++ b/components/url_pattern_index/url_pattern.h
@@ -8,8 +8,10 @@
 #include <iosfwd>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "components/url_pattern_index/proto/rules.pb.h"
+#include "url/third_party/mozilla/url_parse.h"
 
 class GURL;
 
@@ -28,6 +30,31 @@
     kFalse,
   };
 
+  // A wrapper over a GURL to reduce redundant computation.
+  class UrlInfo {
+   public:
+    // The |url| must outlive this instance.
+    UrlInfo(const GURL& url);
+    ~UrlInfo();
+
+    base::StringPiece spec() const { return spec_; }
+    base::StringPiece lower_case_spec() const {
+      return lower_case_spec_ ? *lower_case_spec_ : spec_;
+    }
+    url::Component host() const { return host_; }
+
+   private:
+    // The url spec.
+    const base::StringPiece spec_;
+    // Lower-cased url spec. Only populated if |spec_| contains upper case
+    // characters.
+    const base::Optional<std::string> lower_case_spec_;
+    // The url host component.
+    const url::Component host_;
+
+    DISALLOW_COPY_AND_ASSIGN(UrlInfo);
+  };
+
   UrlPattern();
 
   // Creates a |url_pattern| of a certain |type| and case-sensitivity.
@@ -58,7 +85,7 @@
   // greedily finds each of them in the spec of the |url|. Respects anchors at
   // either end of the pattern, and '^' separator placeholders when comparing a
   // subpattern to a subtring of the spec.
-  bool MatchesUrl(const GURL& url) const;
+  bool MatchesUrl(const UrlInfo& url) const;
 
  private:
   // TODO(pkalinnikov): Store flat:: types instead of proto::, in order to avoid
diff --git a/components/url_pattern_index/url_pattern_index.cc b/components/url_pattern_index/url_pattern_index.cc
index 463253a..b5ff908 100644
--- a/components/url_pattern_index/url_pattern_index.cc
+++ b/components/url_pattern_index/url_pattern_index.cc
@@ -606,7 +606,7 @@
 // |sorted_candidates| or null if no rule matches.
 const flat::UrlRule* FindMatchAmongCandidates(
     const FlatUrlRuleList* sorted_candidates,
-    const GURL& url,
+    const UrlPattern::UrlInfo& url,
     const url::Origin& document_origin,
     flat::ElementType element_type,
     flat::ActivationType activation_type,
@@ -642,7 +642,7 @@
 // between |url| and |document_origin|.
 const flat::UrlRule* FindMatchInFlatUrlPatternIndex(
     const flat::UrlPatternIndex& index,
-    const GURL& url,
+    const UrlPattern::UrlInfo& url,
     const url::Origin& document_origin,
     flat::ElementType element_type,
     flat::ActivationType activation_type,
@@ -657,14 +657,10 @@
 
   NGramHashTableProber prober;
 
-  // |hash_table| contains lower-cased n-grams. Lower case the url if necessary
-  // to find possible matches.
-  base::Optional<std::string> lower_case_url;
-  if (!HasNoUpperAscii(url.spec()))
-    lower_case_url = base::ToLowerASCII(url.spec());
+  // |hash_table| contains lower-cased n-grams. Use lower-cased url to find
+  // prospective matches.
   auto ngrams = CreateNGramExtractor<kNGramSize, uint64_t>(
-      lower_case_url ? *lower_case_url : url.spec(),
-      [](char) { return false; });
+      url.lower_case_spec(), [](char) { return false; });
 
   auto get_max_priority_rule = [](const flat::UrlRule* lhs,
                                   const flat::UrlRule* rhs) {
@@ -766,8 +762,8 @@
   }
 
   return FindMatchInFlatUrlPatternIndex(
-      *flat_index_, url, first_party_origin, element_type, activation_type,
-      is_third_party, disable_generic_rules, strategy);
+      *flat_index_, UrlPattern::UrlInfo(url), first_party_origin, element_type,
+      activation_type, is_third_party, disable_generic_rules, strategy);
 }
 
 }  // namespace url_pattern_index
diff --git a/components/url_pattern_index/url_pattern_unittest.cc b/components/url_pattern_index/url_pattern_unittest.cc
index 0c7d0b7..8ffda4f 100644
--- a/components/url_pattern_index/url_pattern_unittest.cc
+++ b/components/url_pattern_index/url_pattern_unittest.cc
@@ -155,7 +155,9 @@
     SCOPED_TRACE(testing::Message() << "Rule: " << test_case.url_pattern
                                     << "; URL: " << GURL(test_case.url));
 
-    const bool is_match = test_case.url_pattern.MatchesUrl(GURL(test_case.url));
+    GURL url(test_case.url);
+    const bool is_match =
+        test_case.url_pattern.MatchesUrl(UrlPattern::UrlInfo(url));
     EXPECT_EQ(test_case.expect_match, is_match);
   }
 }
diff --git a/components/viz/client/client_resource_provider.cc b/components/viz/client/client_resource_provider.cc
index c7b2477..5bf168b4 100644
--- a/components/viz/client/client_resource_provider.cc
+++ b/components/viz/client/client_resource_provider.cc
@@ -133,34 +133,131 @@
 }
 
 void ClientResourceProvider::ReceiveReturnsFromParent(
-    const std::vector<ReturnedResource>& resources) {
+    std::vector<ReturnedResource> resources) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  for (const ReturnedResource& returned : resources) {
-    ResourceId local_id = returned.id;
+  // |imported_resources_| is a set sorted by id, so if we sort the incoming
+  // |resources| list by id also, we can walk through both structures in order,
+  // replacing  things to be removed from imported_resources_ with things that
+  // we want to keep, making the removal of all items O(N+MlogM) instead of
+  // O(N*M). This algorithm is modelled after std::remove_if() but with a
+  // parallel walk through |resources| instead of an O(logM) lookup into
+  // |resources| for each step.
+  std::sort(resources.begin(), resources.end(),
+            [](const ReturnedResource& a, const ReturnedResource& b) {
+              return a.id < b.id;
+            });
 
-    auto import_it = imported_resources_.find(local_id);
-    DCHECK(import_it != imported_resources_.end());
-    ImportedResource& imported = import_it->second;
+  auto returned_it = resources.begin();
+  auto returned_end = resources.end();
+  auto imported_keep_end_it = imported_resources_.begin();
+  auto imported_compare_it = imported_resources_.begin();
+  auto imported_end = imported_resources_.end();
+
+  std::vector<base::OnceClosure> release_callbacks;
+  release_callbacks.reserve(resources.size());
+
+  while (imported_compare_it != imported_end) {
+    if (returned_it == returned_end) {
+      // Nothing else to remove from |imported_resources_|.
+      if (imported_keep_end_it == imported_compare_it) {
+        // We didn't remove anything, so we're done.
+        break;
+      }
+      // If something was removed, we need to shift everything into the empty
+      // space that was made.
+      *imported_keep_end_it = std::move(*imported_compare_it);
+      ++imported_keep_end_it;
+      ++imported_compare_it;
+      continue;
+    }
+
+    const ResourceId returned_resource_id = returned_it->id;
+    const ResourceId imported_resource_id = imported_compare_it->first;
+
+    if (returned_resource_id != imported_resource_id) {
+      // They're both sorted, and everything being returned should already
+      // be in the imported list. So we should be able to walk through the
+      // resources list in order, and find each id in both sets when present.
+      // That means if it's not matching, we should be above it in the sorted
+      // order of the |imported_resources_|, allowing us to get to it by
+      // continuing to traverse |imported_resources_|.
+      DCHECK_GT(returned_resource_id, imported_resource_id);
+      // This means we want to keep the resource at |imported_compare_it|. So go
+      // to the next. If we removed anything previously and made empty space,
+      // fill it as we move.
+      if (imported_keep_end_it != imported_compare_it)
+        *imported_keep_end_it = std::move(*imported_compare_it);
+      ++imported_keep_end_it;
+      ++imported_compare_it;
+      continue;
+    }
+
+    const ReturnedResource& returned = *returned_it;
+    ImportedResource& imported = imported_compare_it->second;
 
     DCHECK_GE(imported.exported_count, returned.count);
     imported.exported_count -= returned.count;
     imported.returned_lost |= returned.lost;
 
-    if (imported.exported_count)
+    if (imported.exported_count) {
+      // Can't remove the imported yet so go to the next, looking for the next
+      // returned resource.
+      ++returned_it;
+      // The same ResourceId may appear multiple times (in a row) in the
+      // returned set. In that case, we do not want to increment the iterators
+      // in |imported_resources_| yet. So we don't increment them here, and let
+      // the next iteration of the loop do so.
       continue;
+    }
 
+    // Save the sync token only when the exported count is going to 0. Or IOW
+    // drop all by the last returned sync token.
     if (returned.sync_token.HasData()) {
       DCHECK(!imported.resource.is_software);
       imported.returned_sync_token = returned.sync_token;
     }
 
-    if (imported.marked_for_deletion) {
-      imported.release_callback->Run(imported.returned_sync_token,
-                                     imported.returned_lost);
-      imported_resources_.erase(import_it);
+    if (!imported.marked_for_deletion) {
+      // Not going to remove the imported yet so go to the next, looking for the
+      // next returned resource.
+      ++returned_it;
+      // If we removed anything previously and made empty space, fill it as we
+      // move.
+      if (imported_keep_end_it != imported_compare_it)
+        *imported_keep_end_it = std::move(*imported_compare_it);
+      ++imported_keep_end_it;
+      ++imported_compare_it;
+      continue;
     }
+
+    // Save the ReleaseCallback to run after iterating through internal data
+    // structures, in case it calls back into this class.
+    auto run_callback = [](std::unique_ptr<SingleReleaseCallback> cb,
+                           const gpu::SyncToken& sync_token, bool lost) {
+      cb->Run(sync_token, lost);
+      // |cb| is destroyed when leaving scope.
+    };
+    release_callbacks.push_back(
+        base::BindOnce(run_callback, base::Passed(&imported.release_callback),
+                       imported.returned_sync_token, imported.returned_lost));
+    // We don't want to keep this resource, so we leave |imported_keep_end_it|
+    // pointing to it (since it points past the end of what we're keeping). We
+    // do move |imported_compare_it| in order to move on to the next resource.
+    ++imported_compare_it;
+    // The imported iterator is pointing at the next element already, so no need
+    // to increment it, and we can move on to looking for the next returned
+    // resource.
+    ++returned_it;
   }
+
+  // Drop anything that was moved after the |imported_end| iterator in a single
+  // O(N) operation.
+  if (imported_keep_end_it != imported_compare_it)
+    imported_resources_.erase(imported_keep_end_it, imported_resources_.end());
+
+  for (auto& cb : release_callbacks)
+    std::move(cb).Run();
 }
 
 ResourceId ClientResourceProvider::ImportResource(
@@ -188,21 +285,30 @@
 }
 
 void ClientResourceProvider::ReleaseAllExportedResources(bool lose) {
-  std::vector<ResourceId> to_remove;
-  for (auto& pair : imported_resources_) {
-    ImportedResource& imported = pair.second;
-    if (!imported.exported_count)
-      continue;
-    imported.exported_count = 0;
-    imported.returned_lost |= lose;
-    if (imported.marked_for_deletion) {
-      imported.release_callback->Run(imported.returned_sync_token,
-                                     imported.returned_lost);
-      to_remove.push_back(pair.first);
-    }
-  }
-  for (ResourceId id : to_remove)
-    imported_resources_.erase(id);
+  auto release_and_remove =
+      [lose](std::pair<ResourceId, ImportedResource>& pair) {
+        ImportedResource& imported = pair.second;
+        if (!imported.exported_count) {
+          // Not exported, not up for consideration to be returned here.
+          return false;
+        }
+        imported.exported_count = 0;
+        imported.returned_lost |= lose;
+        if (!imported.marked_for_deletion) {
+          // Was exported, but not removed by the client, so don't return it
+          // yet.
+          return false;
+        }
+
+        imported.release_callback->Run(imported.returned_sync_token,
+                                       imported.returned_lost);
+        // Was exported and removed by the client, so return it now.
+        return true;
+      };
+
+  // This will run |release_and_remove| on each element of |imported_resources_|
+  // and drop any resources from the set that it requests.
+  base::EraseIf(imported_resources_, release_and_remove);
 }
 
 void ClientResourceProvider::ShutdownAndReleaseAllResources() {
diff --git a/components/viz/client/client_resource_provider.h b/components/viz/client/client_resource_provider.h
index 4087b57..4706087b 100644
--- a/components/viz/client/client_resource_provider.h
+++ b/components/viz/client/client_resource_provider.h
@@ -13,6 +13,7 @@
 #include "components/viz/common/resources/release_callback.h"
 #include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/resources/resource_settings.h"
+#include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/resources/single_release_callback.h"
 #include "components/viz/common/resources/transferable_resource.h"
 #include "third_party/khronos/GLES2/gl2.h"
@@ -64,7 +65,7 @@
   // NOTE: if the sync_token is set on any TransferableResource, this will
   // wait on it.
   void ReceiveReturnsFromParent(
-      const std::vector<ReturnedResource>& transferable_resources);
+      std::vector<ReturnedResource> transferable_resources);
 
   // Receives a resource from an external client that can be used in compositor
   // frames, via the returned ResourceId.
diff --git a/components/viz/client/client_resource_provider_unittest.cc b/components/viz/client/client_resource_provider_unittest.cc
index da03c3c..cdb71a9 100644
--- a/components/viz/client/client_resource_provider_unittest.cc
+++ b/components/viz/client/client_resource_provider_unittest.cc
@@ -16,6 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::Each;
 
 namespace viz {
 namespace {
@@ -86,6 +87,8 @@
 class MockReleaseCallback {
  public:
   MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost));
+  MOCK_METHOD3(ReleasedWithId,
+               void(ResourceId id, const gpu::SyncToken& token, bool lost));
 };
 
 TEST_P(ClientResourceProviderTest, TransferableResourceReleased) {
@@ -238,6 +241,65 @@
   DestroyProvider();
 }
 
+TEST_P(ClientResourceProviderTest, TransferableResourceSendToParentManyUnsent) {
+  MockReleaseCallback release;
+
+  // 5 resources to have 2 before and 2 after the one being sent and returned,
+  // to verify the data structures are treated correctly when removing from the
+  // middle. 1 after is not enough as that one will replace the resource being
+  // removed and misses some edge cases. We want another resource after that in
+  // the structure to verify it is also not treated incorrectly.
+  struct Data {
+    TransferableResource tran;
+    ResourceId id;
+  } data[5];
+  for (int i = 0; i < 5; ++i) {
+    data[i].tran = MakeTransferableResource(use_gpu(), 'a', 15);
+    data[i].id = provider().ImportResource(
+        data[i].tran,
+        SingleReleaseCallback::Create(base::BindOnce(
+            &MockReleaseCallback::Released, base::Unretained(&release))));
+  }
+  std::sort(std::begin(data), std::end(data),
+            [](const Data& a, const Data& b) { return a.id < b.id; });
+
+  // Export the resource.
+  std::vector<ResourceId> to_send = {data[2].id};
+  std::vector<TransferableResource> exported;
+  provider().PrepareSendToParent(to_send, &exported, context_provider());
+  ASSERT_EQ(exported.size(), 1u);
+
+  // Exported resource matches except for the id which was mapped
+  // to the local ResourceProvider, and the sync token should be
+  // verified if it's a gpu resource.
+  gpu::SyncToken verified_sync_token = data[2].tran.mailbox_holder.sync_token;
+  if (!data[2].tran.is_software)
+    verified_sync_token.SetVerifyFlush();
+
+  // Exported resources are not released when removed, until the export returns.
+  EXPECT_CALL(release, Released(_, _)).Times(0);
+  provider().RemoveImportedResource(data[2].id);
+
+  // Return the resource, with a sync token if using gpu.
+  std::vector<ReturnedResource> returned;
+  returned.push_back({});
+  returned.back().id = exported[0].id;
+  if (use_gpu())
+    returned.back().sync_token = SyncTokenFromUInt(31);
+  returned.back().count = 1;
+  returned.back().lost = false;
+
+  // The sync token is given to the ReleaseCallback.
+  EXPECT_CALL(release, Released(returned[0].sync_token, false));
+  provider().ReceiveReturnsFromParent(returned);
+
+  EXPECT_CALL(release, Released(_, false)).Times(4);
+  provider().RemoveImportedResource(data[0].id);
+  provider().RemoveImportedResource(data[1].id);
+  provider().RemoveImportedResource(data[3].id);
+  provider().RemoveImportedResource(data[4].id);
+}
+
 TEST_P(ClientResourceProviderTest, TransferableResourceRemovedAfterReturn) {
   MockReleaseCallback release;
   TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
@@ -554,7 +616,7 @@
   provider().PrepareSendToParent({resource}, &list, context_provider());
   EXPECT_EQ(1u, list.size());
 
-  // Drop any exported resources. Yhey are now considered lost for gpu
+  // Drop any exported resources. They are now considered lost for gpu
   // compositing, since gpu resources are modified (in their metadata) while
   // being used by the parent.
   provider().ReleaseAllExportedResources(use_gpu());
@@ -567,5 +629,192 @@
   EXPECT_CALL(release, Released(_, _)).Times(0);
 }
 
+TEST_P(ClientResourceProviderTest, ReleaseMultipleResources) {
+  MockReleaseCallback release;
+
+  // Make 5 resources, put them in a non-sorted order.
+  ResourceId resources[5];
+  for (int i = 0; i < 5; ++i) {
+    TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 1 + i);
+    resources[i] = provider().ImportResource(
+        tran, SingleReleaseCallback::Create(
+                  base::BindOnce(&MockReleaseCallback::ReleasedWithId,
+                                 base::Unretained(&release), i)));
+  }
+
+  // Transfer some resources to the parent, but not in the sorted order.
+  std::vector<TransferableResource> list;
+  provider().PrepareSendToParent({resources[2], resources[0], resources[4]},
+                                 &list, context_provider());
+  EXPECT_EQ(3u, list.size());
+
+  // Receive them back. Since these are not in the same order they were
+  // inserted originally, we verify the ClientResourceProvider can handle
+  // resources being returned (in a group) that are not at the front/back
+  // of its internal storage. IOW This shouldn't crash or corrupt state.
+  std::vector<ReturnedResource> returned_to_child;
+  returned_to_child.push_back(list[0].ToReturnedResource());
+  returned_to_child.push_back(list[1].ToReturnedResource());
+  returned_to_child.push_back(list[2].ToReturnedResource());
+  provider().ReceiveReturnsFromParent(returned_to_child);
+
+  // Remove them from the ClientResourceProvider, they should be returned as
+  // they're no longer exported.
+  EXPECT_CALL(release, ReleasedWithId(0, _, false));
+  provider().RemoveImportedResource(resources[0]);
+  EXPECT_CALL(release, ReleasedWithId(2, _, false));
+  provider().RemoveImportedResource(resources[2]);
+  EXPECT_CALL(release, ReleasedWithId(4, _, false));
+  provider().RemoveImportedResource(resources[4]);
+
+  // These were never exported.
+  EXPECT_CALL(release, ReleasedWithId(1, _, false));
+  EXPECT_CALL(release, ReleasedWithId(3, _, false));
+  provider().RemoveImportedResource(resources[1]);
+  provider().RemoveImportedResource(resources[3]);
+
+  EXPECT_CALL(release, Released(_, false)).Times(0);
+}
+
+TEST_P(ClientResourceProviderTest, ReleaseMultipleResourcesBeforeReturn) {
+  MockReleaseCallback release;
+
+  // Make 5 resources, put them in a non-sorted order.
+  ResourceId resources[5];
+  for (int i = 0; i < 5; ++i) {
+    TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 1 + i);
+    resources[i] = provider().ImportResource(
+        tran, SingleReleaseCallback::Create(
+                  base::BindOnce(&MockReleaseCallback::ReleasedWithId,
+                                 base::Unretained(&release), i)));
+  }
+
+  // Transfer some resources to the parent, but not in the sorted order.
+  std::vector<TransferableResource> list;
+  provider().PrepareSendToParent({resources[2], resources[0], resources[4]},
+                                 &list, context_provider());
+  EXPECT_EQ(3u, list.size());
+
+  // Remove the exported resources from the ClientResourceProvider, they should
+  // not yet be returned, since they are exported.
+  provider().RemoveImportedResource(resources[0]);
+  provider().RemoveImportedResource(resources[2]);
+  provider().RemoveImportedResource(resources[4]);
+
+  // Receive them back now. Since these are not in the same order they were
+  // inserted originally, we verify the ClientResourceProvider can handle
+  // resources being returned (in a group) that are not at the front/back
+  // of its internal storage. IOW This shouldn't crash or corrupt state.
+  std::vector<ReturnedResource> returned_to_child;
+  returned_to_child.push_back(list[0].ToReturnedResource());
+  returned_to_child.push_back(list[1].ToReturnedResource());
+  returned_to_child.push_back(list[2].ToReturnedResource());
+  // The resources are returned immediately since they were previously removed.
+  EXPECT_CALL(release, ReleasedWithId(0, _, false));
+  EXPECT_CALL(release, ReleasedWithId(2, _, false));
+  EXPECT_CALL(release, ReleasedWithId(4, _, false));
+  provider().ReceiveReturnsFromParent(returned_to_child);
+
+  // These were never exported.
+  EXPECT_CALL(release, ReleasedWithId(1, _, false));
+  EXPECT_CALL(release, ReleasedWithId(3, _, false));
+  provider().RemoveImportedResource(resources[1]);
+  provider().RemoveImportedResource(resources[3]);
+
+  EXPECT_CALL(release, Released(_, false)).Times(0);
+}
+
+TEST_P(ClientResourceProviderTest, ReturnDuplicateResourceBeforeRemove) {
+  MockReleaseCallback release;
+
+  // Make 5 resources, put them in a non-sorted order.
+  ResourceId resources[5];
+  for (int i = 0; i < 5; ++i) {
+    TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 1 + i);
+    resources[i] = provider().ImportResource(
+        tran, SingleReleaseCallback::Create(
+                  base::BindOnce(&MockReleaseCallback::ReleasedWithId,
+                                 base::Unretained(&release), i)));
+  }
+
+  // Transfer a resource to the parent, do it twice.
+  std::vector<TransferableResource> list;
+  provider().PrepareSendToParent({resources[2]}, &list, context_provider());
+  list.clear();
+  provider().PrepareSendToParent({resources[2]}, &list, context_provider());
+
+  // Receive the resource back. It's possible that the parent may return
+  // the same ResourceId multiple times in the same message, which we test
+  // for here.
+  std::vector<ReturnedResource> returned_to_child;
+  returned_to_child.push_back(list[0].ToReturnedResource());
+  returned_to_child.push_back(list[0].ToReturnedResource());
+  provider().ReceiveReturnsFromParent(returned_to_child);
+
+  // Remove it from the ClientResourceProvider, it should be returned as
+  // it's no longer exported.
+  EXPECT_CALL(release, ReleasedWithId(2, _, false));
+  provider().RemoveImportedResource(resources[2]);
+
+  // These were never exported.
+  EXPECT_CALL(release, ReleasedWithId(0, _, false));
+  EXPECT_CALL(release, ReleasedWithId(1, _, false));
+  EXPECT_CALL(release, ReleasedWithId(3, _, false));
+  EXPECT_CALL(release, ReleasedWithId(4, _, false));
+  provider().RemoveImportedResource(resources[0]);
+  provider().RemoveImportedResource(resources[1]);
+  provider().RemoveImportedResource(resources[3]);
+  provider().RemoveImportedResource(resources[4]);
+
+  EXPECT_CALL(release, Released(_, false)).Times(0);
+}
+
+TEST_P(ClientResourceProviderTest, ReturnDuplicateResourceAfterRemove) {
+  MockReleaseCallback release;
+
+  // Make 5 resources, put them in a non-sorted order.
+  ResourceId resources[5];
+  for (int i = 0; i < 5; ++i) {
+    TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 1 + i);
+    resources[i] = provider().ImportResource(
+        tran, SingleReleaseCallback::Create(
+                  base::BindOnce(&MockReleaseCallback::ReleasedWithId,
+                                 base::Unretained(&release), i)));
+  }
+
+  // Transfer a resource to the parent, do it twice.
+  std::vector<TransferableResource> list;
+  provider().PrepareSendToParent({resources[2]}, &list, context_provider());
+  list.clear();
+  provider().PrepareSendToParent({resources[2]}, &list, context_provider());
+
+  // Remove it from the ClientResourceProvider, it should not be returned yet
+  // as it's still exported.
+  provider().RemoveImportedResource(resources[2]);
+
+  // Receive the resource back. It's possible that the parent may return
+  // the same ResourceId multiple times in the same message, which we test
+  // for here.
+  std::vector<ReturnedResource> returned_to_child;
+  returned_to_child.push_back(list[0].ToReturnedResource());
+  returned_to_child.push_back(list[0].ToReturnedResource());
+  // Once no longer exported, since it was removed earlier, it will be returned
+  // immediately.
+  EXPECT_CALL(release, ReleasedWithId(2, _, false));
+  provider().ReceiveReturnsFromParent(returned_to_child);
+
+  // These were never exported.
+  EXPECT_CALL(release, ReleasedWithId(0, _, false));
+  EXPECT_CALL(release, ReleasedWithId(1, _, false));
+  EXPECT_CALL(release, ReleasedWithId(3, _, false));
+  EXPECT_CALL(release, ReleasedWithId(4, _, false));
+  provider().RemoveImportedResource(resources[0]);
+  provider().RemoveImportedResource(resources[1]);
+  provider().RemoveImportedResource(resources[3]);
+  provider().RemoveImportedResource(resources[4]);
+
+  EXPECT_CALL(release, Released(_, false)).Times(0);
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index e6ed47b..eb0412a 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -65,9 +65,10 @@
   // TODO(riajiang): Check feature flag as well. https://crbug.com/804888
   // TODO(riajiang): Check kVizDisplayCompositor feature when it works with
   // that config.
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kUseVizHitTestSurfaceLayer) ||
-         base::FeatureList::IsEnabled(kEnableVizHitTestSurfaceLayer);
+  return (base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kUseVizHitTestSurfaceLayer) ||
+          base::FeatureList::IsEnabled(kEnableVizHitTestSurfaceLayer)) &&
+         !IsVizHitTestingDrawQuadEnabled();
 }
 
 bool IsDrawOcclusionEnabled() {
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index d6dfe6e..28a8345 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -39,6 +39,18 @@
 
 namespace viz {
 
+namespace {
+
+// Assign each Display instance a starting value for the the display-trace id,
+// so that multiple Displays all don't start at 0, because that makes it
+// difficult to associate the trace-events with the particular displays.
+int64_t GetStartingTraceId() {
+  static int64_t client = 0;
+  return ((++client & 0xffffffff) << 32);
+}
+
+}  // namespace
+
 Display::Display(
     SharedBitmapManager* bitmap_manager,
     const RendererSettings& settings,
@@ -53,7 +65,9 @@
       skia_output_surface_(skia_output_surface),
       output_surface_(std::move(output_surface)),
       scheduler_(std::move(scheduler)),
-      current_task_runner_(std::move(current_task_runner)) {
+      current_task_runner_(std::move(current_task_runner)),
+      swapped_trace_id_(GetStartingTraceId()),
+      last_acked_trace_id_(swapped_trace_id_) {
   DCHECK(output_surface_);
   DCHECK(frame_sink_id_.is_valid());
   if (scheduler_)
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index fd23ced5..6b3c4ef 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -171,8 +171,8 @@
   base::circular_deque<std::vector<Surface::PresentedCallback>>
       pending_presented_callbacks_;
 
-  int32_t swapped_trace_id_ = 0;
-  int32_t last_acked_trace_id_ = 0;
+  int64_t swapped_trace_id_ = 0;
+  int64_t last_acked_trace_id_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(Display);
 };
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 6de7821..5436917 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -514,6 +514,10 @@
   RunAriaTest(FILE_PATH_LITERAL("aria-dropeffect.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaEditable) {
+  RunAriaTest(FILE_PATH_LITERAL("aria-editable.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
                        AccessibilityAriaErrorMessage) {
   RunAriaTest(FILE_PATH_LITERAL("aria-errormessage.html"));
diff --git a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
index 120b53c..58d6ba7 100644
--- a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
+++ b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
@@ -52,7 +52,12 @@
 BackgroundFetchCrossOriginFilter::BackgroundFetchCrossOriginFilter(
     const url::Origin& source_origin,
     const BackgroundFetchRequestInfo& request) {
-  DCHECK(!request.GetURLChain().empty());
+  if (request.GetURLChain().empty()) {
+    // This can happen if a request is resumed on browser restart.
+    // In that case all the header / url chain info will be lost.
+    // TODO(crbug.com/881314): Make sure the info is propagated.
+    return;
+  }
 
   const GURL& final_url = request.GetURLChain().back();
   const auto& response_header_map = request.GetResponseHeaders();
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index e0ffe6a..bc17768 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -50,6 +50,9 @@
   // TODO(nator): Update this when we support uploads.
   total_downloads_size_ = options_.download_total;
 
+  if (!active_fetch_requests.empty())
+    is_processing_a_request_ = true;
+
   std::vector<std::string> active_guids;
   active_guids.reserve(active_fetch_requests.size());
   for (const auto& request_info : active_fetch_requests)
@@ -80,7 +83,9 @@
   DCHECK_LT(completed_downloads_, total_downloads_);
   DCHECK(request_finished_callback);
   DCHECK(request);
+  DCHECK(!is_processing_a_request_);
 
+  is_processing_a_request_ = true;
   active_request_downloaded_bytes_ = 0;
   active_request_finished_callback_ = std::move(request_finished_callback);
 
@@ -88,6 +93,17 @@
                                 registration_id().origin(), request);
 }
 
+bool BackgroundFetchJobController::IsProcessingARequest() {
+  return is_processing_a_request_;
+}
+
+void BackgroundFetchJobController::Resume(
+    RequestFinishedCallback request_finished_callback) {
+  // At the moment, the Download Service immediately resumes downloading a
+  // request on startup. Ideally we should be able to control when this happens.
+  active_request_finished_callback_ = std::move(request_finished_callback);
+}
+
 void BackgroundFetchJobController::DidStartRequest(
     const scoped_refptr<BackgroundFetchRequestInfo>& request) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -127,6 +143,8 @@
   complete_requests_downloaded_bytes_cache_ += request->GetFileSize();
   ++completed_downloads_;
 
+  is_processing_a_request_ = false;
+
   std::move(active_request_finished_callback_).Run(request);
 }
 
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h
index 32a0586..cad92f0 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -110,6 +110,8 @@
   bool HasMoreRequests() override;
   void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
                     RequestFinishedCallback request_finished_callback) override;
+  bool IsProcessingARequest() override;
+  void Resume(RequestFinishedCallback request_finished_callback) override;
   void Abort(
       blink::mojom::BackgroundFetchFailureReason reason_to_abort) override;
 
@@ -146,6 +148,9 @@
   // Number of the requests that have been completed so far.
   int completed_downloads_ = 0;
 
+  // Whether the DownloadService is processing a request.
+  bool is_processing_a_request_ = false;
+
   // The reason background fetch was aborted.
   blink::mojom::BackgroundFetchFailureReason reason_to_abort_ =
       blink::mojom::BackgroundFetchFailureReason::NONE;
diff --git a/content/browser/background_fetch/background_fetch_scheduler.cc b/content/browser/background_fetch/background_fetch_scheduler.cc
index 63fa719..ec5c2c12 100644
--- a/content/browser/background_fetch/background_fetch_scheduler.cc
+++ b/content/browser/background_fetch/background_fetch_scheduler.cc
@@ -53,8 +53,18 @@
 void BackgroundFetchScheduler::AddJobController(Controller* controller) {
   DCHECK(controller);
 
-  controller_queue_.push_back(controller);
+  if (controller->IsProcessingARequest()) {
+    // There is a resuming download from the previous session, no need to
+    // schedule.
+    DCHECK(!active_controller_);
+    active_controller_ = controller;
+    active_controller_->Resume(
+        base::BindOnce(&BackgroundFetchScheduler::MarkRequestAsComplete,
+                       weak_ptr_factory_.GetWeakPtr()));
+    return;
+  }
 
+  controller_queue_.push_back(controller);
   if (!active_controller_)
     ScheduleDownload();
 }
diff --git a/content/browser/background_fetch/background_fetch_scheduler.h b/content/browser/background_fetch/background_fetch_scheduler.h
index 3c692bd..b830570 100644
--- a/content/browser/background_fetch/background_fetch_scheduler.h
+++ b/content/browser/background_fetch/background_fetch_scheduler.h
@@ -46,6 +46,13 @@
     virtual void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
                               RequestFinishedCallback callback) = 0;
 
+    // Whether the controller has a request that is being serviced by
+    // DownloadService. This can span sessions.
+    virtual bool IsProcessingARequest() = 0;
+
+    // Resumes a fetch started in a previous session.
+    virtual void Resume(RequestFinishedCallback request_finished_callback) = 0;
+
     void Finish(blink::mojom::BackgroundFetchFailureReason reason_to_abort);
 
     const BackgroundFetchRegistrationId& registration_id() const {
diff --git a/content/browser/background_fetch/background_fetch_scheduler_unittest.cc b/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
index 156d262c..d527b2fd 100644
--- a/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
@@ -53,6 +53,8 @@
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(std::move(callback), std::move(request)));
   }
+  bool IsProcessingARequest() override { return false; }
+  void Resume(RequestFinishedCallback callback) override { NOTREACHED(); }
 
  private:
   int jobs_started_ = 0;
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index 7535487..0bf7f3c 100644
--- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -275,8 +275,7 @@
 
     // Register the worker.
     blink::mojom::ServiceWorkerRegistrationOptions options(
-        scope_url, blink::mojom::ScriptType::kClassic,
-        blink::mojom::ServiceWorkerUpdateViaCache::kImports);
+        scope_url, blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 94905e7..0e0cbcd 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -564,6 +564,7 @@
       is_waiting_for_swapout_ack_(false),
       render_frame_created_(false),
       is_waiting_for_beforeunload_ack_(false),
+      beforeunload_dialog_request_cancels_unload_(false),
       unload_ack_is_for_navigation_(false),
       beforeunload_timeout_delay_(base::TimeDelta::FromMilliseconds(
           RenderViewHostImpl::kUnloadTimeoutMS)),
@@ -2318,6 +2319,15 @@
   // Allow at most one attempt to show a beforeunload dialog per navigation.
   RenderFrameHostImpl* beforeunload_initiator = GetBeforeUnloadInitiator();
   if (beforeunload_initiator) {
+    // If the running beforeunload handler wants to display a dialog and the
+    // before-unload type wants to ignore it, then short-circuit the request and
+    // respond as if the user decided to stay on the page, canceling the unload.
+    if (beforeunload_initiator->beforeunload_dialog_request_cancels_unload_) {
+      SendJavaScriptDialogReply(reply_msg, false /* success */,
+                                base::string16());
+      return;
+    }
+
     if (beforeunload_initiator->has_shown_beforeunload_dialog_) {
       // TODO(alexmos): Pass enough data back to renderer to record histograms
       // for Document.BeforeUnloadDialog and add the intervention console
@@ -3692,8 +3702,9 @@
       type == BeforeUnloadType::RENDERER_INITIATED_NAVIGATION;
   DCHECK(for_navigation || !is_reload);
 
-  // Tab close should only dispatch beforeunload on main frames.
-  DCHECK(type != BeforeUnloadType::TAB_CLOSE ||
+  // TAB_CLOSE and DISCARD should only dispatch beforeunload on main frames.
+  DCHECK(type == BeforeUnloadType::BROWSER_INITIATED_NAVIGATION ||
+         type == BeforeUnloadType::RENDERER_INITIATED_NAVIGATION ||
          frame_tree_node_->IsMainFrame());
 
   if (!for_navigation) {
@@ -3750,13 +3761,16 @@
     // Start the hang monitor in case the renderer hangs in the beforeunload
     // handler.
     is_waiting_for_beforeunload_ack_ = true;
+    beforeunload_dialog_request_cancels_unload_ = false;
     unload_ack_is_for_navigation_ = for_navigation;
     send_before_unload_start_time_ = base::TimeTicks::Now();
     if (render_view_host_->GetDelegate()->IsJavaScriptDialogShowing()) {
       // If there is a JavaScript dialog up, don't bother sending the renderer
       // the unload event because it is known unresponsive, waiting for the
-      // reply from the dialog.
-      SimulateBeforeUnloadAck();
+      // reply from the dialog. If this incoming request is for a DISCARD be
+      // sure to reply with |proceed = false|, because the presence of a dialog
+      // indicates that the page can't be discarded.
+      SimulateBeforeUnloadAck(type != BeforeUnloadType::DISCARD);
     } else {
       // Start a timer that will be shared by all frames that need to run
       // beforeunload in the current frame's subtree.
@@ -3764,6 +3778,8 @@
         beforeunload_timeout_->Start(beforeunload_timeout_delay_);
 
       beforeunload_pending_replies_.clear();
+      beforeunload_dialog_request_cancels_unload_ =
+          (type == BeforeUnloadType::DISCARD);
 
       // Run beforeunload in this frame and its cross-process descendant
       // frames, in parallel.
@@ -3856,7 +3872,7 @@
   return found_beforeunload;
 }
 
-void RenderFrameHostImpl::SimulateBeforeUnloadAck() {
+void RenderFrameHostImpl::SimulateBeforeUnloadAck(bool proceed) {
   DCHECK(is_waiting_for_beforeunload_ack_);
   base::TimeTicks approx_renderer_start_time = send_before_unload_start_time_;
 
@@ -3864,7 +3880,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&RenderFrameHostImpl::ProcessBeforeUnloadACK,
-                     weak_ptr_factory_.GetWeakPtr(), true /* proceed */,
+                     weak_ptr_factory_.GetWeakPtr(), proceed,
                      true /* treat_as_final_ack */, approx_renderer_start_time,
                      base::TimeTicks::Now()));
 }
@@ -5276,7 +5292,7 @@
   if (render_view_host_->GetDelegate()->ShouldIgnoreUnresponsiveRenderer())
     return;
 
-  SimulateBeforeUnloadAck();
+  SimulateBeforeUnloadAck(true /* proceed */);
 }
 
 void RenderFrameHostImpl::SetLastCommittedSiteUrl(const GURL& url) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 01f060b..8c4b7a0 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -457,7 +457,12 @@
   enum class BeforeUnloadType {
     BROWSER_INITIATED_NAVIGATION,
     RENDERER_INITIATED_NAVIGATION,
-    TAB_CLOSE
+    TAB_CLOSE,
+    // This reason is used before a tab is discarded in order to free up
+    // resources. When this is used and the handler returns a non-empty string,
+    // the confirmation dialog will not be displayed and the discard will
+    // automatically be canceled.
+    DISCARD,
   };
 
   // Runs the beforeunload handler for this frame and its subframes. |type|
@@ -468,7 +473,7 @@
   void DispatchBeforeUnload(BeforeUnloadType type, bool is_reload);
 
   // Simulate beforeunload ack on behalf of renderer if it's unrenresponsive.
-  void SimulateBeforeUnloadAck();
+  void SimulateBeforeUnloadAck(bool proceed);
 
   // Returns true if a call to DispatchBeforeUnload will actually send the
   // BeforeUnload IPC.  This can be called on a main frame or subframe.  If
@@ -1382,6 +1387,11 @@
   // machine.
   bool is_waiting_for_beforeunload_ack_;
 
+  // Valid only when |is_waiting_for_beforeunload_ack_| is true. This indicates
+  // whether a subsequent request to launch a modal dialog should be honored or
+  // whether it should implicitly cause the unload to be canceled.
+  bool beforeunload_dialog_request_cancels_unload_;
+
   // Valid only when is_waiting_for_beforeunload_ack_ or
   // IsWaitingForUnloadACK is true.  This tells us if the unload request
   // is for closing the entire tab ( = false), or only this RenderFrameHost in
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 078899ab..6d57534 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
@@ -201,14 +202,22 @@
       : message_loop_runner_(new MessageLoopRunner), url_invalidate_count_(0) {}
   ~TestJavaScriptDialogManager() override {}
 
+  // This waits until either WCD::BeforeUnloadFired is called (the unload has
+  // been handled) or JSDM::RunJavaScriptDialog/RunBeforeUnloadDialog is called
+  // (a request to display a dialog has been received).
   void Wait() {
     message_loop_runner_->Run();
     message_loop_runner_ = new MessageLoopRunner;
   }
 
-  DialogClosedCallback& callback() { return callback_; }
+  // Runs the dialog callback.
+  void Run(bool success, const base::string16& user_input) {
+    std::move(callback_).Run(success, user_input);
+  }
 
   int num_beforeunload_dialogs_seen() { return num_beforeunload_dialogs_seen_; }
+  int num_beforeunload_fired_seen() { return num_beforeunload_fired_seen_; }
+  bool proceed() { return proceed_; }
 
   // WebContentsDelegate
 
@@ -217,6 +226,14 @@
     return this;
   }
 
+  void BeforeUnloadFired(WebContents* tab,
+                         bool proceed,
+                         bool* proceed_to_fire_unload) override {
+    ++num_beforeunload_fired_seen_;
+    proceed_ = proceed;
+    message_loop_runner_->Quit();
+  }
+
   // JavaScriptDialogManager
 
   void RunJavaScriptDialog(WebContents* web_contents,
@@ -225,7 +242,10 @@
                            const base::string16& message_text,
                            const base::string16& default_prompt_text,
                            DialogClosedCallback callback,
-                           bool* did_suppress_message) override {}
+                           bool* did_suppress_message) override {
+    callback_ = std::move(callback);
+    message_loop_runner_->Quit();
+  }
 
   void RunBeforeUnloadDialog(WebContents* web_contents,
                              RenderFrameHost* render_frame_host,
@@ -267,6 +287,13 @@
   // The total number of beforeunload dialogs seen by this dialog manager.
   int num_beforeunload_dialogs_seen_ = 0;
 
+  // The total number of BeforeUnloadFired events witnessed by the
+  // WebContentsDelegate.
+  int num_beforeunload_fired_seen_ = 0;
+
+  // The |proceed| value returned by the last unload event.
+  bool proceed_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
 };
 
@@ -338,7 +365,7 @@
   main_frame->GetProcess()->AddFilter(filter.get());
 
   // Answer the dialog.
-  std::move(dialog_manager.callback()).Run(true, base::string16());
+  dialog_manager.Run(true, base::string16());
 
   // There will be no beforeunload ACK, so if the beforeunload ACK timer isn't
   // functioning then the navigation will hang forever and this test will time
@@ -377,7 +404,7 @@
   dialog_manager.Wait();
 
   // Answer the dialog.
-  std::move(dialog_manager.callback()).Run(true, base::string16());
+  dialog_manager.Run(true, base::string16());
   EXPECT_TRUE(WaitForLoadStop(wc));
 
   // The reload should have cleared the user gesture bit, so upon leaving again
@@ -408,7 +435,7 @@
 
   // Cancel the dialog.
   dialog_manager.reset_url_invalidate_count();
-  std::move(dialog_manager.callback()).Run(false, base::string16());
+  dialog_manager.Run(false, base::string16());
   EXPECT_FALSE(wc->IsLoading());
 
   // Verify there are no pending history items after the dialog is cancelled.
@@ -446,13 +473,13 @@
   }
 
   void CloseDialogAndProceed() {
-    std::move(dialog_manager()->callback())
-        .Run(true /* navigation should proceed */, base::string16());
+    dialog_manager_->Run(true /* navigation should proceed */,
+                         base::string16());
   }
 
   void CloseDialogAndCancel() {
-    std::move(dialog_manager()->callback())
-        .Run(false /* navigation should proceed */, base::string16());
+    dialog_manager_->Run(false /* navigation should proceed */,
+                         base::string16());
   }
 
   // Installs a beforeunload handler in the given frame.
@@ -1872,4 +1899,75 @@
   //   EXPECT_EQ(blocked_url, nav_handle_observer.last_committed_url());
 }
 
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       BeforeUnloadDialogSuppressedForDiscard) {
+  WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+  TestJavaScriptDialogManager dialog_manager;
+  wc->SetDelegate(&dialog_manager);
+
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetTestUrl("render_frame_host", "beforeunload.html")));
+  // Disable the hang monitor, otherwise there will be a race between the
+  // beforeunload dialog and the beforeunload hang timer.
+  wc->GetMainFrame()->DisableBeforeUnloadHangMonitorForTesting();
+
+  // Give the page a user gesture so javascript beforeunload works, and then
+  // dispatch a before unload with discard as a reason. This should return
+  // without any dialog being seen.
+  wc->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
+      base::string16());
+  wc->GetMainFrame()->DispatchBeforeUnload(
+      RenderFrameHostImpl::BeforeUnloadType::DISCARD, false);
+  dialog_manager.Wait();
+  EXPECT_EQ(0, dialog_manager.num_beforeunload_dialogs_seen());
+  EXPECT_EQ(1, dialog_manager.num_beforeunload_fired_seen());
+  EXPECT_FALSE(dialog_manager.proceed());
+
+  wc->SetDelegate(nullptr);
+  wc->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       PendingDialogMakesDiscardUnloadReturnFalse) {
+  WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+  TestJavaScriptDialogManager dialog_manager;
+  wc->SetDelegate(&dialog_manager);
+
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetTestUrl("render_frame_host", "beforeunload.html")));
+  // Disable the hang monitor, otherwise there will be a race between the
+  // beforeunload dialog and the beforeunload hang timer.
+  wc->GetMainFrame()->DisableBeforeUnloadHangMonitorForTesting();
+
+  // Give the page a user gesture so javascript beforeunload works, and then
+  // dispatch a before unload with discard as a reason. This should return
+  // without any dialog being seen.
+  wc->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
+      base::string16());
+
+  // Launch an alert javascript dialog. This pending dialog should block a
+  // subsequent discarding before unload request.
+  wc->GetMainFrame()->ExecuteJavaScriptForTests(
+      base::ASCIIToUTF16("setTimeout(function(){alert('hello');}, 10);"));
+  dialog_manager.Wait();
+  EXPECT_EQ(0, dialog_manager.num_beforeunload_dialogs_seen());
+  EXPECT_EQ(0, dialog_manager.num_beforeunload_fired_seen());
+
+  // Dispatch a before unload request while the first is still blocked
+  // on the dialog, and expect it to return false immediately (synchronously).
+  wc->GetMainFrame()->DispatchBeforeUnload(
+      RenderFrameHostImpl::BeforeUnloadType::DISCARD, false);
+  dialog_manager.Wait();
+  EXPECT_EQ(0, dialog_manager.num_beforeunload_dialogs_seen());
+  EXPECT_EQ(1, dialog_manager.num_beforeunload_fired_seen());
+  EXPECT_FALSE(dialog_manager.proceed());
+
+  // Clear the existing javascript dialog so that the associated IPC message
+  // doesn't leak.
+  dialog_manager.Run(true, base::string16());
+
+  wc->SetDelegate(nullptr);
+  wc->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc
index 78db702..c06c66a2 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc
+++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc
@@ -19,9 +19,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/service_manager/public/cpp/bind_source_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/win/direct_write.h"
-
-namespace mswr = Microsoft::WRL;
+#include "third_party/blink/public/common/dwrite_rasterizer_support/dwrite_rasterizer_support.h"
 
 namespace content {
 
@@ -32,18 +30,6 @@
   DWriteFontProxyImplUnitTest()
       : binding_(&impl_, mojo::MakeRequest(&dwrite_font_proxy_)) {}
 
-  bool IsDWrite2Available() {
-    mswr::ComPtr<IDWriteFactory> factory;
-    gfx::win::CreateDWriteFactory(&factory);
-    mswr::ComPtr<IDWriteFactory2> factory2;
-    factory.As<IDWriteFactory2>(&factory2);
-
-    if (!factory2.Get()) {
-      // IDWriteFactory2 is expected to not be available before Win8.1
-      EXPECT_LT(base::win::GetVersion(), base::win::VERSION_WIN8_1);
-    }
-    return factory2.Get();
-  }
   mojom::DWriteFontProxy& dwrite_font_proxy() { return *dwrite_font_proxy_; }
 
   base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -119,7 +105,7 @@
 }
 
 TEST_F(DWriteFontProxyImplUnitTest, MapCharacter) {
-  if (!IsDWrite2Available())
+  if (!blink::DWriteRasterizerSupport::IsDWriteFactory2Available())
     return;
 
   mojom::MapCharactersResultPtr result;
@@ -140,7 +126,7 @@
 }
 
 TEST_F(DWriteFontProxyImplUnitTest, MapCharacterInvalidCharacter) {
-  if (!IsDWrite2Available())
+  if (!blink::DWriteRasterizerSupport::IsDWriteFactory2Available())
     return;
 
   mojom::MapCharactersResultPtr result;
@@ -157,7 +143,7 @@
 }
 
 TEST_F(DWriteFontProxyImplUnitTest, MapCharacterInvalidAfterValid) {
-  if (!IsDWrite2Available())
+  if (!blink::DWriteRasterizerSupport::IsDWriteFactory2Available())
     return;
 
   mojom::MapCharactersResultPtr result;
diff --git a/content/browser/renderer_host/input/compositor_event_ack_browsertest.cc b/content/browser/renderer_host/input/compositor_event_ack_browsertest.cc
index 835b21e..dda80454 100644
--- a/content/browser/renderer_host/input/compositor_event_ack_browsertest.cc
+++ b/content/browser/renderer_host/input/compositor_event_ack_browsertest.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #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"
@@ -245,12 +246,17 @@
                        MAYBE_TouchStartDuringFling) {
   LoadURL(kBlockingTouchStartDataURL);
 
+  // Send the touch events via routing since they need to be registered by the
+  // TouchEventAckQueue.
+  auto* root_view = GetWidgetHost()->GetView();
+  auto* input_event_router = GetWidgetHost()->delegate()->GetInputEventRouter();
+
   // Send a TouchStart so that we can set allowed touch action to Auto.
   SyntheticWebTouchEvent touch_event;
   touch_event.PressPoint(50, 50);
   touch_event.SetTimeStamp(ui::EventTimeForNow());
-  GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch_event,
-                                                    ui::LatencyInfo());
+  input_event_router->RouteTouchEvent(root_view, &touch_event,
+                                      ui::LatencyInfo());
   GetWidgetHost()->input_router()->OnSetTouchAction(cc::kTouchActionAuto);
 
   // Send GSB to start scrolling sequence.
@@ -282,8 +288,12 @@
     observer.WaitForMetadataChange();
 
   touch_event.ReleasePoint(0);
-  GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch_event,
-                                                    ui::LatencyInfo());
+  //  TODO(wjmaclean): Figure out why we can send two touch events with the same
+  //  id, and not only does it work, it fails to work if we give the second
+  //  event a unique id!
+  //  touch_event.unique_touch_event_id = ui::GetNextTouchEventId();
+  input_event_router->RouteTouchEvent(root_view, &touch_event,
+                                      ui::LatencyInfo());
   touch_event.ResetPoints();
 
   // Send a touch start event and wait for its ack. The touch start must be
@@ -294,8 +304,8 @@
                                                WebInputEvent::kTouchStart);
   touch_event.PressPoint(50, 50);
   touch_event.SetTimeStamp(ui::EventTimeForNow());
-  GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch_event,
-                                                    ui::LatencyInfo());
+  input_event_router->RouteTouchEvent(root_view, &touch_event,
+                                      ui::LatencyInfo());
   touch_start_ack_observer.Wait();
 }
 
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 3d7a4553..6fe5543 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -117,7 +117,7 @@
  private:
   friend class InputRouterImplTest;
   friend class MockRenderWidgetHost;
-  friend class RenderWidgetHostBrowserTest;
+  friend class RenderWidgetHostSitePerProcessTest;
 
   // Keeps track of last position of touch points and sets MovementXY for them.
   void SetMovementXYForTouchPoints(blink::WebTouchEvent* event);
diff --git a/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc b/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
index 3b1595d..a26f229a 100644
--- a/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
+++ b/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #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"
@@ -141,14 +142,14 @@
   }
 
   void DoTouchMove() {
-    SyntheticWebTouchEvent kEvents[4];
-    kEvents[0].PressPoint(10, 10);
-    kEvents[1].PressPoint(10, 10);
-    kEvents[1].MovePoint(0, 20, 20);
-    kEvents[2].PressPoint(10, 10);
-    kEvents[2].MovePoint(0, 30, 30);
-    kEvents[3].PressPoint(10, 10);
-    kEvents[3].MovePoint(0, 35, 40);
+    SyntheticWebTouchEvent events[4];
+    events[0].PressPoint(10, 10);
+    events[1].PressPoint(10, 10);
+    events[1].MovePoint(0, 20, 20);
+    events[2].PressPoint(10, 10);
+    events[2].MovePoint(0, 30, 30);
+    events[3].PressPoint(10, 10);
+    events[3].MovePoint(0, 35, 40);
 
     // Send a click event to cause some jankiness. This is done via a click
     // event as ExecuteScript is synchronous.
@@ -157,8 +158,11 @@
     auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
         GetWidgetHost(), blink::WebInputEvent::kTouchMove);
 
-    for (const auto& event : kEvents)
-      GetWidgetHost()->ForwardEmulatedTouchEvent(event, nullptr);
+    auto* root_view = GetWidgetHost()->GetView();
+    auto* input_event_router =
+        GetWidgetHost()->delegate()->GetInputEventRouter();
+    for (auto& event : events)
+      input_event_router->RouteTouchEvent(root_view, &event, ui::LatencyInfo());
 
     // Runs until we get the InputMsgAck callback.
     EXPECT_EQ(INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING,
diff --git a/content/browser/renderer_host/input/touch_input_browsertest.cc b/content/browser/renderer_host/input/touch_input_browsertest.cc
index ddab75b..181dcb7 100644
--- a/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -12,7 +12,9 @@
 #include "build/build_config.h"
 #include "components/viz/common/features.h"
 #include "content/browser/gpu/compositor_util.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/input/synthetic_web_input_event_builders.h"
 #include "content/common/input_messages.h"
@@ -99,8 +101,11 @@
 
  protected:
   void SendTouchEvent(SyntheticWebTouchEvent* event) {
-    GetWidgetHost()->ForwardTouchEventWithLatencyInfo(*event,
-                                                      ui::LatencyInfo());
+    auto* root_view = GetWidgetHost()->GetView();
+    auto* input_event_router =
+        GetWidgetHost()->delegate()->GetInputEventRouter();
+    input_event_router->RouteTouchEvent(root_view, event, ui::LatencyInfo());
+
     event->ResetPoints();
   }
   void LoadURL() {
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 86f8645c..d3a73898 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
@@ -178,7 +178,6 @@
         new TestTouchSelectionControllerClientAura(rwhva);
     rwhva->SetSelectionControllerClientForTest(
         base::WrapUnique(selection_controller_client_));
-    rwhva->event_handler()->disable_input_event_router_for_testing();
   }
 
  protected:
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index 373ecd28..b804108 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -4,17 +4,8 @@
 
 #include <vector>
 
-#include "base/optional.h"
 #include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/quads/compositor_frame.h"
-#include "components/viz/common/quads/render_pass.h"
-#include "components/viz/common/surfaces/local_surface_id.h"
-#include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/input/input_router_impl.h"
 #include "content/browser/renderer_host/input/touch_action_filter.h"
 #include "content/browser/renderer_host/input/touch_emulator.h"
@@ -25,37 +16,24 @@
 #include "content/common/input/synthetic_web_input_event_builders.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #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"
 #include "third_party/blink/public/platform/web_input_event.h"
 #include "third_party/blink/public/platform/web_mouse_event.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/events/base_event_utils.h"
-#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/latency/latency_info.h"
 
 namespace content {
 
-class RenderWidgetHostBrowserTest : public ContentBrowserTest {
- protected:
-  WebContentsImpl* web_contents() const {
-    return static_cast<WebContentsImpl*>(shell()->web_contents());
-  }
-
-  TouchActionFilter* GetTouchActionFilterForWidget(RenderWidgetHostImpl* rwhi) {
-    return &static_cast<InputRouterImpl*>(rwhi->input_router())
-                ->touch_action_filter_;
-  }
-};
-
-// The --site-per-porcess version of RenderWidgetHostBrowserTest.
-class RenderWidgetHostSitePerProcessTest : public RenderWidgetHostBrowserTest {
+// This test enables --site-per-porcess flag.
+class RenderWidgetHostSitePerProcessTest : public ContentBrowserTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     IsolateAllSitesForTesting(command_line);
@@ -66,70 +44,17 @@
     SetupCrossSiteRedirector(embedded_test_server());
     ASSERT_TRUE(embedded_test_server()->Start());
   }
-};
 
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostBrowserTest,
-                       ProhibitsCopyRequestsFromRenderer) {
-  NavigateToURL(shell(), GURL("data:text/html,<!doctype html>"
-                              "<body style='background-color: red;'></body>"));
-
-  // Wait for the view's surface to become available.
-  auto* const view = static_cast<RenderWidgetHostViewBase*>(
-      shell()->web_contents()->GetRenderWidgetHostView());
-  while (!view->IsSurfaceAvailableForCopy()) {
-    base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(),
-        base::TimeDelta::FromMilliseconds(250));
-    run_loop.Run();
+ protected:
+  WebContentsImpl* web_contents() const {
+    return static_cast<WebContentsImpl*>(shell()->web_contents());
   }
 
-  // The browser process should be allowed to make a CopyOutputRequest.
-  bool did_receive_copy_result = false;
-  base::RunLoop run_loop;
-  view->CopyFromSurface(gfx::Rect(), gfx::Size(),
-                        base::BindOnce(
-                            [](bool* success, base::OnceClosure quit_closure,
-                               const SkBitmap& bitmap) {
-                              *success = !bitmap.drawsNothing();
-                              std::move(quit_closure).Run();
-                            },
-                            &did_receive_copy_result, run_loop.QuitClosure()));
-  run_loop.Run();
-  ASSERT_TRUE(did_receive_copy_result);
-
-  // Create a simulated-from-renderer CompositorFrame with a CopyOutputRequest.
-  viz::CompositorFrame frame;
-  std::unique_ptr<viz::RenderPass> pass = viz::RenderPass::Create();
-  const gfx::Rect output_rect =
-      gfx::Rect(view->GetCompositorViewportPixelSize());
-  pass->SetNew(1 /* render pass id */, output_rect, output_rect,
-               gfx::Transform());
-  bool did_receive_aborted_copy_result = false;
-  pass->copy_requests.push_back(std::make_unique<viz::CopyOutputRequest>(
-      viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
-      base::BindOnce(
-          [](bool* got_nothing, std::unique_ptr<viz::CopyOutputResult> result) {
-            *got_nothing = result->IsEmpty();
-          },
-          &did_receive_aborted_copy_result)));
-  frame.render_pass_list.push_back(std::move(pass));
-
-  // Submit the frame and expect the renderer to be instantly killed.
-  auto* const host = RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
-  RenderProcessHostKillWaiter waiter(host->GetProcess());
-  host->SubmitCompositorFrame(viz::LocalSurfaceId(), std::move(frame),
-                              base::nullopt, 0);
-  base::Optional<bad_message::BadMessageReason> result = waiter.Wait();
-  ASSERT_TRUE(result.has_value());
-  EXPECT_EQ(bad_message::RWH_COPY_REQUEST_ATTEMPT, *result);
-
-  // Check that the copy request result callback received an empty result. In a
-  // normal browser, the requestor (in the render process) might never see a
-  // response to the copy request before the process is killed. Nevertheless,
-  // ensure the result is empty, just in case there is a race.
-  EXPECT_TRUE(did_receive_aborted_copy_result);
-}
+  TouchActionFilter* GetTouchActionFilterForWidget(RenderWidgetHostImpl* rwhi) {
+    return &static_cast<InputRouterImpl*>(rwhi->input_router())
+                ->touch_action_filter_;
+  }
+};
 
 class TestInputEventObserver : public RenderWidgetHost::InputEventObserver {
  public:
@@ -163,8 +88,7 @@
   blink::WebInputEvent::Type acked_touch_event_type_;
 };
 
-class RenderWidgetHostTouchEmulatorBrowserTest
-    : public RenderWidgetHostBrowserTest {
+class RenderWidgetHostTouchEmulatorBrowserTest : public ContentBrowserTest {
  public:
   RenderWidgetHostTouchEmulatorBrowserTest()
       : view_(nullptr),
@@ -174,7 +98,7 @@
         simulated_event_time_delta_(base::TimeDelta::FromMilliseconds(100)) {}
 
   void SetUpOnMainThread() override {
-    RenderWidgetHostBrowserTest::SetUpOnMainThread();
+    ContentBrowserTest::SetUpOnMainThread();
 
     NavigateToURL(shell(),
                   GURL("data:text/html,<!doctype html>"
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 4488cb5..a57fc144 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2845,16 +2845,6 @@
     viz::CompositorFrame frame,
     base::Optional<viz::HitTestRegionList> hit_test_region_list,
     uint64_t submit_time) {
-  // Ensure there are no CopyOutputRequests stowed-away in the CompositorFrame.
-  // For security/privacy reasons, renderers are not allowed to make copy
-  // requests because they could use this to gain access to content from another
-  // domain (e.g., in a child frame).
-  if (frame.HasCopyOutputRequests()) {
-    bad_message::ReceivedBadMessage(GetProcess(),
-                                    bad_message::RWH_COPY_REQUEST_ATTEMPT);
-    return;
-  }
-
   last_received_content_source_id_ = frame.metadata.content_source_id;
 
   if (enable_surface_synchronization_) {
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 3d2fed7..7c35654 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 
+#include <algorithm>
+#include <deque>
 #include <vector>
 
 #include "base/debug/crash_logging.h"
@@ -82,6 +84,142 @@
 
 namespace content {
 
+// A class to implement a queue for tracking outbound TouchEvents, and making
+// sure that their acks are returned to the appropriate root view in order.
+// This is important to ensure proper operation of the GestureProvider.
+// Some challenges include:
+// * differentiating between native and emulated TouchEvents, as the latter ack
+//   to the TouchEmulator's GestureProvider,
+// * making sure all events from destroyed renderers are acked properly, and
+//   without delaying acks from other renderers, and
+// * making sure events are only acked if the root_view (at the time of the
+//   out-bound event) is still valid.
+// Some of this logic, e.g. the last item above, is shared with
+// RenderWidgetHostViewBase.
+class TouchEventAckQueue {
+ public:
+  enum class TouchEventAckStatus { TouchEventNotAcked, TouchEventAcked };
+  enum class TouchEventSource { SystemTouchEvent, EmulatedTouchEvent };
+  struct AckData {
+    uint32_t touch_event_id;
+    RenderWidgetHostViewBase* target_view;
+    RenderWidgetHostViewBase* root_view;
+    TouchEventSource touch_event_source;
+    TouchEventAckStatus touch_event_ack_status;
+    InputEventAckState ack_result;
+  };
+
+  TouchEventAckQueue() {}
+
+  void Add(uint32_t touch_event_id,
+           RenderWidgetHostViewBase* target_view,
+           RenderWidgetHostViewBase* root_view,
+           TouchEventSource touch_event_source,
+           TouchEventAckStatus touch_event_ack_status,
+           InputEventAckState ack_result);
+
+  void Add(uint32_t touch_event_id,
+           RenderWidgetHostViewBase* target_view,
+           RenderWidgetHostViewBase* root_view,
+           TouchEventSource touch_event_source);
+
+  void MarkAcked(uint32_t touch_event_id,
+                 InputEventAckState ack_result,
+                 RenderWidgetHostViewBase* target_view);
+
+  void UpdateQueueAfterTargetDestroyed(RenderWidgetHostViewBase* target_view);
+
+ private:
+  void ProcessAckedTouchEvents();
+  void ReportTouchEventAckQueueUmaStats();
+
+  std::deque<AckData> ack_queue_;
+};
+
+void TouchEventAckQueue::Add(uint32_t touch_event_id,
+                             RenderWidgetHostViewBase* target_view,
+                             RenderWidgetHostViewBase* root_view,
+                             TouchEventSource touch_event_source,
+                             TouchEventAckStatus touch_event_ack_status,
+                             InputEventAckState ack_result) {
+  AckData data = {
+      touch_event_id, target_view, root_view, touch_event_source,
+      touch_event_ack_status, ack_result};
+  ack_queue_.push_back(data);
+  if (touch_event_ack_status == TouchEventAckStatus::TouchEventAcked)
+    ProcessAckedTouchEvents();
+  ReportTouchEventAckQueueUmaStats();
+}
+
+void TouchEventAckQueue::Add(uint32_t touch_event_id,
+                             RenderWidgetHostViewBase* target_view,
+                             RenderWidgetHostViewBase* root_view,
+                             TouchEventSource touch_event_source) {
+  Add(touch_event_id, target_view, root_view, touch_event_source,
+      TouchEventAckStatus::TouchEventNotAcked, INPUT_EVENT_ACK_STATE_UNKNOWN);
+}
+
+void TouchEventAckQueue::MarkAcked(uint32_t touch_event_id,
+                                   InputEventAckState ack_result,
+                                   RenderWidgetHostViewBase* target_view) {
+  auto it = find_if(ack_queue_.begin(), ack_queue_.end(),
+                    [touch_event_id](AckData data) {
+                      return data.touch_event_id == touch_event_id;
+                    });
+  if (it == ack_queue_.end())
+    return;
+  DCHECK(it->touch_event_ack_status != TouchEventAckStatus::TouchEventAcked);
+  DCHECK(target_view && target_view == it->target_view);
+  it->touch_event_ack_status = TouchEventAckStatus::TouchEventAcked;
+  it->ack_result = ack_result;
+  ProcessAckedTouchEvents();
+}
+
+void TouchEventAckQueue::ProcessAckedTouchEvents() {
+  if (ack_queue_.empty())
+    return;
+
+  // TODO(wjmaclean): modify the following loop to actually forward the acks
+  // to the root_view. Must verify that the root_view at the time the event
+  // was registered still exists.
+  while (!ack_queue_.empty() && ack_queue_.front().touch_event_ack_status ==
+                                    TouchEventAckStatus::TouchEventAcked) {
+    // TODO(wjmaclean): We will eventually ack touch events to the root_view
+    // here. Each ack will require confirmation that the touch event's root
+    // view (at the time of event dispatch) is still valid, otherwise we just
+    // discard the ack.
+    ack_queue_.pop_front();
+  }
+}
+
+void TouchEventAckQueue::ReportTouchEventAckQueueUmaStats() {
+  size_t count = ack_queue_.size();
+  UMA_HISTOGRAM_COUNTS_10000("Event.FrameEventRouting.TouchEventAckQueueSize",
+                             count);
+  // TODO(wjmaclean): is it worth also recording how many different renderers
+  // are waiting on touch event acks at the time of reporting?
+}
+
+void TouchEventAckQueue::UpdateQueueAfterTargetDestroyed(
+    RenderWidgetHostViewBase* target_view) {
+  // If a queue entry's root view is being destroyed, just delete it.
+  ack_queue_.erase(remove_if(ack_queue_.begin(), ack_queue_.end(),
+                             [target_view](AckData data) {
+                               return data.root_view == target_view;
+                             }),
+                   ack_queue_.end());
+
+  // Otherwise, mark its status accordingly.
+  for_each(ack_queue_.begin(), ack_queue_.end(), [target_view](AckData data) {
+    if (data.target_view == target_view) {
+      data.touch_event_ack_status = TouchEventAckStatus::TouchEventAcked;
+      data.ack_result = INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
+    }
+  });
+
+  ProcessAckedTouchEvents();
+}
+
 void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed(
     RenderWidgetHostViewBase* view) {
   // RenderWidgetHostViewBase::RemoveObserver() should only ever be called
@@ -106,6 +244,7 @@
     touch_target_.target = nullptr;
     active_touches_ = 0;
   }
+  touch_event_ack_queue_->UpdateQueueAfterTargetDestroyed(view);
 
   if (view == wheel_target_.target)
     wheel_target_.target = nullptr;
@@ -199,6 +338,7 @@
       gesture_pinch_did_send_scroll_begin_(false),
       event_targeter_(std::make_unique<RenderWidgetTargeter>(this)),
       use_viz_hit_test_(features::IsVizHitTestingEnabled()),
+      touch_event_ack_queue_(new TouchEventAckQueue),
       weak_ptr_factory_(this) {}
 
 RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() {
@@ -561,7 +701,8 @@
     RenderWidgetHostViewBase* target,
     const blink::WebTouchEvent& touch_event,
     const ui::LatencyInfo& latency,
-    const base::Optional<gfx::PointF>& target_location) {
+    const base::Optional<gfx::PointF>& target_location,
+    bool is_emulated_touchevent) {
   DCHECK(blink::WebInputEvent::IsTouchEventType(touch_event.GetType()) &&
          touch_event.GetType() != blink::WebInputEvent::kTouchScrollStarted);
 
@@ -604,7 +745,15 @@
     base::debug::DumpWithoutCrashing();
   }
 
+  TouchEventAckQueue::TouchEventSource event_source =
+      is_emulated_touchevent
+          ? TouchEventAckQueue::TouchEventSource::EmulatedTouchEvent
+          : TouchEventAckQueue::TouchEventSource::SystemTouchEvent;
   if (!touch_target_.target) {
+    touch_event_ack_queue_->Add(
+        touch_event.unique_touch_event_id, nullptr, root_view, event_source,
+        TouchEventAckQueue::TouchEventAckStatus::TouchEventAcked,
+        INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
     TouchEventWithLatencyInfo touch_with_latency(touch_event, latency);
     root_view->ProcessAckedTouchEvent(touch_with_latency,
                                       INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
@@ -619,6 +768,9 @@
     }
   }
 
+  touch_event_ack_queue_->Add(touch_event.unique_touch_event_id,
+                              touch_target_.target, root_view, event_source);
+
   blink::WebTouchEvent event(touch_event);
   TransformEventTouchPositions(&event, touch_target_.delta);
   touch_target_.target->ProcessTouchEvent(event, latency);
@@ -631,6 +783,8 @@
     const TouchEventWithLatencyInfo& event,
     InputEventAckState ack_result,
     RenderWidgetHostViewBase* view) {
+  touch_event_ack_queue_->MarkAcked(event.event.unique_touch_event_id,
+                                    ack_result, view);
   // TODO(wjmaclean): Eventually we will keep track of which outgoing touch
   // events are emulated and which aren't, so the decision to hand off to the
   // touch emulator won't just rely on the existence of the touch emulator.
@@ -1441,8 +1595,8 @@
                                         INPUT_EVENT_ACK_STATE_CONSUMED);
       return;
     }
-    DispatchTouchEvent(root_view, target, touch_event, latency,
-                       target_location);
+    DispatchTouchEvent(root_view, target, touch_event, latency, target_location,
+                       false /* not emulated */);
     return;
   }
   if (blink::WebInputEvent::IsGestureEventType(event.GetType())) {
@@ -1503,7 +1657,7 @@
   gfx::PointF transformed_point = target->TransformRootPointToViewCoordSpace(
       gfx::PointF(position_in_widget.x, position_in_widget.y));
   DispatchTouchEvent(last_emulated_event_root_view_, target, event,
-                     ui::LatencyInfo(), transformed_point);
+                     ui::LatencyInfo(), transformed_point, true /* emulated */);
 }
 
 void RenderWidgetHostInputEventRouter::SetCursor(const WebCursor& cursor) {
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index c6db0202..de43b92e 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -60,6 +60,7 @@
 class RenderWidgetHostViewBase;
 class RenderWidgetTargeter;
 class TouchEmulator;
+class TouchEventAckQueue;
 
 // Class owned by WebContentsImpl for the purpose of directing input events
 // to the correct RenderWidgetHost on pages with multiple RenderWidgetHosts.
@@ -253,7 +254,8 @@
                           RenderWidgetHostViewBase* target,
                           const blink::WebTouchEvent& touch_event,
                           const ui::LatencyInfo& latency,
-                          const base::Optional<gfx::PointF>& target_location);
+                          const base::Optional<gfx::PointF>& target_location,
+                          bool is_emulated);
   // Assumes |gesture_event| has coordinates in root view's coordinate space.
   void DispatchTouchscreenGestureEvent(
       RenderWidgetHostViewBase* root_view,
@@ -330,6 +332,7 @@
   bool events_being_flushed_ = false;
 
   std::unique_ptr<TouchEmulator> touch_emulator_;
+  std::unique_ptr<TouchEventAckQueue> touch_event_ack_queue_;
 
   base::WeakPtrFactory<RenderWidgetHostInputEventRouter> weak_ptr_factory_;
 
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index eb96a73..5dac55e 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -125,8 +125,8 @@
         options, context()->storage()->NewRegistrationId(),
         context()->AsWeakPtr());
     pair.second = base::MakeRefCounted<ServiceWorkerVersion>(
-        pair.first.get(), script_url, blink::mojom::ScriptType::kClassic,
-        context()->storage()->NewVersionId(), context()->AsWeakPtr());
+        pair.first.get(), script_url, context()->storage()->NewVersionId(),
+        context()->AsWeakPtr());
     return pair;
   }
 
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index af48553..8a2f70b 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -652,8 +652,8 @@
     registration_->set_last_update_check(base::Time::Now());
 
     version_ = new ServiceWorkerVersion(
-        registration_.get(), embedded_test_server()->GetURL(worker_url),
-        blink::mojom::ScriptType::kClassic,
+        registration_.get(),
+        embedded_test_server()->GetURL(worker_url),
         wrapper()->context()->storage()->NewVersionId(),
         wrapper()->context()->AsWeakPtr());
 
@@ -688,7 +688,6 @@
     scoped_refptr<ServiceWorkerVersion> waiting_version(
         new ServiceWorkerVersion(
             registration_.get(), embedded_test_server()->GetURL(worker_url),
-            blink::mojom::ScriptType::kClassic,
             wrapper()->context()->storage()->NewVersionId(),
             wrapper()->context()->AsWeakPtr()));
     waiting_version->set_fetch_handler_existence(
@@ -1473,7 +1472,6 @@
   // Make options. Set to kAll so updating exercises the browser cache.
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL(kScope),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kAll);
 
   // Register and wait for activation.
@@ -1606,7 +1604,6 @@
   observer->Init();
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL(kPageUrl),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   public_context()->RegisterServiceWorker(
       embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -1651,7 +1648,6 @@
   observer->Init();
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL(kPageUrl),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   public_context()->RegisterServiceWorker(
       embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -1697,7 +1693,6 @@
 
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL(kPageUrl),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   public_context()->RegisterServiceWorker(
       embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -1726,7 +1721,6 @@
   observer->Init();
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL(kPageUrl),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   public_context()->RegisterServiceWorker(
       embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -1778,8 +1772,7 @@
       "/service_worker/fetch_event_respond_with_fetch.js");
 
   blink::mojom::ServiceWorkerRegistrationOptions options(
-      scope, blink::mojom::ScriptType::kClassic,
-      blink::mojom::ServiceWorkerUpdateViaCache::kNone);
+      scope, blink::mojom::ServiceWorkerUpdateViaCache::kNone);
   public_context()->RegisterServiceWorker(
       worker_url, options,
       base::BindOnce(&ExpectResultAndRun, true, base::DoNothing()));
@@ -1882,8 +1875,7 @@
     observer->Init();
 
     blink::mojom::ServiceWorkerRegistrationOptions options(
-        scope, blink::mojom::ScriptType::kClassic,
-        blink::mojom::ServiceWorkerUpdateViaCache::kImports);
+        scope, blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     public_context()->RegisterServiceWorker(
         worker_url, options,
         base::BindOnce(&ExpectResultAndRun, true, base::DoNothing()));
@@ -2629,7 +2621,7 @@
       new WorkerActivatedObserver(wrapper());
   observer->Init();
   blink::mojom::ServiceWorkerRegistrationOptions options(
-      https_server.GetURL(kPageUrl), blink::mojom::ScriptType::kClassic,
+      https_server.GetURL(kPageUrl),
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   public_context()->RegisterServiceWorker(
       https_server.GetURL(kWorkerUrl), options,
@@ -2668,7 +2660,6 @@
   observer->Init();
   blink::mojom::ServiceWorkerRegistrationOptions options(
       embedded_test_server()->GetURL(kPageUrl),
-      blink::mojom::ScriptType::kClassic,
       blink::mojom::ServiceWorkerUpdateViaCache::kImports);
   public_context()->RegisterServiceWorker(
       embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -2810,7 +2801,6 @@
     base::RunLoop run_loop;
     blink::mojom::ServiceWorkerRegistrationOptions options(
         embedded_test_server()->GetURL(kScope),
-        blink::mojom::ScriptType::kClassic,
         blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     public_context()->RegisterServiceWorker(
         embedded_test_server()->GetURL("/does/not/exist"), options,
@@ -2824,7 +2814,6 @@
     base::RunLoop run_loop;
     blink::mojom::ServiceWorkerRegistrationOptions options(
         embedded_test_server()->GetURL(kScope),
-        blink::mojom::ScriptType::kClassic,
         blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     public_context()->RegisterServiceWorker(
         embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -2839,7 +2828,6 @@
     base::RunLoop run_loop;
     blink::mojom::ServiceWorkerRegistrationOptions options(
         embedded_test_server()->GetURL(kScope),
-        blink::mojom::ScriptType::kClassic,
         blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     public_context()->RegisterServiceWorker(
         embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -3178,7 +3166,6 @@
     observer->Init();
     blink::mojom::ServiceWorkerRegistrationOptions options(
         embedded_test_server()->GetURL(kPageUrl),
-        blink::mojom::ScriptType::kClassic,
         blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     public_context()->RegisterServiceWorker(
         embedded_test_server()->GetURL(kWorkerUrl), options,
@@ -3300,7 +3287,7 @@
         new WorkerActivatedObserver(wrapper());
     observer->Init();
     blink::mojom::ServiceWorkerRegistrationOptions options(
-        cross_origin_server_.GetURL(scope), blink::mojom::ScriptType::kClassic,
+        cross_origin_server_.GetURL(scope),
         blink::mojom::ServiceWorkerUpdateViaCache::kImports);
     public_context()->RegisterServiceWorker(
         cross_origin_server_.GetURL(script), options,
diff --git a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index 661fb389..692d21d 100644
--- a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -79,9 +79,9 @@
     options.scope = scope_;
     registration_ = base::MakeRefCounted<ServiceWorkerRegistration>(
         options, 1L, context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(
-        registration_.get(), script_url_, blink::mojom::ScriptType::kClassic,
-        context()->storage()->NewVersionId(), context()->AsWeakPtr());
+    version_ = new ServiceWorkerVersion(registration_.get(), script_url_,
+                                        context()->storage()->NewVersionId(),
+                                        context()->AsWeakPtr());
     SetUpProvider();
 
     std::unique_ptr<MockHttpProtocolHandler> handler(
@@ -398,8 +398,8 @@
 TEST_F(ServiceWorkerContextRequestHandlerTest, Incumbent) {
   // Make an incumbent version.
   scoped_refptr<ServiceWorkerVersion> incumbent = new ServiceWorkerVersion(
-      registration_.get(), script_url_, blink::mojom::ScriptType::kClassic,
-      context()->storage()->NewVersionId(), context()->AsWeakPtr());
+      registration_.get(), script_url_, context()->storage()->NewVersionId(),
+      context()->AsWeakPtr());
   incumbent->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   std::vector<ServiceWorkerDatabase::ResourceRecord> resources = {
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index d4d3809..7ca8519 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -307,8 +307,8 @@
       options, 1l /* dummy registration id */, context()->AsWeakPtr());
 
   auto version = base::MakeRefCounted<ServiceWorkerVersion>(
-      registration.get(), script_url, blink::mojom::ScriptType::kClassic,
-      2l /* dummy version id */, context()->AsWeakPtr());
+      registration.get(), script_url, 2l /* dummy version id */,
+      context()->AsWeakPtr());
 
   ServiceWorkerRemoteProviderEndpoint endpoint;
   std::unique_ptr<ServiceWorkerProviderHost> host =
@@ -341,8 +341,8 @@
       options, 1l /* dummy registration id */, context()->AsWeakPtr());
 
   auto version = base::MakeRefCounted<ServiceWorkerVersion>(
-      registration.get(), script_url, blink::mojom::ScriptType::kClassic,
-      2l /* dummy version id */, context()->AsWeakPtr());
+      registration.get(), script_url, 2l /* dummy version id */,
+      context()->AsWeakPtr());
 
   TestServiceWorkerContextObserver observer(context_wrapper());
 
@@ -368,8 +368,8 @@
       options, 1l /* dummy registration id */, context()->AsWeakPtr());
 
   auto version = base::MakeRefCounted<ServiceWorkerVersion>(
-      registration.get(), script_url, blink::mojom::ScriptType::kClassic,
-      2l /* dummy version id */, context()->AsWeakPtr());
+      registration.get(), script_url, 2l /* dummy version id */,
+      context()->AsWeakPtr());
 
   TestServiceWorkerContextObserver observer(context_wrapper());
 
@@ -850,8 +850,7 @@
       base::MakeRefCounted<ServiceWorkerVersion>(
           registration.get(),
           GURL("https://another-origin.example.net/test/script_url"),
-          blink::mojom::ScriptType::kClassic, 1L /* version_id */,
-          helper_->context()->AsWeakPtr());
+          1L /* version_id */, helper_->context()->AsWeakPtr());
   remote_endpoints.emplace_back();
   base::WeakPtr<ServiceWorkerProviderHost> host4 =
       CreateProviderHostForServiceWorkerContext(
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index f6ecc10..4203d20 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -322,8 +322,7 @@
     return;
   }
   blink::mojom::ServiceWorkerRegistrationOptions options_to_pass(
-      net::SimplifyUrlForRequest(options.scope), options.type,
-      options.update_via_cache);
+      net::SimplifyUrlForRequest(options.scope), options.update_via_cache);
   context()->RegisterServiceWorker(
       net::SimplifyUrlForRequest(script_url), options_to_pass,
       base::BindOnce(&FinishRegistrationOnIO, std::move(callback)));
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index 581d57c..930165c 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -145,9 +145,8 @@
     options.scope = scope_;
     registration_ =
         new ServiceWorkerRegistration(options, 1L, context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(registration_.get(), script_url_,
-                                        blink::mojom::ScriptType::kClassic, 1L,
-                                        context()->AsWeakPtr());
+    version_ = new ServiceWorkerVersion(
+        registration_.get(), script_url_, 1L, context()->AsWeakPtr());
 
     context()->storage()->LazyInitializeForTest(base::DoNothing());
     base::RunLoop().RunUntilIdle();
diff --git a/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc b/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
index f279d09..3ec996cb 100644
--- a/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
+++ b/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
@@ -86,8 +86,7 @@
     registration_ = new ServiceWorkerRegistration(
         options, 1L, helper_->context()->AsWeakPtr());
     version_ = new ServiceWorkerVersion(
-        registration_.get(), GURL("https://example.com/service_worker.js"),
-        blink::mojom::ScriptType::kClassic, 1L,
+        registration_.get(), GURL("https://example.com/service_worker.js"), 1L,
         helper_->context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 627704f..7bdd0811 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -107,8 +107,7 @@
     options.scope = scope;
     registration_ =
         new ServiceWorkerRegistration(options, 1L, context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(registration_.get(), script_url,
-                                        blink::mojom::ScriptType::kClassic, 1L,
+    version_ = new ServiceWorkerVersion(registration_.get(), script_url, 1L,
                                         context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(
diff --git a/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc b/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
index 0aef37c..db4c5af 100644
--- a/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
+++ b/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
@@ -182,7 +182,6 @@
     version_ = base::MakeRefCounted<ServiceWorkerVersion>(
         registration_.get(),
         GURL("http://www.example.com/test/service_worker.js"),
-        blink::mojom::ScriptType::kClassic,
         context()->storage()->NewVersionId(), context()->AsWeakPtr());
     version_->set_fetch_handler_existence(
         ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index eef369d..dc40958 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -550,8 +550,7 @@
   job_coordinator()->Register(
       script_url1,
       blink::mojom::ServiceWorkerRegistrationOptions(
-          pattern, blink::mojom::ScriptType::kClassic,
-          blink::mojom::ServiceWorkerUpdateViaCache::kNone),
+          pattern, blink::mojom::ServiceWorkerUpdateViaCache::kNone),
       SaveRegistration(blink::ServiceWorkerStatusCode::kOk,
                        &registration1_called, &registration1));
 
@@ -561,8 +560,7 @@
   job_coordinator()->Register(
       script_url2,
       blink::mojom::ServiceWorkerRegistrationOptions(
-          pattern, blink::mojom::ScriptType::kClassic,
-          blink::mojom::ServiceWorkerUpdateViaCache::kAll),
+          pattern, blink::mojom::ServiceWorkerUpdateViaCache::kAll),
       SaveRegistration(blink::ServiceWorkerStatusCode::kOk,
                        &registration2_called, &registration2));
 
@@ -766,8 +764,7 @@
   // Manually create the waiting worker since there is no way to become a
   // waiting worker until Update is implemented.
   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
-      registration.get(), script_url, blink::mojom::ScriptType::kClassic, 1L,
-      helper_->context()->AsWeakPtr());
+      registration.get(), script_url, 1L, helper_->context()->AsWeakPtr());
   base::Optional<blink::ServiceWorkerStatusCode> status;
   version->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
                        CreateReceiverOnCurrentThread(&status));
@@ -1326,8 +1323,8 @@
   // Add a waiting version with a new script.
   GURL new_script("https://www.example.com/new_worker.js");
   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
-      registration.get(), new_script, blink::mojom::ScriptType::kClassic,
-      2L /* dummy version id */, helper_->context()->AsWeakPtr());
+      registration.get(), new_script, 2L /* dummy version id */,
+      helper_->context()->AsWeakPtr());
   registration->SetWaitingVersion(version);
 
   // Run the update job.
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
index f16c0fe..3bacdef 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -447,8 +447,7 @@
                                       helper_->context()->AsWeakPtr());
     version_ = new ServiceWorkerVersion(
         registration_.get(), GURL("https://example.com/service_worker.js"),
-        blink::mojom::ScriptType::kClassic, storage()->NewVersionId(),
-        helper_->context()->AsWeakPtr());
+        storage()->NewVersionId(), helper_->context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(WriteToDiskCacheSync(
         storage(), version_->script_url(), storage()->NewResourceId(),
diff --git a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
index d4b7001..7494702 100644
--- a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
@@ -217,8 +217,8 @@
   // possibly updating if registration has an installed worker.
   void SetUpVersion(const GURL& script_url) {
     version_ = base::MakeRefCounted<ServiceWorkerVersion>(
-        registration_.get(), script_url, blink::mojom::ScriptType::kClassic,
-        context()->storage()->NewVersionId(), context()->AsWeakPtr());
+        registration_.get(), script_url, context()->storage()->NewVersionId(),
+        context()->AsWeakPtr());
     version_->SetStatus(ServiceWorkerVersion::NEW);
 
     if (registration_->waiting_version() || registration_->active_version())
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 08ec897..fd1ca22 100644
--- a/content/browser/service_worker/service_worker_object_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -130,10 +130,10 @@
     registration_ = new ServiceWorkerRegistration(
         options, helper_->context()->storage()->NewRegistrationId(),
         helper_->context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(
-        registration_.get(), script_url, blink::mojom::ScriptType::kClassic,
-        helper_->context()->storage()->NewVersionId(),
-        helper_->context()->AsWeakPtr());
+    version_ =
+        new ServiceWorkerVersion(registration_.get(), script_url,
+                                 helper_->context()->storage()->NewVersionId(),
+                                 helper_->context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(
         ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 77e0b69..926cb6b 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -459,8 +459,7 @@
   // Create an active version and then start the navigation.
   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   version->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -495,8 +494,7 @@
   // Create an installing version and then start the navigation.
   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   registration1_->SetInstallingVersion(version);
 
   // Finish the navigation.
@@ -561,8 +559,7 @@
   scoped_refptr<ServiceWorkerVersion> version =
       base::MakeRefCounted<ServiceWorkerVersion>(
           registration1_.get(), GURL("https://www.example.com/sw.js"),
-          blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-          helper_->context()->AsWeakPtr());
+          1 /* version_id */, helper_->context()->AsWeakPtr());
   registration1_->SetActiveVersion(version);
 
   ServiceWorkerRemoteProviderEndpoint remote_endpoint;
@@ -891,8 +888,7 @@
   // Make an active version.
   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   version1->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -934,8 +930,7 @@
   // Make the waiting worker and have it call SkipWaiting().
   auto version2 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 2 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      2 /* version_id */, helper_->context()->AsWeakPtr());
   version2->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version2->SetStatus(ServiceWorkerVersion::INSTALLED);
@@ -974,8 +969,7 @@
   // Make an active version.
   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   version1->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -983,8 +977,7 @@
 
   auto version2 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration2_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 2 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      2 /* version_id */, helper_->context()->AsWeakPtr());
   version2->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version2->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -1015,8 +1008,7 @@
   // Make an active version.
   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   version1->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -1057,8 +1049,7 @@
   // Make an active version.
   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   version1->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -1088,8 +1079,7 @@
   // Make active versions.
   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration1_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 1 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      1 /* version_id */, helper_->context()->AsWeakPtr());
   version1->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -1097,8 +1087,7 @@
 
   auto version2 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration2_.get(), GURL("https://www.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 2 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      2 /* version_id */, helper_->context()->AsWeakPtr());
   version2->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version2->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -1106,8 +1095,7 @@
 
   auto version3 = base::MakeRefCounted<ServiceWorkerVersion>(
       registration3_.get(), GURL("https://other.example.com/sw.js"),
-      blink::mojom::ScriptType::kClassic, 3 /* version_id */,
-      helper_->context()->AsWeakPtr());
+      3 /* version_id */, helper_->context()->AsWeakPtr());
   version3->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   version3->SetStatus(ServiceWorkerVersion::ACTIVATED);
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc b/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
index 188907a1..89b539a 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
@@ -96,7 +96,6 @@
     registration_ = new ServiceWorkerRegistration(options, kRegistrationId,
                                                   context()->AsWeakPtr());
     version_ = new ServiceWorkerVersion(registration_.get(), main_script_.url,
-                                        blink::mojom::ScriptType::kClassic,
                                         kVersionId, context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
     resources.push_back(main_script_);
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index eaf2361..78c265e 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -41,7 +41,6 @@
       job_type_(REGISTRATION_JOB),
       pattern_(options.scope),
       script_url_(script_url),
-      worker_script_type_(options.type),
       update_via_cache_(options.update_via_cache),
       phase_(INITIAL),
       doom_installing_worker_(false),
@@ -60,12 +59,6 @@
     : context_(context),
       job_type_(UPDATE_JOB),
       pattern_(registration->pattern()),
-      // TODO(crbug.com/824647): Change |worker_script_type_| based on the
-      // current version's type. This constructor is called when ServiceWorker
-      // scripts have already been installed. |worker_script_type_| will be set
-      // in ContinueWithUpdate().
-      // (https://w3c.github.io/ServiceWorker/#soft-update-algorithm)
-      worker_script_type_(blink::mojom::ScriptType::kClassic),
       update_via_cache_(registration->update_via_cache()),
       phase_(INITIAL),
       doom_installing_worker_(false),
@@ -337,8 +330,8 @@
     return;
   }
 
-  blink::mojom::ServiceWorkerRegistrationOptions options(
-      pattern_, worker_script_type_, update_via_cache_);
+  blink::mojom::ServiceWorkerRegistrationOptions options(pattern_,
+                                                         update_via_cache_);
   set_registration(
       new ServiceWorkerRegistration(options, registration_id, context_));
   AddRegistrationToMatchingProviderHosts(registration());
@@ -399,8 +392,8 @@
 
   // "Let worker be a new ServiceWorker object..." and start
   // the worker.
-  set_new_version(new ServiceWorkerVersion(
-      registration(), script_url_, worker_script_type_, version_id, context_));
+  set_new_version(new ServiceWorkerVersion(registration(), script_url_,
+                                           version_id, context_));
   new_version()->set_force_bypass_cache_for_scripts(force_bypass_cache_);
   if (registration()->has_installed_version() && !skip_script_comparison_) {
     new_version()->SetToPauseAfterDownload(
diff --git a/content/browser/service_worker/service_worker_register_job.h b/content/browser/service_worker/service_worker_register_job.h
index 7b4f6e48b..e396a85 100644
--- a/content/browser/service_worker/service_worker_register_job.h
+++ b/content/browser/service_worker/service_worker_register_job.h
@@ -153,9 +153,6 @@
   RegistrationJobType job_type_;
   const GURL pattern_;
   GURL script_url_;
-  // "A job has a worker type ("classic" or "module")."
-  // https://w3c.github.io/ServiceWorker/#dfn-job-worker-type
-  const blink::mojom::ScriptType worker_script_type_;
   const blink::mojom::ServiceWorkerUpdateViaCache update_via_cache_;
   std::vector<RegistrationCallback> callbacks_;
   Phase phase_;
diff --git a/content/browser/service_worker/service_worker_registration_object_host.cc b/content/browser/service_worker/service_worker_registration_object_host.cc
index 60ccb342..c5dae23 100644
--- a/content/browser/service_worker/service_worker_registration_object_host.cc
+++ b/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -97,16 +97,9 @@
 
 blink::mojom::ServiceWorkerRegistrationObjectInfoPtr
 ServiceWorkerRegistrationObjectHost::CreateObjectInfo() {
-  // |info->options->script_type| is never accessed anywhere, so just set it to
-  // kClassic.
-  // TODO(asamidoi, nhiroki): Remove |options| from
-  // ServiceWorkerRegistrationObjectInfo, since |script_type| is a
-  // non-per-registration property.
-  blink::mojom::ScriptType script_type = blink::mojom::ScriptType::kClassic;
-
   auto info = blink::mojom::ServiceWorkerRegistrationObjectInfo::New();
   info->options = blink::mojom::ServiceWorkerRegistrationOptions::New(
-      registration_->pattern(), script_type, registration_->update_via_cache());
+      registration_->pattern(), registration_->update_via_cache());
   info->registration_id = registration_->id();
   bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info));
   info->request = mojo::MakeRequest(&remote_registration_);
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 94749e7..5059ff3 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -221,12 +221,10 @@
   const int64_t version_2_id = 2L;
   scoped_refptr<ServiceWorkerVersion> version_1 =
       base::MakeRefCounted<ServiceWorkerVersion>(
-          registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-          version_1_id, context()->AsWeakPtr());
+          registration.get(), kScript, version_1_id, context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> version_2 =
       base::MakeRefCounted<ServiceWorkerVersion>(
-          registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-          version_2_id, context()->AsWeakPtr());
+          registration.get(), kScript, version_2_id, context()->AsWeakPtr());
 
   RegistrationListener listener;
   registration->AddListener(&listener);
@@ -317,17 +315,17 @@
       base::MakeRefCounted<ServiceWorkerRegistration>(
           options, storage()->NewRegistrationId(), context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> version_1 =
-      base::MakeRefCounted<ServiceWorkerVersion>(
-          registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-          storage()->NewVersionId(), context()->AsWeakPtr());
+      base::MakeRefCounted<ServiceWorkerVersion>(registration.get(), kScript,
+                                                 storage()->NewVersionId(),
+                                                 context()->AsWeakPtr());
   version_1->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   registration->SetActiveVersion(version_1);
   version_1->SetStatus(ServiceWorkerVersion::ACTIVATED);
   scoped_refptr<ServiceWorkerVersion> version_2 =
-      base::MakeRefCounted<ServiceWorkerVersion>(
-          registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-          storage()->NewVersionId(), context()->AsWeakPtr());
+      base::MakeRefCounted<ServiceWorkerVersion>(registration.get(), kScript,
+                                                 storage()->NewVersionId(),
+                                                 context()->AsWeakPtr());
   version_2->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   registration->SetWaitingVersion(version_2);
@@ -366,9 +364,9 @@
 
     // Create an active version.
     scoped_refptr<ServiceWorkerVersion> version_1 =
-        base::MakeRefCounted<ServiceWorkerVersion>(
-            registration_.get(), kScript, blink::mojom::ScriptType::kClassic,
-            storage()->NewVersionId(), context()->AsWeakPtr());
+        base::MakeRefCounted<ServiceWorkerVersion>(registration_.get(), kScript,
+                                                   storage()->NewVersionId(),
+                                                   context()->AsWeakPtr());
     version_1->set_fetch_handler_existence(
         ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
     registration_->SetActiveVersion(version_1);
@@ -404,9 +402,9 @@
 
     // Create a waiting version.
     scoped_refptr<ServiceWorkerVersion> version_2 =
-        base::MakeRefCounted<ServiceWorkerVersion>(
-            registration_.get(), kScript, blink::mojom::ScriptType::kClassic,
-            storage()->NewVersionId(), context()->AsWeakPtr());
+        base::MakeRefCounted<ServiceWorkerVersion>(registration_.get(), kScript,
+                                                   storage()->NewVersionId(),
+                                                   context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records_2;
     records_2.push_back(WriteToDiskCacheSync(
         helper_->context()->storage(), version_2->script_url(),
@@ -765,9 +763,9 @@
       ServiceWorkerRegistration* registration,
       const GURL& script_url) {
     scoped_refptr<ServiceWorkerVersion> version =
-        base::MakeRefCounted<ServiceWorkerVersion>(
-            registration, script_url, blink::mojom::ScriptType::kClassic,
-            storage()->NewVersionId(), context()->AsWeakPtr());
+        base::MakeRefCounted<ServiceWorkerVersion>(registration, script_url,
+                                                   storage()->NewVersionId(),
+                                                   context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(WriteToDiskCacheSync(
         storage(), version->script_url(), storage()->NewResourceId(),
@@ -1120,12 +1118,10 @@
   const int64_t version_2_id = 2L;
   scoped_refptr<ServiceWorkerVersion> version_1 =
       base::MakeRefCounted<ServiceWorkerVersion>(
-          registration, kScriptUrl, blink::mojom::ScriptType::kClassic,
-          version_1_id, context()->AsWeakPtr());
+          registration, kScriptUrl, version_1_id, context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> version_2 =
       base::MakeRefCounted<ServiceWorkerVersion>(
-          registration, kScriptUrl, blink::mojom::ScriptType::kClassic,
-          version_2_id, context()->AsWeakPtr());
+          registration, kScriptUrl, version_2_id, context()->AsWeakPtr());
 
   // Set an active worker.
   registration->SetActiveVersion(version_1);
diff --git a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
index 09a0579..c53cae1 100644
--- a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
+++ b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
@@ -96,8 +96,7 @@
         options, 1L /* registration_id */, context->AsWeakPtr());
     version_ = base::MakeRefCounted<ServiceWorkerVersion>(
         registration_.get(), GURL("https://host/script.js"),
-        blink::mojom::ScriptType::kClassic, context->storage()->NewVersionId(),
-        context->AsWeakPtr());
+        context->storage()->NewVersionId(), context->AsWeakPtr());
 
     provider_host_ = CreateProviderHostForServiceWorkerContext(
         helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index 54871da..92b13a6 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -1537,11 +1537,8 @@
   if (registration)
     return registration;
 
-  blink::mojom::ServiceWorkerRegistrationOptions options(
-      data.scope,
-      // TODO(crbug.com/824647): Add script_type attribute to
-      // ServiceWorkerDatabase::RegistrationData
-      blink::mojom::ScriptType::kClassic, data.update_via_cache);
+  blink::mojom::ServiceWorkerRegistrationOptions options(data.scope,
+                                                         data.update_via_cache);
   registration =
       new ServiceWorkerRegistration(options, data.registration_id, context_);
   registration->set_resources_total_size_bytes(data.resources_total_size_bytes);
@@ -1554,10 +1551,7 @@
       context_->GetLiveVersion(data.version_id);
   if (!version) {
     version = new ServiceWorkerVersion(
-        registration.get(), data.script,
-        // TODO(crbug.com/824647): Replace data.script_type after add worker
-        // type attribute to ServiceWorkerDatabase::RegistrationData
-        blink::mojom::ScriptType::kClassic, data.version_id, context_);
+        registration.get(), data.script, data.version_id, context_);
     version->set_fetch_handler_existence(
         data.has_fetch_handler
             ? ServiceWorkerVersion::FetchHandlerExistence::EXISTS
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index 818540e..fcb289f 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -371,8 +371,8 @@
     auto registration = base::MakeRefCounted<ServiceWorkerRegistration>(
         options, storage()->NewRegistrationId(), context()->AsWeakPtr());
     auto version = base::MakeRefCounted<ServiceWorkerVersion>(
-        registration.get(), script, blink::mojom::ScriptType::kClassic,
-        storage()->NewVersionId(), context()->AsWeakPtr());
+        registration.get(), script, storage()->NewVersionId(),
+        context()->AsWeakPtr());
     std::vector<ResourceRecord> records = {
         ResourceRecord(storage()->NewResourceId(), script, 100)};
     version->script_cache_map()->SetResources(records);
@@ -649,8 +649,7 @@
       new ServiceWorkerRegistration(options, kRegistrationId,
                                     context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
-      live_registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-      kVersionId, context()->AsWeakPtr());
+      live_registration.get(), kScript, kVersionId, context()->AsWeakPtr());
   EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorAbort,
             StoreRegistration(live_registration, live_version));
 
@@ -738,8 +737,7 @@
       new ServiceWorkerRegistration(options, kRegistrationId,
                                     context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
-      live_registration.get(), kResource1, blink::mojom::ScriptType::kClassic,
-      kVersionId, context()->AsWeakPtr());
+      live_registration.get(), kResource1, kVersionId, context()->AsWeakPtr());
   live_version->set_fetch_handler_existence(
       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
   live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
@@ -909,8 +907,7 @@
       new ServiceWorkerRegistration(options, kRegistrationId,
                                     context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
-      live_registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-      kVersionId, context()->AsWeakPtr());
+      live_registration.get(), kScript, kVersionId, context()->AsWeakPtr());
   live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
   live_registration->SetWaitingVersion(live_version);
 
@@ -1663,8 +1660,8 @@
 
   // Make an updated registration.
   scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
-      registration_.get(), script_, blink::mojom::ScriptType::kClassic,
-      storage()->NewVersionId(), context()->AsWeakPtr());
+      registration_.get(), script_, storage()->NewVersionId(),
+      context()->AsWeakPtr());
   live_version->SetStatus(ServiceWorkerVersion::NEW);
   registration_->SetWaitingVersion(live_version);
   std::vector<ResourceRecord> records;
@@ -1865,8 +1862,7 @@
       new ServiceWorkerRegistration(options, kRegistrationId,
                                     context()->AsWeakPtr());
   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
-      registration.get(), kScript, blink::mojom::ScriptType::kClassic,
-      kVersionId, context()->AsWeakPtr());
+      registration.get(), kScript, kVersionId, context()->AsWeakPtr());
 
   net::HttpResponseInfo http_info;
   http_info.ssl_info.cert =
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 0685759f..fef3544 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -233,8 +233,7 @@
     registration_ = new ServiceWorkerRegistration(
         options, 1L, helper_->context()->AsWeakPtr());
     version_ = new ServiceWorkerVersion(
-        registration_.get(), GURL("https://example.com/service_worker.js"),
-        blink::mojom::ScriptType::kClassic, 1L,
+        registration_.get(), GURL("https://example.com/service_worker.js"), 1L,
         helper_->context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(WriteToDiskCacheWithCustomResponseInfoSync(
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 25614fa..5d82134 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -226,7 +226,6 @@
 ServiceWorkerVersion::ServiceWorkerVersion(
     ServiceWorkerRegistration* registration,
     const GURL& script_url,
-    blink::mojom::ScriptType script_type,
     int64_t version_id,
     base::WeakPtr<ServiceWorkerContextCore> context)
     : version_id_(version_id),
@@ -234,7 +233,6 @@
       script_url_(script_url),
       script_origin_(url::Origin::Create(script_url_)),
       scope_(registration->pattern()),
-      script_type_(script_type),
       fetch_handler_existence_(FetchHandlerExistence::UNKNOWN),
       site_for_uma_(ServiceWorkerMetrics::SiteFromURL(scope_)),
       binding_(this),
@@ -1524,7 +1522,6 @@
   params->service_worker_version_id = version_id_;
   params->scope = scope_;
   params->script_url = script_url_;
-  params->script_type = script_type_;
   params->is_installed = IsInstalled(status_);
   params->pause_after_download = pause_after_download();
 
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 424ca62..166f9093 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -183,7 +183,6 @@
 
   ServiceWorkerVersion(ServiceWorkerRegistration* registration,
                        const GURL& script_url,
-                       blink::mojom::ScriptType script_type,
                        int64_t version_id,
                        base::WeakPtr<ServiceWorkerContextCore> context);
 
@@ -192,7 +191,6 @@
   const GURL& script_url() const { return script_url_; }
   const url::Origin& script_origin() const { return script_origin_; }
   const GURL& scope() const { return scope_; }
-  blink::mojom::ScriptType script_type() const { return script_type_; }
   EmbeddedWorkerStatus running_status() const {
     return embedded_worker_->status();
   }
@@ -776,10 +774,6 @@
   const GURL script_url_;
   const url::Origin script_origin_;
   const GURL scope_;
-  // A service worker has an associated type which is either
-  // "classic" or "module". Unless stated otherwise, it is "classic".
-  // https://w3c.github.io/ServiceWorker/#dfn-type
-  const blink::mojom::ScriptType script_type_;
   FetchHandlerExistence fetch_handler_existence_;
   // The source of truth for navigation preload state is the
   // ServiceWorkerRegistration. |navigation_preload_state_| is essentially a
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index e34825c1..fddd9d4 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -155,7 +155,6 @@
     version_ = new ServiceWorkerVersion(
         registration_.get(),
         GURL("https://www.example.com/test/service_worker.js"),
-        blink::mojom::ScriptType::kClassic,
         helper_->context()->storage()->NewVersionId(),
         helper_->context()->AsWeakPtr());
     EXPECT_EQ(url::Origin::Create(pattern_), version_->script_origin());
@@ -1313,7 +1312,6 @@
   auto version = base::MakeRefCounted<ServiceWorkerVersion>(
       registration_.get(),
       GURL("bad-origin://www.example.com/test/service_worker.js"),
-      blink::mojom::ScriptType::kClassic,
       helper_->context()->storage()->NewVersionId(),
       helper_->context()->AsWeakPtr());
   base::Optional<blink::ServiceWorkerStatusCode> status;
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.cc b/content/browser/service_worker/service_worker_write_to_cache_job.cc
index 42494f9..f2c05dc 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -72,26 +72,9 @@
       version_(version),
       weak_factory_(this) {
   DCHECK(version_);
-
-#if DCHECK_IS_ON()
-  switch (version_->script_type()) {
-    case blink::mojom::ScriptType::kClassic:
-      // For classic scripts, the main service worker script should have the
-      // "service worker" resource type and imported scripts should have the
-      // "script" resource type.
-      DCHECK(resource_type_ == RESOURCE_TYPE_SCRIPT ||
-             (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER &&
-              version_->script_url() == url_));
-      break;
-    case blink::mojom::ScriptType::kModule:
-      // For module scripts, both the main service worker script and
-      // static-imported scripts should have the "service worker" resource type
-      // because static import inherits the resource type of the top-level
-      // module script.
-      DCHECK_EQ(RESOURCE_TYPE_SERVICE_WORKER, resource_type_);
-      break;
-  }
-#endif  // DCHECK_IS_ON()
+  DCHECK(resource_type_ == RESOURCE_TYPE_SCRIPT ||
+         (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER &&
+          version_->script_url() == url_));
   InitNetRequest(extra_load_flags);
 }
 
@@ -249,9 +232,7 @@
   if (extra_load_flags)
     net_request_->SetLoadFlags(net_request_->load_flags() | extra_load_flags);
 
-  // Add the 'Service-Worker' header for the main script request.
-  // https://w3c.github.io/ServiceWorker/#service-worker-script-request
-  if (IsMainScript()) {
+  if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER) {
     // This will get copied into net_request_ when URLRequest::StartJob calls
     // ServiceWorkerWriteToCacheJob::SetExtraRequestHeaders.
     request()->SetExtraRequestHeaderByName("Service-Worker", "script", true);
@@ -350,7 +331,7 @@
     return;
   }
 
-  if (IsMainScript()) {
+  if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER) {
     std::string mime_type;
     request->GetMimeType(&mime_type);
     if (!blink::IsSupportedJavascriptMimeType(mime_type)) {
@@ -516,9 +497,4 @@
          version_->pause_after_download();
 }
 
-bool ServiceWorkerWriteToCacheJob::IsMainScript() const {
-  return url_ == version_->script_url() &&
-         resource_type_ == RESOURCE_TYPE_SERVICE_WORKER;
-}
-
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.h b/content/browser/service_worker/service_worker_write_to_cache_job.h
index 5c18785..46572db7 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.h
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.h
@@ -132,10 +132,6 @@
   // do the byte-for-byte check.
   bool ShouldByteForByteCheck() const;
 
-  // Returns true if this writer is writing the main script for the service
-  // worker.
-  bool IsMainScript() const;
-
   const ResourceType resource_type_;  // Differentiate main script and imports
   scoped_refptr<net::IOBuffer> io_buffer_;
   int io_buffer_bytes_;
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index ea969ba5..d4c73d7 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -338,9 +338,9 @@
     options.scope = scope_;
     registration_ =
         new ServiceWorkerRegistration(options, 1L, context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(
-        registration_.get(), script_url_, blink::mojom::ScriptType::kClassic,
-        NextVersionId(), context()->AsWeakPtr());
+    version_ =
+        new ServiceWorkerVersion(registration_.get(), script_url_,
+                                 NextVersionId(), context()->AsWeakPtr());
     base::WeakPtr<ServiceWorkerProviderHost> host =
         CreateHostForVersion(helper_->mock_render_process_id(), version_);
     ASSERT_TRUE(host);
@@ -392,9 +392,9 @@
   // to the script |response|. Returns the new version.
   scoped_refptr<ServiceWorkerVersion> UpdateScript(
       const std::string& response) {
-    scoped_refptr<ServiceWorkerVersion> new_version = new ServiceWorkerVersion(
-        registration_.get(), script_url_, blink::mojom::ScriptType::kClassic,
-        NextVersionId(), context()->AsWeakPtr());
+    scoped_refptr<ServiceWorkerVersion> new_version =
+        new ServiceWorkerVersion(registration_.get(), script_url_,
+                                 NextVersionId(), context()->AsWeakPtr());
     new_version->SetToPauseAfterDownload(base::DoNothing());
     base::WeakPtr<ServiceWorkerProviderHost> host =
         CreateHostForVersion(helper_->mock_render_process_id(), new_version);
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index da46f2f..d64bf38 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -1506,7 +1506,7 @@
   RunTest(TouchActionBubbling);
 }
 
-#if defined(OS_ANDROID) || defined(USE_AURA)
+#if defined(OS_ANDROID)
 namespace {
 // This function is used in TouchActionAckTimeout and
 // SubframeGestureEventRouting, which is defined either under Android or Aura.
@@ -1516,17 +1516,15 @@
   runner->Quit();
 }
 
-#if defined(OS_ANDROID)
 void GiveItSomeTime(int t) {
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(t));
   run_loop.Run();
 }
-#endif  // defined(OS_ANDROID)
 
 }  // namespace
-#endif  // defined(OS_ANDROID) || defined(USE_AURA)
+#endif  // defined(OS_ANDROID)
 
 // Regression test for https://crbug.com/851644. The test passes as long as it
 // doesn't crash.
@@ -2150,32 +2148,31 @@
 // This test tests that browser process hittesting ignores frames with
 // pointer-events: none.
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       SurfaceHitTestPointerEventsNone) {
-  // TODO(sunxd): Fix pointer-events none for surface layer viz hit testing. See
-  // https://crbug.com/841358.
-  if (features::IsVizHitTestingSurfaceLayerEnabled()) {
-    LOG(INFO) << "Skipping test due to https://crbug.com/841358";
-    return;
-  }
+                       SurfaceHitTestPointerEventsNoneChanged) {
+  // In /2 hit testing, OOPIFs with pointer-events: none are ignored and no hit
+  // test data is submitted. To make sure we wait enough time until child frame
+  // fully loaded, we add a 1x1 pixel OOPIF for the test to track the process of
+  // /2 hit testing.
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_frame_pointer-events_none.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
   FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
+  ASSERT_EQ(2U, root->child_count());
 
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
+  FrameTreeNode* child_node1 = root->child_at(0);
+  FrameTreeNode* child_node2 = root->child_at(1);
+  GURL site_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node2->current_url());
   EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
+            child_node2->current_frame_host()->GetSiteInstance());
 
   // Create listeners for mouse events.
   RenderWidgetHostMouseEventMonitor main_frame_monitor(
       root->current_frame_host()->GetRenderWidgetHost());
   RenderWidgetHostMouseEventMonitor child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
+      child_node1->current_frame_host()->GetRenderWidgetHost());
 
   RenderWidgetHostInputEventRouter* router =
       web_contents()->GetInputEventRouter();
@@ -2183,9 +2180,9 @@
   RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
       root->current_frame_host()->GetRenderWidgetHost()->GetView());
 
-  WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+  WaitForHitTestDataOrChildSurfaceReady(child_node2->current_frame_host());
 
-  // Target input event to child frame.
+  // Target input event to child1 frame.
   blink::WebMouseEvent child_event(
       blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers,
       blink::WebInputEvent::GetStaticTimeStampForTests());
@@ -2203,6 +2200,43 @@
   EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().x, 2);
   EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().y, 2);
   EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+
+  // Surface hit test can only learn about pointer-events changes when
+  // submitting compositing frame, so we disable the second half of the test for
+  // surface hit test.
+  if (!features::IsVizHitTestingEnabled())
+    return;
+
+  // Remove pointer-events: none property from iframe, also remove child2 to
+  // properly notify the observer the update.
+  // Wait for the confirmation of the deletion so that surface hit test is aware
+  // of the change of pointer-events property. When viz hit testing is enabled,
+  // we do not need to wait.
+  EXPECT_TRUE(ExecuteScript(web_contents(),
+                            "document.getElementsByTagName('iframe')[0].style."
+                            "pointerEvents = 'auto';\n"));
+
+  ASSERT_EQ(2U, root->child_count());
+
+  {
+    MainThreadFrameObserver observer(
+        root->current_frame_host()->GetRenderWidgetHost());
+    observer.Wait();
+  }
+
+  WaitForHitTestDataOrChildSurfaceReady(child_node1->current_frame_host());
+  WaitForHitTestDataOrChildSurfaceReady(child_node2->current_frame_host());
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  InputEventAckWaiter child_waiter(
+      child_node1->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kMouseDown);
+  router->RouteMouseEvent(root_view, &child_event, ui::LatencyInfo());
+  child_waiter.Wait();
+
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_NEAR(23, child_frame_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(23, child_frame_monitor.event().PositionInWidget().y, 2);
 }
 
 // Verify that an event is properly retargeted to the main frame when an
@@ -3419,9 +3453,8 @@
             render_widget_host->input_router()->AllowedTouchAction());
 }
 
-// https://crbug.com/592320
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       DISABLED_SubframeGestureEventRouting) {
+                       SubframeGestureEventRouting) {
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_nested_frames.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -3459,15 +3492,17 @@
 
   RenderWidgetHostImpl* render_widget_host =
       root->current_frame_host()->GetRenderWidgetHost();
-  // TODO(wjmaclean): Convert the call to base::Bind() to a lambda someday.
-  render_widget_host->QueueSyntheticGesture(
-      std::move(gesture), base::BindOnce(OnSyntheticGestureCompleted, runner));
+  InputEventAckWaiter ack_waiter(child_frame_host->GetRenderWidgetHost(),
+                                 blink::WebInputEvent::kGestureTap);
 
-  // We need to run the message loop while we wait for the synthetic gesture
-  // to be processed; the callback registered above will get us out of the
-  // message loop when that happens.
-  runner->Run();
-  runner = nullptr;
+  render_widget_host->QueueSyntheticGesture(
+      std::move(gesture), base::BindOnce([](SyntheticGesture::Result result) {
+        EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
+      }));
+
+  // We must wait for the kGestureTap ack to come back before querying the click
+  // handler in the subframe.
+  ack_waiter.Wait();
 
   // Verify click handler in subframe was invoked
   {
@@ -4853,7 +4888,8 @@
  protected:
   // Load the page |host_name| and retrieve the hit test data from HitTestQuery.
   std::vector<viz::AggregatedHitTestRegion> SetupAndGetHitTestData(
-      const std::string& host_name) {
+      const std::string& host_name,
+      unsigned skipped_child = -1) {
     GURL main_url(embedded_test_server()->GetURL(host_name));
     EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
@@ -4866,8 +4902,12 @@
             root->current_frame_host()->GetRenderWidgetHost()->GetView());
 
     for (unsigned i = 0; i < root->child_count(); i++) {
-      WaitForHitTestDataOrChildSurfaceReady(
-          root->child_at(i)->current_frame_host());
+      // Child with pointer-events: none property will never submit a hit test
+      // region in /2 hit testing.
+      if (i != skipped_child) {
+        WaitForHitTestDataOrChildSurfaceReady(
+            root->child_at(i)->current_frame_host());
+      }
     }
 
     HitTestRegionObserver observer(rwhv_root->GetRootFrameSinkId());
@@ -5175,6 +5215,74 @@
   EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
 }
 
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+                       PointerEventsNoneOOPIF) {
+  if (!features::IsVizHitTestingSurfaceLayerEnabled())
+    return;
+  auto hit_test_data = SetupAndGetHitTestData(
+      "/frame_tree/page_with_positioned_frame_pointer-events_none.html", 0);
+  float device_scale_factor = current_device_scale_factor();
+  gfx::Transform expected_transform;
+  gfx::Rect expected_region = gfx::ScaleToEnclosingRect(
+      gfx::Rect(1, 1), device_scale_factor, device_scale_factor);
+  expected_transform.Translate(-2 * device_scale_factor,
+                               -2 * device_scale_factor);
+
+  // We should not submit hit test region for iframes with pointer-events: none
+  // in /2 hit testing.
+  DCHECK(hit_test_data.size() == 3);
+  EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString());
+  EXPECT_TRUE(
+      expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+  EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+
+  // Check that an update on the css property can trigger an update in submitted
+  // hit test data.
+  EXPECT_TRUE(ExecuteScript(web_contents(),
+                            "document.getElementsByTagName('iframe')[0].style."
+                            "pointerEvents = 'auto';\n"));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  ASSERT_EQ(2U, root->child_count());
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  {
+    MainThreadFrameObserver observer(
+        root->current_frame_host()->GetRenderWidgetHost());
+    observer.Wait();
+  }
+
+  WaitForHitTestDataOrChildSurfaceReady(
+      root->child_at(0)->current_frame_host());
+  WaitForHitTestDataOrChildSurfaceReady(
+      root->child_at(1)->current_frame_host());
+
+  HitTestRegionObserver observer(rwhv_root->GetRootFrameSinkId());
+  observer.WaitForHitTestData();
+  hit_test_data = observer.GetHitTestData();
+
+  gfx::Rect expected_region2 = gfx::ScaleToEnclosingRect(
+      gfx::Rect(100, 100), device_scale_factor, device_scale_factor);
+  gfx::Transform expected_transform2;
+  expected_transform2.Translate(-52 * device_scale_factor,
+                                -52 * device_scale_factor);
+
+  DCHECK(hit_test_data.size() == 4);
+  EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString());
+  EXPECT_TRUE(
+      expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+  EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+
+  EXPECT_EQ(expected_region2.ToString(), hit_test_data[3].rect.ToString());
+  EXPECT_TRUE(
+      expected_transform2.ApproximatelyEqual(hit_test_data[3].transform()));
+  EXPECT_EQ(kFastHitTestFlags, hit_test_data[3].flags);
+}
+
 static const int kHitTestOption[] = {0, 1, 2};
 static const float kOneScale[] = {1.f};
 
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc
index 864037ef..8ebdc7f 100644
--- a/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -669,7 +669,8 @@
     case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_NAVIGATION: {
       auto config = TraceConfig(
           "benchmark,toplevel,ipc,base,browser,navigation,omnibox,"
-          "safe_browsing,task_scheduler,task_scheduler_diagnostics"
+          "safe_browsing,task_scheduler,"
+          "disabled-by-default-task_scheduler_diagnostics,"
           "disabled-by-default-system_stats,disabled-by-default-cpu_profiler",
           record_mode);
       // Filter only browser process events.
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 31b53e9..b0d3fea 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -523,6 +523,40 @@
       ConvertJavaStringToUTF16(env, script), js_callback);
 }
 
+void WebContentsAndroid::EvaluateJavaScriptForTests(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jstring>& script,
+    const JavaParamRef<jobject>& callback) {
+  RenderViewHost* rvh = web_contents_->GetRenderViewHost();
+  DCHECK(rvh);
+
+  if (!rvh->IsRenderViewLive()) {
+    if (!static_cast<WebContentsImpl*>(web_contents_)->
+        CreateRenderViewForInitialEmptyDocument()) {
+      LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScriptForTests";
+      return;
+    }
+  }
+
+  if (!callback) {
+    // No callback requested.
+    web_contents_->GetMainFrame()->ExecuteJavaScriptForTests(
+        ConvertJavaStringToUTF16(env, script));
+    return;
+  }
+
+  // Secure the Java callback in a scoped object and give ownership of it to the
+  // base::Callback.
+  ScopedJavaGlobalRef<jobject> j_callback;
+  j_callback.Reset(env, callback);
+  RenderFrameHost::JavaScriptResultCallback js_callback =
+      base::Bind(&JavaScriptResultCallback, j_callback);
+
+  web_contents_->GetMainFrame()->ExecuteJavaScriptForTests(
+      ConvertJavaStringToUTF16(env, script), js_callback);
+}
+
 void WebContentsAndroid::AddMessageToDevToolsConsole(
     JNIEnv* env,
     const JavaParamRef<jobject>& jobj,
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index 6af2cbf6..6e55efc6 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -126,6 +126,12 @@
                           const base::android::JavaParamRef<jobject>& obj,
                           const base::android::JavaParamRef<jstring>& script,
                           const base::android::JavaParamRef<jobject>& callback);
+  void EvaluateJavaScriptForTests(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jstring>& script,
+      const base::android::JavaParamRef<jobject>& callback);
+
   void AddMessageToDevToolsConsole(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jobj,
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 51b9b7b4..889e2c2 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1049,6 +1049,10 @@
                            BeforeUnloadDialogRequiresGesture);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest,
                            CancelBeforeUnloadResetsURL);
+  FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest,
+                           BeforeUnloadDialogSuppressedForDiscard);
+  FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest,
+                           PendingDialogMakesDiscardUnloadReturnFalse);
   FRIEND_TEST_ALL_PREFIXES(DevToolsProtocolTest, JavaScriptDialogNotifications);
   FRIEND_TEST_ALL_PREFIXES(DevToolsProtocolTest, JavaScriptDialogInterop);
   FRIEND_TEST_ALL_PREFIXES(DevToolsProtocolTest, BeforeUnloadDialog);
diff --git a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
new file mode 100644
index 0000000..c3957b2a
--- /dev/null
+++ b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
@@ -0,0 +1,160 @@
+// 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 "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/service_manager_connection.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "media/base/media_switches.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
+
+namespace content {
+
+namespace {
+
+static const char kVideoCaptureHtmlFile[] = "/media/video_capture_test.html";
+static const std::string kEnumerateVideoCaptureDevicesAndVerify =
+    "enumerateVideoCaptureDevicesAndVerifyCount";
+
+}  // anonymous namespace
+
+// Integration test that obtains a connection to the video capture service via
+// the Browser process' service manager. It then registers and unregisters
+// virtual devices at the service and checks in JavaScript that the list of
+// enumerated devices changes correspondingly.
+class WebRtcVideoCaptureServiceEnumerationBrowserTest
+    : public ContentBrowserTest {
+ public:
+  WebRtcVideoCaptureServiceEnumerationBrowserTest() {
+    scoped_feature_list_.InitAndEnableFeature(features::kMojoVideoCapture);
+  }
+
+  ~WebRtcVideoCaptureServiceEnumerationBrowserTest() override {}
+
+  void ConnectToService() {
+    connector_->BindInterface(video_capture::mojom::kServiceName, &provider_);
+    provider_->ConnectToDeviceFactory(mojo::MakeRequest(&factory_));
+  }
+
+  void AddVirtualDevice(const std::string& device_id) {
+    media::VideoCaptureDeviceInfo info;
+    info.descriptor.device_id = device_id;
+    info.descriptor.set_display_name(device_id);
+    info.descriptor.capture_api = media::VideoCaptureApi::VIRTUAL_DEVICE;
+
+    video_capture::mojom::TextureVirtualDevicePtr virtual_device;
+    factory_->AddTextureVirtualDevice(info, mojo::MakeRequest(&virtual_device));
+    virtual_devices_by_id_.insert(
+        std::make_pair(device_id, std::move(virtual_device)));
+  }
+
+  void RemoveVirtualDevice(const std::string& device_id) {
+    virtual_devices_by_id_.erase(device_id);
+  }
+
+  void DisconnectFromService() {
+    factory_ = nullptr;
+    provider_ = nullptr;
+  }
+
+  void EnumerateDevicesInRendererAndVerifyDeviceCount(
+      int expected_device_count) {
+    NavigateToURL(shell(),
+                  GURL(embedded_test_server()->GetURL(kVideoCaptureHtmlFile)));
+
+    const std::string javascript_to_execute = base::StringPrintf(
+        (kEnumerateVideoCaptureDevicesAndVerify + "(%d)").c_str(),
+        expected_device_count);
+    std::string result;
+    ASSERT_TRUE(
+        ExecuteScriptAndExtractString(shell(), javascript_to_execute, &result));
+    ASSERT_EQ("OK", result);
+  }
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Note: We are not planning to actually use any fake device, but we want
+    // to avoid enumerating or otherwise calling into real capture devices.
+    command_line->AppendSwitchASCII(switches::kUseFakeDeviceForMediaStream,
+                                    "device-count=0");
+    command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
+  }
+
+  void Initialize() {
+    DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+    embedded_test_server()->StartAcceptingConnections();
+
+    auto* connection = content::ServiceManagerConnection::GetForProcess();
+    ASSERT_TRUE(connection);
+    auto* connector = connection->GetConnector();
+    ASSERT_TRUE(connector);
+    connector_ = connector->Clone();
+  }
+
+  std::unique_ptr<service_manager::Connector> connector_;
+  std::map<std::string, video_capture::mojom::TextureVirtualDevicePtr>
+      virtual_devices_by_id_;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  video_capture::mojom::DeviceFactoryProviderPtr provider_;
+  video_capture::mojom::DeviceFactoryPtr factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebRtcVideoCaptureServiceEnumerationBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureServiceEnumerationBrowserTest,
+                       SingleAddedVirtualDeviceGetsEnumerated) {
+  Initialize();
+  ConnectToService();
+
+  // Exercise
+  // TODO(chfremer): It is probably not guaranteed that the Mojo IPC call to
+  // AddVirtualDevice arrives at the service before the request to enumerate
+  // devices triggered by JavaScript. To guarantee this, we would have to add
+  // a done-callback to AddVirtualDevice() and wait for that to arrive before
+  // doing the enumeration.
+  AddVirtualDevice("test");
+  EnumerateDevicesInRendererAndVerifyDeviceCount(1);
+
+  // Tear down
+  RemoveVirtualDevice("test");
+  DisconnectFromService();
+}
+
+IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureServiceEnumerationBrowserTest,
+                       RemoveVirtualDeviceAfterItHasBeenEnumerated) {
+  // TODO(chfremer): Remove this when https://crbug.com/876892 is resolved.
+  if (base::FeatureList::IsEnabled(features::kMediaDevicesSystemMonitorCache)) {
+    LOG(WARNING) << "Skipping test, because feature not yet supported when "
+                    "device monitoring is enabled.";
+    return;
+  }
+  Initialize();
+  ConnectToService();
+
+  AddVirtualDevice("test_1");
+  AddVirtualDevice("test_2");
+  EnumerateDevicesInRendererAndVerifyDeviceCount(2);
+  RemoveVirtualDevice("test_1");
+  EnumerateDevicesInRendererAndVerifyDeviceCount(1);
+  RemoveVirtualDevice("test_2");
+  EnumerateDevicesInRendererAndVerifyDeviceCount(0);
+
+  // Tear down
+  DisconnectFromService();
+}
+
+}  // namespace content
diff --git a/content/common/service_worker/embedded_worker.mojom b/content/common/service_worker/embedded_worker.mojom
index 85dd7db..adb7fbb 100644
--- a/content/common/service_worker/embedded_worker.mojom
+++ b/content/common/service_worker/embedded_worker.mojom
@@ -17,7 +17,6 @@
 import "services/service_manager/public/mojom/interface_provider.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom";
-import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
 import "third_party/blink/public/platform/web_feature.mojom";
 import "third_party/blink/public/web/console_message.mojom";
 import "third_party/blink/public/web/devtools_agent.mojom";
@@ -39,9 +38,6 @@
   // This service worker's script url:
   // https://w3c.github.io/ServiceWorker/#dom-serviceworker-scripturl
   url.mojom.Url script_url;
-  // This service worker's script type:
-  // https://w3c.github.io/ServiceWorker/#dfn-type
-  blink.mojom.ScriptType script_type;
   // The id to talk with the DevTools agent for the worker.
   int32 worker_devtools_agent_route_id;
   // Unique token identifying this worker for DevTools.
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 5b649ab..25856a5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -529,6 +529,13 @@
     }
 
     @Override
+    @VisibleForTesting
+    public void evaluateJavaScriptForTests(String script, JavaScriptCallback callback) {
+        if (script == null) return;
+        nativeEvaluateJavaScriptForTests(mNativeWebContentsAndroid, script, callback);
+    }
+
+    @Override
     public void addMessageToDevToolsConsole(int level, String message) {
         nativeAddMessageToDevToolsConsole(mNativeWebContentsAndroid, level, message);
     }
@@ -918,6 +925,8 @@
     private native void nativeResumeLoadingCreatedWebContents(long nativeWebContentsAndroid);
     private native void nativeEvaluateJavaScript(long nativeWebContentsAndroid,
             String script, JavaScriptCallback callback);
+    private native void nativeEvaluateJavaScriptForTests(long nativeWebContentsAndroid,
+            String script, JavaScriptCallback callback);
     private native void nativeAddMessageToDevToolsConsole(
             long nativeWebContentsAndroid, int level, String message);
     private native void nativePostMessageToFrame(long nativeWebContentsAndroid, String frameName,
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index b069f3b..6f4e5e1 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -11,6 +11,7 @@
 import android.support.annotation.Nullable;
 
 import org.chromium.base.Callback;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.ui.OverscrollRefreshHandler;
 import org.chromium.ui.base.EventForwarder;
 import org.chromium.ui.base.ViewAndroidDelegate;
@@ -277,6 +278,19 @@
     void evaluateJavaScript(String script, JavaScriptCallback callback);
 
     /**
+     * Injects the passed Javascript code in the current page and evaluates it.
+     * If a result is required, pass in a callback.
+     *
+     * @param script The Javascript to execute.
+     * @param callback The callback to be fired off when a result is ready. The script's
+     *                 result will be json encoded and passed as the parameter, and the call
+     *                 will be made on the main thread.
+     *                 If no result is required, pass null.
+     */
+    @VisibleForTesting
+    void evaluateJavaScriptForTests(String script, JavaScriptCallback callback);
+
+    /**
      * Adds a log message to dev tools console. |level| must be a value of
      * org.chromium.content_public.common.ConsoleMessageLevel.
      */
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
index b2559378..2ad2cb6d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
@@ -23,7 +23,6 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
-import org.chromium.content_public.browser.test.util.WebContentsUtils;
 
 import java.lang.ref.WeakReference;
 import java.util.concurrent.CountDownLatch;
@@ -289,7 +288,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                WebContentsUtils.evaluateJavaScript(webContents, script, resultCallback);
+                webContents.evaluateJavaScriptForTests(script, resultCallback);
             }
         });
         resultCallback.waitForResult();
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java b/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
index a4a3ec2b..e357b1c 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
@@ -16,7 +16,6 @@
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.DOMUtils;
-import org.chromium.content_public.browser.test.util.WebContentsUtils;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
@@ -51,7 +50,7 @@
         for (int i = 0; i < 30; ++i) {
             for (int j = 0; j < 10; ++j) {
                 // Start evaluation of a JavaScript script -- we don't need a result.
-                WebContentsUtils.evaluateJavaScript(webContents, "foobar();", null);
+                webContents.evaluateJavaScriptForTests("foobar();", null);
             }
             // DOMUtils does need to evaluate a JavaScript and get its result to get DOM bounds.
             Assert.assertNotNull(
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index af80f6c..1e121c9 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -469,7 +469,7 @@
 // Enable WebAssembly structured cloning.
 // http://webassembly.org/
 const base::Feature kWebAssembly{"WebAssembly",
-                                 base::FEATURE_DISABLED_BY_DEFAULT};
+                                 base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enable WebAssembly streamed compilation.
 const base::Feature kWebAssemblyStreaming{"WebAssemblyStreaming",
diff --git a/content/public/test/android/BUILD.gn b/content/public/test/android/BUILD.gn
index f46225c..2bc36ac 100644
--- a/content/public/test/android/BUILD.gn
+++ b/content/public/test/android/BUILD.gn
@@ -85,7 +85,6 @@
     "render_frame_host_test_ext.cc",
     "render_frame_host_test_ext.h",
     "web_contents_utils.cc",
-    "web_contents_utils.h",
   ]
   deps = [
     ":content_test_jni",
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
index c24daed..0b4f5b5 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
@@ -168,6 +168,9 @@
     public void evaluateJavaScript(String script, JavaScriptCallback callback) {}
 
     @Override
+    public void evaluateJavaScriptForTests(String script, JavaScriptCallback callback) {}
+
+    @Override
     public void addMessageToDevToolsConsole(int level, String message) {}
 
     @Override
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java
index 0aa8e6f..ae8e6437 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java
@@ -63,7 +63,7 @@
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                WebContentsUtils.evaluateJavaScript(webContents, code, null);
+                webContents.evaluateJavaScriptForTests(code, null);
             }
         });
     }
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestCallbackHelperContainer.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestCallbackHelperContainer.java
index 6b0dd0b..03f94af 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestCallbackHelperContainer.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestCallbackHelperContainer.java
@@ -123,7 +123,7 @@
                 }
             };
             mJsonResult = null;
-            WebContentsUtils.evaluateJavaScript(webContents, code, callback);
+            webContents.evaluateJavaScriptForTests(code, callback);
         }
 
         /**
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/WebContentsUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/WebContentsUtils.java
index c5e446e..9f39714 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/WebContentsUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/WebContentsUtils.java
@@ -5,13 +5,11 @@
 package org.chromium.content_public.browser.test.util;
 
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.browser.input.SelectPopup;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.ImeAdapter;
-import org.chromium.content_public.browser.JavaScriptCallback;
 import org.chromium.content_public.browser.RenderFrameHost;
 import org.chromium.content_public.browser.ViewEventSink;
 import org.chromium.content_public.browser.WebContents;
@@ -99,34 +97,7 @@
         }
     }
 
-    /**
-     * Injects the passed Javascript code in the current page and evaluates it. This is different
-     * from {@link WebContents#evaluateJavaScript()} in that it allows for executing script
-     * in non-webui frames.
-     * <p>
-     * If a result is required, pass in a callback.
-     *
-     * @param script The Javascript to execute.
-     * @param callback The callback to be fired off when a result is ready. The script's
-     *                 result will be json encoded and passed as the parameter, and the call
-     *                 will be made on the main thread.
-     *                 If no result is required, pass null.
-     */
-    public static void evaluateJavaScript(
-            WebContents webContents, String script, JavaScriptCallback callback) {
-        if (script == null) return;
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> nativeEvaluateJavaScript(webContents, script, callback));
-    }
-
-    @CalledByNative
-    private static void onEvaluateJavaScriptResult(String jsonResult, JavaScriptCallback callback) {
-        callback.handleJavaScriptResult(jsonResult);
-    }
-
     private static native void nativeReportAllFrameSubmissions(
             WebContents webContents, boolean enabled);
     private static native RenderFrameHost nativeGetFocusedFrame(WebContents webContents);
-    private static native void nativeEvaluateJavaScript(
-            WebContents webContents, String script, JavaScriptCallback callback);
 }
diff --git a/content/public/test/android/web_contents_utils.cc b/content/public/test/android/web_contents_utils.cc
index 3e86416..0dfeb53e 100644
--- a/content/public/test/android/web_contents_utils.cc
+++ b/content/public/test/android/web_contents_utils.cc
@@ -2,38 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/test/android/web_contents_utils.h"
-
-#include "base/json/json_writer.h"
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/render_frame_metadata_provider.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/WebContentsUtils_jni.h"
 
-using base::android::ConvertJavaStringToUTF16;
-using base::android::ConvertUTF8ToJavaString;
 using base::android::JavaParamRef;
-using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace content {
 
-namespace {
-
-void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
-                              const base::Value* result) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  std::string json;
-  base::JSONWriter::Write(*result, &json);
-  ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
-  Java_WebContentsUtils_onEvaluateJavaScriptResult(env, j_json, callback);
-}
-
-}  // namespace
-
 // Reports all frame submissions to the browser process, even those that do not
 // impact Browser UI.
 void JNI_WebContentsUtils_ReportAllFrameSubmissions(
@@ -57,47 +39,4 @@
       ->GetJavaRenderFrameHost();
 }
 
-void JNI_WebContentsUtils_EvaluateJavaScript(
-    JNIEnv* env,
-    const JavaParamRef<jclass>& clazz,
-    const JavaParamRef<jobject>& jweb_contents,
-    const JavaParamRef<jstring>& script,
-    const JavaParamRef<jobject>& callback) {
-  EvaluateJavaScript(env, jweb_contents, script, callback);
-}
-
-void EvaluateJavaScript(JNIEnv* env,
-                        const JavaParamRef<jobject>& jweb_contents,
-                        const JavaParamRef<jstring>& script,
-                        const JavaParamRef<jobject>& callback) {
-  WebContents* web_contents = WebContents::FromJavaWebContents(jweb_contents);
-  RenderViewHost* rvh = web_contents->GetRenderViewHost();
-  DCHECK(rvh);
-
-  if (!rvh->IsRenderViewLive()) {
-    if (!static_cast<WebContentsImpl*>(web_contents)
-             ->CreateRenderViewForInitialEmptyDocument()) {
-      LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScriptForTests";
-      return;
-    }
-  }
-
-  if (!callback) {
-    // No callback requested.
-    web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
-        ConvertJavaStringToUTF16(env, script));
-    return;
-  }
-
-  // Secure the Java callback in a scoped object and give ownership of it to the
-  // base::Callback.
-  ScopedJavaGlobalRef<jobject> j_callback;
-  j_callback.Reset(env, callback);
-  RenderFrameHost::JavaScriptResultCallback js_callback =
-      base::Bind(&JavaScriptResultCallback, j_callback);
-
-  web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
-      ConvertJavaStringToUTF16(env, script), js_callback);
-}
-
 }  // namespace content
diff --git a/content/public/test/android/web_contents_utils.h b/content/public/test/android/web_contents_utils.h
deleted file mode 100644
index 9b64a908..0000000
--- a/content/public/test/android/web_contents_utils.h
+++ /dev/null
@@ -1,22 +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 CONTENT_PUBLIC_TEST_ANDROID_WEB_CONTENTS_UTILS_H_
-#define CONTENT_PUBLIC_TEST_ANDROID_WEB_CONTENTS_UTILS_H_
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-
-namespace content {
-
-void EvaluateJavaScript(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& jweb_contents,
-    const base::android::JavaParamRef<jstring>& script,
-    const base::android::JavaParamRef<jobject>& callback);
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_TEST_ANDROID_WEB_CONTENTS_UTILS_H_
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.cc b/content/renderer/accessibility/blink_ax_enum_conversion.cc
index d51402b4..00346c1 100644
--- a/content/renderer/accessibility/blink_ax_enum_conversion.cc
+++ b/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -409,73 +409,6 @@
   }
 }
 
-ax::mojom::Event AXEventFromBlink(blink::WebAXEvent event) {
-  switch (event) {
-    case blink::kWebAXEventActiveDescendantChanged:
-      return ax::mojom::Event::kActiveDescendantChanged;
-    case blink::kWebAXEventAriaAttributeChanged:
-      return ax::mojom::Event::kAriaAttributeChanged;
-    case blink::kWebAXEventAutocorrectionOccured:
-      return ax::mojom::Event::kAutocorrectionOccured;
-    case blink::kWebAXEventBlur:
-      return ax::mojom::Event::kBlur;
-    case blink::kWebAXEventCheckedStateChanged:
-      return ax::mojom::Event::kCheckedStateChanged;
-    case blink::kWebAXEventChildrenChanged:
-      return ax::mojom::Event::kChildrenChanged;
-    case blink::kWebAXEventClicked:
-      return ax::mojom::Event::kClicked;
-    case blink::kWebAXEventDocumentSelectionChanged:
-      return ax::mojom::Event::kDocumentSelectionChanged;
-    case blink::kWebAXEventDocumentTitleChanged:
-      return ax::mojom::Event::kDocumentTitleChanged;
-    case blink::kWebAXEventExpandedChanged:
-      return ax::mojom::Event::kExpandedChanged;
-    case blink::kWebAXEventFocus:
-      return ax::mojom::Event::kFocus;
-    case blink::kWebAXEventHover:
-      return ax::mojom::Event::kHover;
-    case blink::kWebAXEventInvalidStatusChanged:
-      return ax::mojom::Event::kInvalidStatusChanged;
-    case blink::kWebAXEventLayoutComplete:
-      return ax::mojom::Event::kLayoutComplete;
-    case blink::kWebAXEventLiveRegionChanged:
-      return ax::mojom::Event::kLiveRegionChanged;
-    case blink::kWebAXEventLoadComplete:
-      return ax::mojom::Event::kLoadComplete;
-    case blink::kWebAXEventLocationChanged:
-      return ax::mojom::Event::kLocationChanged;
-    case blink::kWebAXEventMenuListItemSelected:
-      return ax::mojom::Event::kMenuListItemSelected;
-    case blink::kWebAXEventMenuListItemUnselected:
-      return ax::mojom::Event::kMenuListItemSelected;
-    case blink::kWebAXEventMenuListValueChanged:
-      return ax::mojom::Event::kMenuListValueChanged;
-    case blink::kWebAXEventRowCollapsed:
-      return ax::mojom::Event::kRowCollapsed;
-    case blink::kWebAXEventRowCountChanged:
-      return ax::mojom::Event::kRowCountChanged;
-    case blink::kWebAXEventRowExpanded:
-      return ax::mojom::Event::kRowExpanded;
-    case blink::kWebAXEventScrollPositionChanged:
-      return ax::mojom::Event::kScrollPositionChanged;
-    case blink::kWebAXEventScrolledToAnchor:
-      return ax::mojom::Event::kScrolledToAnchor;
-    case blink::kWebAXEventSelectedChildrenChanged:
-      return ax::mojom::Event::kSelectedChildrenChanged;
-    case blink::kWebAXEventSelectedTextChanged:
-      return ax::mojom::Event::kTextSelectionChanged;
-    case blink::kWebAXEventTextChanged:
-      return ax::mojom::Event::kTextChanged;
-    case blink::kWebAXEventValueChanged:
-      return ax::mojom::Event::kValueChanged;
-    default:
-      // We can't add an assertion here, that prevents us
-      // from adding new event enums in Blink.
-      return ax::mojom::Event::kNone;
-  }
-}
-
 ax::mojom::DefaultActionVerb AXDefaultActionVerbFromBlink(
     blink::WebAXDefaultActionVerb action_verb) {
   switch (action_verb) {
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.h b/content/renderer/accessibility/blink_ax_enum_conversion.h
index 0c543f27..82500cc 100644
--- a/content/renderer/accessibility/blink_ax_enum_conversion.h
+++ b/content/renderer/accessibility/blink_ax_enum_conversion.h
@@ -16,10 +16,6 @@
 // Convert a Blink WebAXRole to an ax::mojom::Role defined in ui/accessibility.
 ax::mojom::Role AXRoleFromBlink(blink::WebAXRole role);
 
-// Convert a Blink WebAXEvent to an ax::mojom::Event defined in
-// ui/accessibility.
-ax::mojom::Event AXEventFromBlink(blink::WebAXEvent event);
-
 // Provides a conversion between the WebAXObject state
 // accessors and a state bitmask stored in an AXNodeData.
 // (Note that some rare states are sent as boolean attributes
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 31ec8b961..27cba58 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -201,8 +201,9 @@
 }
 
 void RenderAccessibilityImpl::HandleWebAccessibilityEvent(
-    const blink::WebAXObject& obj, blink::WebAXEvent event) {
-  HandleAXEvent(obj, AXEventFromBlink(event));
+    const blink::WebAXObject& obj,
+    ax::mojom::Event event) {
+  HandleAXEvent(obj, event);
 }
 
 void RenderAccessibilityImpl::HandleAccessibilityFindInPageResult(
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h
index 240a0ff6..7acea8b 100644
--- a/content/renderer/accessibility/render_accessibility_impl.h
+++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -80,7 +80,7 @@
 
   // Called when an accessibility notification occurs in Blink.
   void HandleWebAccessibilityEvent(const blink::WebAXObject& obj,
-                                   blink::WebAXEvent event);
+                                   ax::mojom::Event event);
 
   // Called when a new find in page result is highlighted.
   void HandleAccessibilityFindInPageResult(
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 963702e..aea320e1 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -881,4 +881,8 @@
   return GetContentClient()->renderer()->GetSadWebViewBitmap();
 }
 
+bool BrowserPlugin::HasPointerEventsNone() {
+  return false;
+}
+
 }  // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index b3091678..5896a9d 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -229,6 +229,8 @@
                 bool prevent_contents_opaque_changes) override;
   SkBitmap* GetSadPageBitmap() override;
 
+  bool HasPointerEventsNone() override;
+
   // This indicates whether this BrowserPlugin has been attached to a
   // WebContents and is ready to receive IPCs.
   bool attached_;
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index ba7454e..7c502bad 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -82,6 +82,8 @@
   surface_layer_ = cc::SurfaceLayer::Create();
   surface_layer_->SetMasksToBounds(true);
   surface_layer_->SetSurfaceHitTestable(true);
+  surface_layer_->SetHasPointerEventsNone(
+      child_frame_compositor_->HasPointerEventsNone());
   surface_layer_->SetBackgroundColor(SK_ColorTRANSPARENT);
 
   surface_layer_->SetPrimarySurfaceId(surface_id, deadline);
@@ -118,4 +120,14 @@
     layer->SetIsDrawable(visible);
 }
 
+void ChildFrameCompositingHelper::SetHasPointerEventsNone(
+    bool has_pointer_events_none) {
+  if (!primary_surface_id_.is_valid())
+    return;
+  cc::SurfaceLayer* layer =
+      static_cast<cc::SurfaceLayer*>(child_frame_compositor_->GetLayer());
+  if (layer)
+    layer->SetHasPointerEventsNone(has_pointer_events_none);
+}
+
 }  // namespace content
diff --git a/content/renderer/child_frame_compositing_helper.h b/content/renderer/child_frame_compositing_helper.h
index 7a05417..23cf9f76 100644
--- a/content/renderer/child_frame_compositing_helper.h
+++ b/content/renderer/child_frame_compositing_helper.h
@@ -41,6 +41,7 @@
   void SetFallbackSurfaceId(const viz::SurfaceId& surface_id,
                             const gfx::Size& frame_size_in_dip);
   void UpdateVisibility(bool visible);
+  void SetHasPointerEventsNone(bool has_pointer_events_none);
   void ChildFrameGone(const gfx::Size& frame_size_in_dip,
                       float device_scale_factor);
 
diff --git a/content/renderer/child_frame_compositing_helper_unittest.cc b/content/renderer/child_frame_compositing_helper_unittest.cc
index d2c3e49..a42db10 100644
--- a/content/renderer/child_frame_compositing_helper_unittest.cc
+++ b/content/renderer/child_frame_compositing_helper_unittest.cc
@@ -27,6 +27,8 @@
     layer_ = std::move(layer);
   }
 
+  bool HasPointerEventsNone() override { return false; }
+
   SkBitmap* GetSadPageBitmap() override { return &sad_page_bitmap_; }
 
  private:
diff --git a/content/renderer/child_frame_compositor.h b/content/renderer/child_frame_compositor.h
index f93b026..a2a22c5 100644
--- a/content/renderer/child_frame_compositor.h
+++ b/content/renderer/child_frame_compositor.h
@@ -24,6 +24,8 @@
 
   // Returns a sad page bitmap used when the child frame has crashed.
   virtual SkBitmap* GetSadPageBitmap() = 0;
+
+  virtual bool HasPointerEventsNone() = 0;
 };
 
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 68e0840..630624c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -310,31 +310,6 @@
 
 namespace content {
 
-// Helper struct keeping track in one place of all the parameters the browser
-// provided to the renderer to commit a navigation.
-struct PendingNavigationParams {
-  PendingNavigationParams(
-      const CommonNavigationParams& common_params,
-      const RequestNavigationParams& request_params,
-      base::TimeTicks time_commit_requested,
-      content::mojom::FrameNavigationControl::CommitNavigationCallback
-          commit_callback)
-      : common_params(common_params),
-        request_params(request_params),
-        time_commit_requested(time_commit_requested),
-        commit_callback_(std::move(commit_callback)) {}
-  ~PendingNavigationParams() = default;
-
-  CommonNavigationParams common_params;
-  RequestNavigationParams request_params;
-
-  // Time when RenderFrameImpl::CommitNavigation() is called.
-  base::TimeTicks time_commit_requested;
-
-  content::mojom::FrameNavigationControl::CommitNavigationCallback
-      commit_callback_;
-};
-
 namespace {
 
 const int kExtraCharsBeforeAndAfterSelection = 100;
@@ -421,14 +396,6 @@
   return document_loader->OriginalRequest().Url();
 }
 
-bool IsBrowserInitiated(PendingNavigationParams* pending) {
-  // A navigation resulting from loading a javascript URL should not be treated
-  // as a browser initiated event.  Instead, we want it to look as if the page
-  // initiated any load resulting from JS execution.
-  return pending &&
-         !pending->common_params.url.SchemeIs(url::kJavaScriptScheme);
-}
-
 // Returns false unless this is a top-level navigation.
 bool IsTopLevelNavigation(WebFrame* frame) {
   return frame->Parent() == nullptr;
@@ -804,7 +771,7 @@
 }
 
 // Creates a fully functional DocumentState in the case where we do not have
-// pending_navigation_params_ available in the RenderFrameImpl.
+// navigation parameters available.
 std::unique_ptr<DocumentState> BuildDocumentState() {
   std::unique_ptr<DocumentState> document_state =
       std::make_unique<DocumentState>();
@@ -814,23 +781,17 @@
 }
 
 // Creates a fully functional DocumentState in the case where we have
-// pending_navigation_params_ available in the RenderFrameImpl.
-// TODO(ahemery): This currently removes the callback from the pending params
-// which is a bit counterintuitive. We would like to leave
-// pending_navigation_params in a valid state. Callback should probably not be
-// a part of PendingNavigationParams.
-std::unique_ptr<DocumentState> BuildDocumentStateFromPending(
-    PendingNavigationParams* pending_navigation_params,
+// navigation parameters available in the RenderFrameImpl.
+std::unique_ptr<DocumentState> BuildDocumentStateFromParams(
+    const CommonNavigationParams& common_params,
+    const RequestNavigationParams& request_params,
+    base::TimeTicks time_commit_requested,
+    mojom::FrameNavigationControl::CommitNavigationCallback commit_callback,
     const network::ResourceResponseHead* head) {
   std::unique_ptr<DocumentState> document_state(new DocumentState());
   InternalDocumentStateData* internal_data =
       InternalDocumentStateData::FromDocumentState(document_state.get());
 
-  const CommonNavigationParams& common_params =
-      pending_navigation_params->common_params;
-  const RequestNavigationParams& request_params =
-      pending_navigation_params->request_params;
-
   DCHECK(!common_params.navigation_start.is_null());
   DCHECK(!common_params.url.SchemeIs(url::kJavaScriptScheme));
 
@@ -877,11 +838,9 @@
     document_state->set_data_url(common_params.url);
 
   document_state->set_navigation_state(
-      NavigationStateImpl::CreateBrowserInitiated(
-          pending_navigation_params->common_params,
-          pending_navigation_params->request_params,
-          pending_navigation_params->time_commit_requested,
-          std::move(pending_navigation_params->commit_callback_)));
+      NavigationStateImpl::CreateBrowserInitiated(common_params, request_params,
+                                                  time_commit_requested,
+                                                  std::move(commit_callback)));
   return document_state;
 }
 
@@ -2641,24 +2600,17 @@
   // If we failed on a browser initiated request, then make sure that our error
   // page load is regarded as the same browser initiated request.
   if (!navigation_state->IsContentInitiated()) {
-    pending_navigation_params_.reset(new PendingNavigationParams(
+    document_state = BuildDocumentStateFromParams(
         navigation_state->common_params(), navigation_state->request_params(),
-        base::TimeTicks(),  // not used for failed navigation.
-        CommitNavigationCallback()));
-    document_state = BuildDocumentStateFromPending(
-        pending_navigation_params_.get(), nullptr);
+        base::TimeTicks(),  // Not used for failed navigation.
+        CommitNavigationCallback(), nullptr);
     navigation_params = BuildNavigationParams(
-        pending_navigation_params_->common_params,
-        pending_navigation_params_->request_params,
+        navigation_state->common_params(), navigation_state->request_params(),
         BuildServiceWorkerNetworkProviderForNavigation(
             nullptr /* request_params */,
             nullptr /* controller_service_worker_info */));
   }
 
-  DCHECK(!pending_navigation_params_ || document_state)
-      << "We should never have pending_navigation_params_ if we "
-         "are not coming from CommitFailedNavigation.";
-
   LoadNavigationErrorPage(failed_request, error, replace, nullptr,
                           error_page_content, std::move(navigation_params),
                           std::move(document_state));
@@ -3135,9 +3087,6 @@
   if (request_params.is_view_source)
     frame_->EnableViewSourceMode(true);
 
-  pending_navigation_params_.reset(
-      new PendingNavigationParams(common_params, request_params,
-                                  base::TimeTicks::Now(), std::move(callback)));
   PrepareFrameForCommit(common_params.url, request_params);
 
   // We only save metrics of the main frame's main resource to the
@@ -3147,8 +3096,9 @@
   const network::ResourceResponseHead* response_head = nullptr;
   if (!frame_->Parent() && !frame_->IsViewSourceModeEnabled())
     response_head = &head;
-  std::unique_ptr<DocumentState> document_state(BuildDocumentStateFromPending(
-      pending_navigation_params_.get(), response_head));
+  std::unique_ptr<DocumentState> document_state(BuildDocumentStateFromParams(
+      common_params, request_params, base::TimeTicks::Now(),
+      std::move(callback), response_head));
 
   blink::WebFrameLoadType load_type = NavigationTypeToLoadType(
       common_params.navigation_type, common_params.should_replace_current_entry,
@@ -3217,9 +3167,6 @@
       Send(new FrameHostMsg_DidStopLoading(routing_id_));
   }
 
-  // In case LoadRequest failed before DidCreateDocumentLoader was called.
-  pending_navigation_params_.reset();
-
   // Reset the source location now that the commit checks have been processed.
   frame_->GetDocumentLoader()->ResetSourceLocation();
   if (frame_->GetProvisionalDocumentLoader())
@@ -3279,7 +3226,6 @@
     // The browser expects this frame to be loading an error page. Inform it
     // that the load stopped.
     std::move(callback).Run(blink::mojom::CommitResult::Aborted);
-    pending_navigation_params_.reset();
     Send(new FrameHostMsg_DidStopLoading(routing_id_));
     browser_side_navigation_pending_ = false;
     browser_side_navigation_pending_url_ = GURL();
@@ -3298,7 +3244,6 @@
       // unrelated to this navigation failure. In that case, just send a stop
       // IPC to the browser to unwind its state, and leave the frame as-is.
       std::move(callback).Run(blink::mojom::CommitResult::Aborted);
-      pending_navigation_params_.reset();
       Send(new FrameHostMsg_DidStopLoading(routing_id_));
     } else {
       std::move(callback).Run(blink::mojom::CommitResult::Ok);
@@ -3332,16 +3277,13 @@
   // otherwise it will result in a use-after-free bug.
   base::WeakPtr<RenderFrameImpl> weak_this = weak_factory_.GetWeakPtr();
 
-  pending_navigation_params_.reset(new PendingNavigationParams(
-      common_params, request_params,
-      base::TimeTicks(),  // Not used for failed navigation.
-      std::move(callback)));
   std::unique_ptr<blink::WebNavigationParams> navigation_params =
       BuildNavigationParams(common_params, request_params,
                             BuildServiceWorkerNetworkProviderForNavigation(
                                 &request_params, nullptr));
-  std::unique_ptr<DocumentState> navigation_data(
-      BuildDocumentStateFromPending(pending_navigation_params_.get(), nullptr));
+  std::unique_ptr<DocumentState> navigation_data(BuildDocumentStateFromParams(
+      common_params, request_params, base::TimeTicks(), std::move(callback),
+      nullptr));
 
   // For renderer initiated navigations, we send out a didFailProvisionalLoad()
   // notification.
@@ -3448,8 +3390,6 @@
       commit_status != blink::mojom::CommitResult::Ok) {
     Send(new FrameHostMsg_DidStopLoading(routing_id_));
   }
-
-  pending_navigation_params_.reset();
 }
 
 void RenderFrameImpl::HandleRendererDebugURL(const GURL& url) {
@@ -4106,7 +4046,6 @@
 
 void RenderFrameImpl::DidCreateDocumentLoader(
     blink::WebDocumentLoader* document_loader) {
-  pending_navigation_params_.reset();
   DocumentState* document_state =
       DocumentState::FromDocumentLoader(document_loader);
   if (!document_state) {
@@ -4595,10 +4534,6 @@
   static_cast<NavigationStateImpl*>(document_state->navigation_state())
       ->set_was_within_same_document(true);
 
-  // Just reset pending navigation params here, if they exist they are for some
-  // other navigation <https://crbug.com/597239>.
-  pending_navigation_params_.reset();
-
   DidCommitNavigationInternal(item, commit_type,
                               true /* was_within_same_document */,
                               nullptr /* remote_interface_provider_request */);
@@ -4827,7 +4762,6 @@
 }
 
 void RenderFrameImpl::WillSendRequest(blink::WebURLRequest& request) {
-  CHECK(!pending_navigation_params_);
   // TODO(ahemery): We should skip the processing for the main resource, it has
   // been done before sending the request to the browser.
 
@@ -5302,7 +5236,7 @@
 }
 
 void RenderFrameImpl::PostAccessibilityEvent(const blink::WebAXObject& obj,
-                                             blink::WebAXEvent event) {
+                                             ax::mojom::Event event) {
   HandleWebAccessibilityEvent(obj, event);
 }
 
@@ -5925,8 +5859,8 @@
   Send(new FrameHostMsg_DidChangeLoadProgress(routing_id_, load_progress));
 }
 
-void RenderFrameImpl::HandleWebAccessibilityEvent(
-    const blink::WebAXObject& obj, blink::WebAXEvent event) {
+void RenderFrameImpl::HandleWebAccessibilityEvent(const blink::WebAXObject& obj,
+                                                  ax::mojom::Event event) {
   if (render_accessibility_)
     render_accessibility_->HandleWebAccessibilityEvent(obj, event);
 }
@@ -6451,18 +6385,8 @@
   params.triggering_event_info = info.triggering_event_info;
   params.blob_url_token =
       CloneBlobURLToken(info.blob_url_token.get()).PassHandle().release();
-
-  if (IsBrowserInitiated(pending_navigation_params_.get())) {
-    // This is necessary to preserve the should_replace_current_entry value on
-    // cross-process redirects, in the event it was set by a previous process.
-    WebDocumentLoader* document_loader = frame_->GetProvisionalDocumentLoader();
-    DCHECK(document_loader);
-    params.should_replace_current_entry =
-        document_loader->ReplacesCurrentHistoryItem();
-  } else {
-    params.should_replace_current_entry = info.replaces_current_history_item &&
-                                          render_view_->history_list_length_;
-  }
+  params.should_replace_current_entry =
+      info.replaces_current_history_item && render_view_->history_list_length_;
   params.user_gesture =
       WebUserGestureIndicator::IsProcessingUserGesture(frame_);
   if (GetContentClient()->renderer()->AllowPopup())
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 65655f0..0240d4a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -161,7 +161,6 @@
 class ManifestManager;
 class MediaPermissionDispatcher;
 class MediaStreamDeviceObserver;
-class NavigationState;
 class NavigationClient;
 class PepperPluginInstanceImpl;
 class PushMessagingClient;
@@ -181,7 +180,6 @@
 struct FileChooserParams;
 struct FrameOwnerProperties;
 struct FrameReplicationState;
-struct PendingNavigationParams;
 struct RequestNavigationParams;
 struct ScreenInfo;
 
@@ -339,7 +337,7 @@
   bool in_frame_tree() { return in_frame_tree_; }
 
   void HandleWebAccessibilityEvent(const blink::WebAXObject& obj,
-                                   blink::WebAXEvent event);
+                                   ax::mojom::Event event);
 
   // The focused node changed to |node|. If focus was lost from this frame,
   // |node| will be null.
@@ -722,7 +720,7 @@
   bool AllowContentInitiatedDataUrlNavigations(
       const blink::WebURL& url) override;
   void PostAccessibilityEvent(const blink::WebAXObject& obj,
-                              blink::WebAXEvent event) override;
+                              ax::mojom::Event event) override;
   void HandleAccessibilityFindInPageResult(int identifier,
                                            int match_index,
                                            const blink::WebNode& start_node,
@@ -1377,11 +1375,6 @@
   // parent that is a local frame.
   scoped_refptr<RenderWidget> render_widget_;
 
-  // Temporarily holds state pertaining to a navigation that has been initiated
-  // until the NavigationState corresponding to the new navigation is created in
-  // DidCreateDocumentLoader().
-  std::unique_ptr<PendingNavigationParams> pending_navigation_params_;
-
   // Keeps track of which future subframes the browser process has history items
   // for during a history navigation, as well as whether those items are for
   // about:blank.  The renderer process should ask the browser for history items
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 954ea7f..16f9ce3 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -838,6 +838,10 @@
                                                          touch_action));
 }
 
+void RenderFrameProxy::PointerEventsChanged() {
+  compositing_helper_->SetHasPointerEventsNone(HasPointerEventsNone());
+}
+
 void RenderFrameProxy::UpdateRenderThrottlingStatus(bool is_throttled,
                                                     bool subtree_throttled) {
   Send(new FrameHostMsg_UpdateRenderThrottlingStatus(routing_id_, is_throttled,
@@ -906,6 +910,10 @@
   return GetContentClient()->renderer()->GetSadWebViewBitmap();
 }
 
+bool RenderFrameProxy::HasPointerEventsNone() {
+  return web_frame()->OOPIFHasPointerEventsNone();
+}
+
 uint32_t RenderFrameProxy::Print(const blink::WebRect& rect,
                                  cc::PaintCanvas* canvas) {
 #if BUILDFLAG(ENABLE_PRINTING)
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 4715761b..d7d727cc 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -201,6 +201,7 @@
   void VisibilityChanged(bool visible) override;
   void SetIsInert(bool) override;
   void SetInheritedEffectiveTouchAction(cc::TouchAction) override;
+  void PointerEventsChanged() override;
   void UpdateRenderThrottlingStatus(bool is_throttled,
                                     bool subtree_throttled) override;
   void DidChangeOpener(blink::WebFrame* opener) override;
@@ -276,6 +277,7 @@
   void SetLayer(scoped_refptr<cc::Layer> layer,
                 bool prevent_contents_opaque_changes) override;
   SkBitmap* GetSadPageBitmap() override;
+  bool HasPointerEventsNone() override;
 
   const viz::LocalSurfaceId& GetLocalSurfaceId() const;
 
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index bdfd146..617fcda2 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -165,7 +165,6 @@
   start_data.script_url = params->script_url;
   start_data.user_agent =
       blink::WebString::FromUTF8(GetContentClient()->GetUserAgent());
-  start_data.script_type = params->script_type;
   start_data.wait_for_debugger_mode =
       params->wait_for_debugger
           ? blink::WebEmbeddedWorkerStartData::kWaitForDebugger
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index 2a34a8e..deac479e 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -290,8 +290,7 @@
     registration_info->registration_id = 100;  // dummy
     registration_info->options =
         blink::mojom::ServiceWorkerRegistrationOptions::New(
-            kScope, blink::mojom::ScriptType::kClassic,
-            blink::mojom::ServiceWorkerUpdateViaCache::kAll);
+            kScope, blink::mojom::ServiceWorkerUpdateViaCache::kAll);
     out_pipes->registration_host_request =
         mojo::MakeRequest(&registration_info->host_ptr_info);
     registration_info->request = mojo::MakeRequest(&out_pipes->registration);
diff --git a/content/renderer/service_worker/web_service_worker_provider_impl.cc b/content/renderer/service_worker/web_service_worker_provider_impl.cc
index b9c8626..0a66df3 100644
--- a/content/renderer/service_worker/web_service_worker_provider_impl.cc
+++ b/content/renderer/service_worker/web_service_worker_provider_impl.cc
@@ -70,7 +70,6 @@
 void WebServiceWorkerProviderImpl::RegisterServiceWorker(
     const WebURL& web_pattern,
     const WebURL& web_script_url,
-    blink::mojom::ScriptType script_type,
     blink::mojom::ServiceWorkerUpdateViaCache update_via_cache,
     std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks) {
   DCHECK(callbacks);
@@ -99,13 +98,8 @@
   TRACE_EVENT_ASYNC_BEGIN2(
       "ServiceWorker", "WebServiceWorkerProviderImpl::RegisterServiceWorker",
       this, "Scope", pattern.spec(), "Script URL", script_url.spec());
-
-  // TODO(asamidoi): Create this options in
-  // ServiceWorkerContainer::RegisterServiceWorker() and pass it as an argument
-  // in this function instead of blink::mojom::ScriptType and
-  // blink::mojom::ServiceWorkerUpdateViaCache.
   auto options = blink::mojom::ServiceWorkerRegistrationOptions::New(
-      pattern, script_type, update_via_cache);
+      pattern, update_via_cache);
   context_->container_host()->Register(
       script_url, std::move(options),
       base::BindOnce(&WebServiceWorkerProviderImpl::OnRegistered,
diff --git a/content/renderer/service_worker/web_service_worker_provider_impl.h b/content/renderer/service_worker/web_service_worker_provider_impl.h
index 3f7602f1..9f60733 100644
--- a/content/renderer/service_worker/web_service_worker_provider_impl.h
+++ b/content/renderer/service_worker/web_service_worker_provider_impl.h
@@ -41,7 +41,6 @@
   void RegisterServiceWorker(
       const blink::WebURL& web_pattern,
       const blink::WebURL& web_script_url,
-      blink::mojom::ScriptType script_type,
       blink::mojom::ServiceWorkerUpdateViaCache update_via_cache,
       std::unique_ptr<WebServiceWorkerRegistrationCallbacks>) override;
   void GetRegistration(
diff --git a/content/shell/test_runner/web_frame_test_client.cc b/content/shell/test_runner/web_frame_test_client.cc
index 404c9eff..42ff1b6 100644
--- a/content/shell/test_runner/web_frame_test_client.cc
+++ b/content/shell/test_runner/web_frame_test_client.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/public/web/web_plugin_params.h"
 #include "third_party/blink/public/web/web_user_gesture_indicator.h"
 #include "third_party/blink/public/web/web_view.h"
+#include "ui/accessibility/ax_enums.mojom.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
@@ -216,7 +217,7 @@
 }
 
 void WebFrameTestClient::PostAccessibilityEvent(const blink::WebAXObject& obj,
-                                                blink::WebAXEvent event) {
+                                                ax::mojom::Event event) {
   // Only hook the accessibility events occured during the test run.
   // This check prevents false positives in BlinkLeakDetector.
   // The pending tasks in browser/renderer message queue may trigger
@@ -228,94 +229,85 @@
 
   const char* event_name = nullptr;
   switch (event) {
-    case blink::kWebAXEventActiveDescendantChanged:
+    case ax::mojom::Event::kActiveDescendantChanged:
       event_name = "ActiveDescendantChanged";
       break;
-    case blink::kWebAXEventAriaAttributeChanged:
+    case ax::mojom::Event::kAriaAttributeChanged:
       event_name = "AriaAttributeChanged";
       break;
-    case blink::kWebAXEventAutocorrectionOccured:
+    case ax::mojom::Event::kAutocorrectionOccured:
       event_name = "AutocorrectionOccured";
       break;
-    case blink::kWebAXEventBlur:
+    case ax::mojom::Event::kBlur:
       event_name = "Blur";
       break;
-    case blink::kWebAXEventCheckedStateChanged:
+    case ax::mojom::Event::kCheckedStateChanged:
       event_name = "CheckedStateChanged";
       break;
-    case blink::kWebAXEventChildrenChanged:
+    case ax::mojom::Event::kChildrenChanged:
       event_name = "ChildrenChanged";
       break;
-    case blink::kWebAXEventClicked:
+    case ax::mojom::Event::kClicked:
       event_name = "Clicked";
       break;
-    case blink::kWebAXEventDocumentSelectionChanged:
+    case ax::mojom::Event::kDocumentSelectionChanged:
       event_name = "DocumentSelectionChanged";
       break;
-    case blink::kWebAXEventDocumentTitleChanged:
+    case ax::mojom::Event::kDocumentTitleChanged:
       event_name = "DocumentTitleChanged";
       break;
-    case blink::kWebAXEventFocus:
+    case ax::mojom::Event::kFocus:
       event_name = "Focus";
       break;
-    case blink::kWebAXEventHide:
-      event_name = "Hide";
-      break;
-    case blink::kWebAXEventHover:
+    case ax::mojom::Event::kHover:
       event_name = "Hover";
       break;
-    case blink::kWebAXEventInvalidStatusChanged:
+    case ax::mojom::Event::kInvalidStatusChanged:
       event_name = "InvalidStatusChanged";
       break;
-    case blink::kWebAXEventLayoutComplete:
+    case ax::mojom::Event::kLayoutComplete:
       event_name = "LayoutComplete";
       break;
-    case blink::kWebAXEventLiveRegionChanged:
+    case ax::mojom::Event::kLiveRegionChanged:
       event_name = "LiveRegionChanged";
       break;
-    case blink::kWebAXEventLoadComplete:
+    case ax::mojom::Event::kLoadComplete:
       event_name = "LoadComplete";
       break;
-    case blink::kWebAXEventLocationChanged:
+    case ax::mojom::Event::kLocationChanged:
       event_name = "LocationChanged";
       break;
-    case blink::kWebAXEventMenuListItemSelected:
+    case ax::mojom::Event::kMenuListItemSelected:
       event_name = "MenuListItemSelected";
       break;
-    case blink::kWebAXEventMenuListItemUnselected:
-      event_name = "MenuListItemUnselected";
-      break;
-    case blink::kWebAXEventMenuListValueChanged:
+    case ax::mojom::Event::kMenuListValueChanged:
       event_name = "MenuListValueChanged";
       break;
-    case blink::kWebAXEventRowCollapsed:
+    case ax::mojom::Event::kRowCollapsed:
       event_name = "RowCollapsed";
       break;
-    case blink::kWebAXEventRowCountChanged:
+    case ax::mojom::Event::kRowCountChanged:
       event_name = "RowCountChanged";
       break;
-    case blink::kWebAXEventRowExpanded:
+    case ax::mojom::Event::kRowExpanded:
       event_name = "RowExpanded";
       break;
-    case blink::kWebAXEventScrollPositionChanged:
+    case ax::mojom::Event::kScrollPositionChanged:
       event_name = "ScrollPositionChanged";
       break;
-    case blink::kWebAXEventScrolledToAnchor:
+    case ax::mojom::Event::kScrolledToAnchor:
       event_name = "ScrolledToAnchor";
       break;
-    case blink::kWebAXEventSelectedChildrenChanged:
+    case ax::mojom::Event::kSelectedChildrenChanged:
       event_name = "SelectedChildrenChanged";
       break;
-    case blink::kWebAXEventSelectedTextChanged:
+    case ax::mojom::Event::kTextSelectionChanged:
       event_name = "SelectedTextChanged";
       break;
-    case blink::kWebAXEventShow:
-      event_name = "Show";
-      break;
-    case blink::kWebAXEventTextChanged:
+    case ax::mojom::Event::kTextChanged:
       event_name = "TextChanged";
       break;
-    case blink::kWebAXEventValueChanged:
+    case ax::mojom::Event::kValueChanged:
       event_name = "ValueChanged";
       break;
     default:
diff --git a/content/shell/test_runner/web_frame_test_client.h b/content/shell/test_runner/web_frame_test_client.h
index b63ff5f2..8e5ff62 100644
--- a/content/shell/test_runner/web_frame_test_client.h
+++ b/content/shell/test_runner/web_frame_test_client.h
@@ -41,7 +41,7 @@
                             blink::WebString* actual_value) override;
   bool RunModalBeforeUnloadDialog(bool is_reload) override;
   void PostAccessibilityEvent(const blink::WebAXObject& object,
-                              blink::WebAXEvent event) override;
+                              ax::mojom::Event event) override;
   void DidChangeSelection(bool is_selection_empty) override;
   void DidChangeContents() override;
   blink::WebPlugin* CreatePlugin(const blink::WebPluginParams& params) override;
diff --git a/content/shell/test_runner/web_frame_test_proxy.cc b/content/shell/test_runner/web_frame_test_proxy.cc
index 0adaee59..ca8b973 100644
--- a/content/shell/test_runner/web_frame_test_proxy.cc
+++ b/content/shell/test_runner/web_frame_test_proxy.cc
@@ -210,7 +210,7 @@
 }
 
 void WebFrameTestProxy::PostAccessibilityEvent(const blink::WebAXObject& object,
-                                               blink::WebAXEvent event) {
+                                               ax::mojom::Event event) {
   test_client_->PostAccessibilityEvent(object, event);
   // Guard against the case where |this| was deleted as a result of an
   // accessibility listener detaching a frame. If that occurs, the
diff --git a/content/shell/test_runner/web_frame_test_proxy.h b/content/shell/test_runner/web_frame_test_proxy.h
index 9338c7e..8a61862 100644
--- a/content/shell/test_runner/web_frame_test_proxy.h
+++ b/content/shell/test_runner/web_frame_test_proxy.h
@@ -106,7 +106,7 @@
   blink::WebNavigationPolicy DecidePolicyForNavigation(
       const blink::WebLocalFrameClient::NavigationPolicyInfo& info) override;
   void PostAccessibilityEvent(const blink::WebAXObject& object,
-                              blink::WebAXEvent event) override;
+                              ax::mojom::Event event) override;
   void CheckIfAudioSinkExistsAndIsAuthorized(
       const blink::WebString& sink_id,
       blink::WebSetSinkIdCallbacks* web_callbacks) override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 00151df..d9f5f62 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -897,6 +897,7 @@
     "../browser/webrtc/webrtc_stress_source_switch_browsertest.cc",
     "../browser/webrtc/webrtc_video_capture_browsertest.cc",
     "../browser/webrtc/webrtc_video_capture_service_browsertest.cc",
+    "../browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc",
     "../browser/webrtc/webrtc_webcam_browsertest.cc",
     "../browser/webrtc/webrtc_webcam_browsertest.h",
     "../browser/webui/web_ui_mojo_browsertest.cc",
@@ -2036,7 +2037,10 @@
     }
   }
   if (is_win) {
-    deps += [ "//third_party/iaccessible2" ]
+    deps += [
+      "//third_party/blink/public/common",
+      "//third_party/iaccessible2",
+    ]
     libs = [ "dwrite.lib" ]
   }
   if (is_mac) {
diff --git a/content/test/data/accessibility/aria/aria-editable-expected-auralinux.txt b/content/test/data/accessibility/aria/aria-editable-expected-auralinux.txt
new file mode 100644
index 0000000..e54a5f8
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-editable-expected-auralinux.txt
@@ -0,0 +1,8 @@
+[document web]
+++[section] editable selectable-text
+++++[paragraph] editable
+++++++[text] name='Editable paragraph' editable
+++++[paragraph]
+++++++[text] name='Non-editable paragraph'
+++[section] editable
+++++[text] name='Fake-editable' editable
diff --git a/content/test/data/accessibility/aria/aria-editable-expected-blink.txt b/content/test/data/accessibility/aria/aria-editable-expected-blink.txt
new file mode 100644
index 0000000..82a3e8d
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-editable-expected-blink.txt
@@ -0,0 +1,11 @@
+rootWebArea
+++genericContainer editable multiline richlyEditable value='Editable paragraph<newline><newline>Non-editable paragraph' editableRoot=true
+++++paragraph editable richlyEditable
+++++++staticText editable richlyEditable name='Editable paragraph'
+++++++++inlineTextBox name='Editable paragraph'
+++++paragraph
+++++++staticText name='Non-editable paragraph'
+++++++++inlineTextBox name='Non-editable paragraph'
+++genericContainer editable richlyEditable
+++++staticText editable richlyEditable name='Fake-editable'
+++++++inlineTextBox name='Fake-editable'
diff --git a/content/test/data/accessibility/aria/aria-editable-expected-mac.txt b/content/test/data/accessibility/aria/aria-editable-expected-mac.txt
new file mode 100644
index 0000000..434d7a8
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-editable-expected-mac.txt
@@ -0,0 +1,8 @@
+AXWebArea
+++AXTextArea AXValue='Editable paragraph<newline><newline>Non-editable paragraph' AXEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph' AXHighestEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph'
+++++AXGroup AXEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph' AXHighestEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph'
+++++++AXStaticText AXValue='Editable paragraph' AXEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph' AXHighestEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph'
+++++AXGroup AXEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph' AXHighestEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph'
+++++++AXStaticText AXValue='Non-editable paragraph' AXEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph' AXHighestEditableAncestor='AXTextArea Editable paragraph<newline><newline>Non-editable paragraph'
+++AXGroup
+++++AXStaticText AXValue='Fake-editable'
diff --git a/content/test/data/accessibility/aria/aria-editable-expected-win.txt b/content/test/data/accessibility/aria/aria-editable-expected-win.txt
new file mode 100644
index 0000000..199a34b
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-editable-expected-win.txt
@@ -0,0 +1,8 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION value='Editable paragraph<newline><newline>Non-editable paragraph' FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE
+++++IA2_ROLE_PARAGRAPH IA2_STATE_EDITABLE
+++++++ROLE_SYSTEM_STATICTEXT name='Editable paragraph' IA2_STATE_EDITABLE
+++++IA2_ROLE_PARAGRAPH
+++++++ROLE_SYSTEM_STATICTEXT name='Non-editable paragraph'
+++IA2_ROLE_SECTION IA2_STATE_EDITABLE
+++++ROLE_SYSTEM_STATICTEXT name='Fake-editable' IA2_STATE_EDITABLE
diff --git a/content/test/data/accessibility/aria/aria-editable.html b/content/test/data/accessibility/aria/aria-editable.html
new file mode 100644
index 0000000..ddecba2a
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-editable.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!--
+@MAC-ALLOW:AXEditableAncestor*
+@MAC-ALLOW:AXHighestEditableAncestor*
+@WIN-ALLOW:IA2_STATE_EDITABLE
+@BLINK-ALLOW:editable*
+@BLINK-ALLOW:richlyEditable
+@AURALINUX-ALLOW:editable
+-->
+<!-- TODO(accessibility) Put aria-goog-editable on a standards track so that it
+  becomes aria-editable -->
+<div contenteditable>
+  <p>Editable paragraph</p>
+  <p aria-goog-editable="false">Non-editable paragraph</p>
+</div>
+
+<div aria-goog-editable="true">
+  Fake-editable
+</div>
diff --git a/content/test/data/frame_tree/page_with_positioned_frame_pointer-events_none.html b/content/test/data/frame_tree/page_with_positioned_frame_pointer-events_none.html
index 2e429485..c181eb6 100644
--- a/content/test/data/frame_tree/page_with_positioned_frame_pointer-events_none.html
+++ b/content/test/data/frame_tree/page_with_positioned_frame_pointer-events_none.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
 <style>
 iframe {
   position:absolute;
@@ -13,5 +14,6 @@
 <body>
 <iframe src="/cross-site/baz.com/title1.html"></iframe>
 This page contains a positioned cross-origin iframe.
+<iframe id="small" style="pointer-events: auto; width: 1px; height: 1px; top: 0px; left: 0px;" src="/cross-site/bar.com/title1.html"></iframe>
 </body>
 </html>
diff --git a/content/test/data/media/video_capture_test.html b/content/test/data/media/video_capture_test.html
index 7f5737d..b05b193c 100644
--- a/content/test/data/media/video_capture_test.html
+++ b/content/test/data/media/video_capture_test.html
@@ -1,90 +1,7 @@
 <html>
 <head>
   <script type="text/javascript" src="webrtc_test_utilities.js"></script>
-  <script type="text/javascript">
-  $ = function(id) {
-    return document.getElementById(id);
-  };
-
-  const WIDTH = 320;
-  var CONSTRAINTS = { video: { width: { exact : WIDTH } } };
-  var hasReceivedTrackEndedEvent = false;
-
-  function startVideoCaptureAndVerifySize() {
-    console.log('Calling getUserMediaAndWaitForVideoRendering.');
-    navigator.mediaDevices.getUserMedia(CONSTRAINTS)
-        .then(gotStreamCallback)
-        .catch(failedCallback);
-  }
-
-  function startVideoCaptureFromDeviceNamedVirtualDeviceAndVerifySize() {
-    console.log('Trying to find device named "Virtual Device".');
-    navigator.mediaDevices.enumerateDevices()
-        .then(function(devices) {
-            var target_device;
-            devices.forEach(function(device) {
-              if (device.kind == 'videoinput') {
-                console.log('Found videoinput device with label '
-                    + device.label);
-                if (device.label == 'Virtual Device') {
-                  target_device = device;
-                }
-              }
-            });
-            if (target_device == null) {
-              failTest('No video input device was found with label = Virtual ' +
-                       'Device');
-              return;
-            }
-            var device_specific_constraints = { video: { width: { exact :
-                WIDTH }, deviceId: { exact : target_device.deviceId } } };
-            navigator.mediaDevices.getUserMedia(device_specific_constraints)
-                .then(gotStreamCallback)
-                .catch(failedCallback);
-          });
-  }
-
-  function failedCallback(error) {
-    failTest('GetUserMedia call failed with code ' + error.code);
-  }
-
-  function gotStreamCallback(stream) {
-    var localView = $('local-view');
-    localView.srcObject = stream;
-
-    var videoTracks = stream.getVideoTracks();
-    if (videoTracks.length == 0) {
-      failTest('Did not receive any video tracks');
-    }
-    var videoTrack = videoTracks[0];
-    videoTrack.onended = function() {
-      hasReceivedTrackEndedEvent = true;
-    };
-
-    detectVideoPlaying('local-view').then(() => {
-      if (localView.videoWidth == WIDTH) {
-        reportTestSuccess();
-      } else {
-        failTest('Video has unexpected width.');
-      }
-    });
-  }
-
-  function waitForVideoToTurnBlack() {
-    detectBlackVideo('local-view').then(() => {
-      reportTestSuccess();
-    });
-  }
-
-  function verifyHasReceivedTrackEndedEvent() {
-    if (hasReceivedTrackEndedEvent) {
-      reportTestSuccess();
-    } else {
-      failTest('Did not receive ended event from track.');
-    }
-  }
-
-  </script>
+  <script type="text/javascript" src="video_capture_test.js"></script>
 </head>
 <body>
   <table border="0">
diff --git a/content/test/data/media/video_capture_test.js b/content/test/data/media/video_capture_test.js
new file mode 100644
index 0000000..96ebe0d
--- /dev/null
+++ b/content/test/data/media/video_capture_test.js
@@ -0,0 +1,105 @@
+// 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.
+
+$ = function(id) {
+  return document.getElementById(id);
+};
+
+const WIDTH = 320;
+var CONSTRAINTS = {video: {width: {exact: WIDTH}}};
+var hasReceivedTrackEndedEvent = false;
+
+function startVideoCaptureAndVerifySize() {
+  console.log('Calling getUserMediaAndWaitForVideoRendering.');
+  navigator.mediaDevices.getUserMedia(CONSTRAINTS)
+      .then(gotStreamCallback)
+      .catch(failedCallback);
+}
+
+function startVideoCaptureFromDeviceNamedVirtualDeviceAndVerifySize() {
+  console.log('Trying to find device named "Virtual Device".');
+  navigator.mediaDevices.enumerateDevices().then(function(devices) {
+    var target_device;
+    devices.forEach(function(device) {
+      if (device.kind == 'videoinput') {
+        console.log('Found videoinput device with label ' + device.label);
+        if (device.label == 'Virtual Device') {
+          target_device = device;
+        }
+      }
+    });
+    if (target_device == null) {
+      failTest(
+          'No video input device was found with label = Virtual ' +
+          'Device');
+      return;
+    }
+    var device_specific_constraints = {
+      video: {width: {exact: WIDTH}, deviceId: {exact: target_device.deviceId}}
+    };
+    navigator.mediaDevices.getUserMedia(device_specific_constraints)
+        .then(gotStreamCallback)
+        .catch(failedCallback);
+  });
+}
+
+function enumerateVideoCaptureDevicesAndVerifyCount(expected_count) {
+  console.log('Enumerating devices and verifying count.');
+  navigator.mediaDevices.enumerateDevices().then(function(devices) {
+    var actual_count = 0;
+    devices.forEach(function(device) {
+      if (device.kind == 'videoinput') {
+        console.log('Found videoinput device with label ' + device.label);
+        actual_count = actual_count + 1;
+      }
+    });
+    if (actual_count == expected_count) {
+      reportTestSuccess();
+    } else {
+      failTest(
+          'Device count ' + actual_count + ' did not match expectation of ' +
+          expected_count);
+    }
+  });
+}
+
+function failedCallback(error) {
+  failTest('GetUserMedia call failed with code ' + error.code);
+}
+
+function gotStreamCallback(stream) {
+  var localView = $('local-view');
+  localView.srcObject = stream;
+
+  var videoTracks = stream.getVideoTracks();
+  if (videoTracks.length == 0) {
+    failTest('Did not receive any video tracks');
+  }
+  var videoTrack = videoTracks[0];
+  videoTrack.onended = function() {
+    hasReceivedTrackEndedEvent = true;
+  };
+
+  detectVideoPlaying('local-view').then(() => {
+    if (localView.videoWidth == WIDTH) {
+      reportTestSuccess();
+    } else {
+      failTest('Video has unexpected width.');
+    }
+  });
+}
+
+function waitForVideoToTurnBlack() {
+  detectBlackVideo('local-view').then(() => {
+    reportTestSuccess();
+  });
+}
+
+function verifyHasReceivedTrackEndedEvent() {
+  if (hasReceivedTrackEndedEvent) {
+    reportTestSuccess();
+  } else {
+    failTest('Did not receive ended event from track.');
+  }
+}
diff --git a/device/usb/mojo/device_manager_impl.cc b/device/usb/mojo/device_manager_impl.cc
index d0b09f1e..8240e53 100644
--- a/device/usb/mojo/device_manager_impl.cc
+++ b/device/usb/mojo/device_manager_impl.cc
@@ -25,23 +25,20 @@
 namespace usb {
 
 // static
-std::unique_ptr<DeviceManagerImpl> DeviceManagerImpl::Create(
+void DeviceManagerImpl::Create(
     mojom::UsbDeviceManagerRequest request) {
   DCHECK(DeviceClient::Get());
   UsbService* service = DeviceClient::Get()->GetUsbService();
   if (!service)
-    return nullptr;
+    return;
 
-  auto* device_manager = new DeviceManagerImpl(service);
-  device_manager->binding_.Bind(std::move(request));
-  return base::WrapUnique(device_manager);
+  auto* device_manager_impl = new DeviceManagerImpl(service);
+  device_manager_impl->binding_ = mojo::MakeStrongBinding(
+      base::WrapUnique(device_manager_impl), std::move(request));
 }
 
 DeviceManagerImpl::DeviceManagerImpl(UsbService* usb_service)
-    : usb_service_(usb_service),
-      observer_(this),
-      binding_(this),
-      weak_factory_(this) {
+    : usb_service_(usb_service), observer_(this), weak_factory_(this) {
   // This object owns itself and will be destroyed if the message pipe it is
   // bound to is closed, the message loop is destructed, or the UsbService is
   // shut down.
@@ -101,8 +98,7 @@
 }
 
 void DeviceManagerImpl::WillDestroyUsbService() {
-  binding_.Close();
-  client_.reset();
+  binding_->Close();
 }
 
 }  // namespace usb
diff --git a/device/usb/mojo/device_manager_impl.h b/device/usb/mojo/device_manager_impl.h
index 782386a3..43224dd 100644
--- a/device/usb/mojo/device_manager_impl.h
+++ b/device/usb/mojo/device_manager_impl.h
@@ -18,7 +18,7 @@
 #include "base/scoped_observer.h"
 #include "device/usb/public/mojom/device_manager.mojom.h"
 #include "device/usb/usb_service.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace device {
 
@@ -31,8 +31,7 @@
 class DeviceManagerImpl : public mojom::UsbDeviceManager,
                           public UsbService::Observer {
  public:
-  static std::unique_ptr<DeviceManagerImpl> Create(
-      mojom::UsbDeviceManagerRequest request);
+  static void Create(mojom::UsbDeviceManagerRequest request);
 
   ~DeviceManagerImpl() override;
 
@@ -59,10 +58,10 @@
 
   void MaybeRunDeviceChangesCallback();
 
+  mojo::StrongBindingPtr<mojom::UsbDeviceManager> binding_;
+
   UsbService* usb_service_;
   ScopedObserver<UsbService, UsbService::Observer> observer_;
-
-  mojo::Binding<mojom::UsbDeviceManager> binding_;
   mojom::UsbDeviceManagerClientPtr client_;
 
   base::WeakPtrFactory<DeviceManagerImpl> weak_factory_;
diff --git a/device/usb/mojo/device_manager_impl_unittest.cc b/device/usb/mojo/device_manager_impl_unittest.cc
index ab88d0e..d81db9d 100644
--- a/device/usb/mojo/device_manager_impl_unittest.cc
+++ b/device/usb/mojo/device_manager_impl_unittest.cc
@@ -53,22 +53,15 @@
   ~USBDeviceManagerImplTest() override = default;
 
  protected:
-  void TearDown() override {
-    // Clean up the devcie manager for next test case.
-    device_manager_instance_.reset();
-  }
-
   UsbDeviceManagerPtr ConnectToDeviceManager() {
     UsbDeviceManagerPtr device_manager;
-    device_manager_instance_ =
-        DeviceManagerImpl::Create(mojo::MakeRequest(&device_manager));
+    DeviceManagerImpl::Create(mojo::MakeRequest(&device_manager));
     return device_manager;
   }
 
   MockDeviceClient device_client_;
 
  private:
-  std::unique_ptr<DeviceManagerImpl> device_manager_instance_;
   std::unique_ptr<base::MessageLoop> message_loop_;
 };
 
diff --git a/device/vr/openvr/openvr_render_loop.cc b/device/vr/openvr/openvr_render_loop.cc
index 2fae5df..c0c63b2c 100644
--- a/device/vr/openvr/openvr_render_loop.cc
+++ b/device/vr/openvr/openvr_render_loop.cc
@@ -366,6 +366,19 @@
     }
   }
 
+  // Yield here to let the event queue process pending mojo messages,
+  // specifically the next gamepad callback request that's likely to
+  // have been sent during WaitGetPoses.
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&OpenVRRenderLoop::GetControllerDataAndSendFrameData,
+                     base::Unretained(this), std::move(callback),
+                     std::move(frame_data)));
+}
+
+void OpenVRRenderLoop::GetControllerDataAndSendFrameData(
+    XRFrameDataProvider::GetFrameDataCallback callback,
+    mojom::XRFrameDataPtr frame_data) {
   // Update gamepad controllers.
   UpdateControllerState();
 
diff --git a/device/vr/openvr/openvr_render_loop.h b/device/vr/openvr/openvr_render_loop.h
index bf0715d..06eb7eb 100644
--- a/device/vr/openvr/openvr_render_loop.h
+++ b/device/vr/openvr/openvr_render_loop.h
@@ -58,6 +58,9 @@
                          const gfx::Size& source_size) override;
   void GetFrameData(
       XRFrameDataProvider::GetFrameDataCallback callback) override;
+  void GetControllerDataAndSendFrameData(
+      XRFrameDataProvider::GetFrameDataCallback callback,
+      mojom::XRFrameDataPtr frame_data);
 
   void RequestGamepadProvider(mojom::IsolatedXRGamepadProviderRequest request);
 
diff --git a/docs/layout_tests_linux.md b/docs/layout_tests_linux.md
index 33a99b7..896edf95 100644
--- a/docs/layout_tests_linux.md
+++ b/docs/layout_tests_linux.md
@@ -6,7 +6,7 @@
         "LayoutTests", you may need to comment it out and sync.
     *   You can run a subset of the tests by passing in a path relative to
         `src/third_party/WebKit/LayoutTests/`.  For example,
-        `run_layout_tests.py fast` will only run the tests under
+        `third_party/blink/tools/run_web_tests.py fast` will only run the tests under
         `src/third_party/WebKit/LayoutTests/fast/`.
 1.  When the tests finish, any unexpected results should be displayed.
 
@@ -65,7 +65,7 @@
 
 There are two ways:
 
-1.  Run `content_shell` directly rather than using `run_layout_tests.py`. You
+1.  Run `content_shell` directly rather than using `run_web_tests.py`. You
     will need to pass some options:
     *   `--no-timeout` to give you plenty of time to debug
     *   the fully qualified path of the layout test (rather than relative to
@@ -86,7 +86,7 @@
 
 1.  Install Xephyr (`sudo apt-get install xserver-xephyr`)
 1.  Start Xephyr as display 4: `Xephyr :4 -screen 1024x768x24`
-1.  Run the layout tests in the Xephyr: `DISPLAY=:4 run_layout_tests.py`
+1.  Run the layout tests in the Xephyr: `DISPLAY=:4 run_web_tests.py`
 
 Xephyr supports debugging repainting. See the
 [Xephyr README](http://cgit.freedesktop.org/xorg/xserver/tree/hw/kdrive/ephyr/README)
@@ -99,7 +99,7 @@
 installed).
 
 1.  Start Xvfb as display 4: `Xvfb :4 -screen 0 1024x768x24`
-1.  Run the layout tests in the Xvfb: `DISPLAY=:4 run_layout_tests.py`
+1.  Run the layout tests in the Xvfb: `DISPLAY=:4 run_web_tests.py`
 
 ## Tiling Window managers
 
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index e9d949f..4ca8b3b5 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -1,6 +1,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromecast_build.gni")
 import("//build/config/jumbo.gni")
 import("//extensions/buildflags/buildflags.gni")
 import("//testing/test.gni")
@@ -38,6 +39,7 @@
 
 grit("extensions_renderer_resources") {
   source = "renderer/resources/extensions_renderer_resources.grd"
+  defines = [ "is_chromecast=$is_chromecast" ]
   outputs = [
     "grit/extensions_renderer_resources.h",
     "extensions_renderer_resources.pak",
diff --git a/extensions/browser/bad_message.h b/extensions/browser/bad_message.h
index bf7fe1f..d93599e 100644
--- a/extensions/browser/bad_message.h
+++ b/extensions/browser/bad_message.h
@@ -35,6 +35,7 @@
   EFD_BAD_MESSAGE_WORKER = 9,
   WVG_PARTITION_ID_NOT_UTF8 = 10,
   ESWMF_BAD_EVENT_ACK = 11,
+  MHVG_INVALID_PLUGIN_FRAME_ID = 12,
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. ExtensionHost becomes EH) plus a unique description of the
   // reason. After making changes, you MUST update histograms.xml by running:
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 771fae4..5c08120 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1335,6 +1335,7 @@
   FILEMANAGERPRIVATEINTERNAL_SHAREPATHWITHCROSTINICONTAINER = 1272,
   AUTOTESTPRIVATE_SETCROSTINIENABLED = 1273,
   AUTOTESTPRIVATE_GETHISTOGRAM = 1274,
+  TABCAPTURE_GETMEDIASTREAMID = 1275,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
index 21ecbf1..172e6de 100644
--- a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
+++ b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/mime_handler_view_mode.h"
 #include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/bad_message.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h"
@@ -38,6 +39,40 @@
 
 namespace extensions {
 
+namespace {
+
+// TODO(ekaramad): Remove this once MimeHandlerViewGuest has fully migrated to
+// using cross-process-frames.
+// Returns true if |child_routing_id| corresponds to a frame which is a direct
+// child of |parent_rfh|.
+bool AreRoutingIDsConsistent(content::RenderFrameHost* parent_rfh,
+                             int32_t child_routing_id) {
+  const bool uses_cross_process_frame =
+      content::MimeHandlerViewMode::UsesCrossProcessFrame();
+  const bool is_child_routing_id_none = (child_routing_id == MSG_ROUTING_NONE);
+
+  // For cross-process-frame MimeHandlerView, |child_routing_id| cannot be none.
+  bool should_shutdown_process =
+      (is_child_routing_id_none == uses_cross_process_frame);
+
+  if (!should_shutdown_process && uses_cross_process_frame) {
+    // The |child_routing_id| is the routing ID of either a RenderFrame or a
+    // proxy in the |parent_rfh|. Therefore, to get the associated RFH we need
+    // to go through the FTN first.
+    int32_t child_ftn_id =
+        content::RenderFrameHost::GetFrameTreeNodeIdForRoutingId(
+            parent_rfh->GetProcess()->GetID(), child_routing_id);
+    // The |child_rfh| is not really used; it is retrieved to verify whether or
+    // not what the renderer process says makes any sense.
+    auto* child_rfh = content::WebContents::FromRenderFrameHost(parent_rfh)
+                          ->UnsafeFindFrameByFrameTreeNodeId(child_ftn_id);
+    should_shutdown_process =
+        child_rfh && (child_rfh->GetParent() != parent_rfh);
+  }
+  return !should_shutdown_process;
+}
+
+}  // namespace
 const uint32_t ExtensionsGuestViewMessageFilter::kFilteredMessageClasses[] = {
     GuestViewMsgStart, ExtensionsGuestViewMsgStart};
 
@@ -128,8 +163,7 @@
     int32_t plugin_frame_routing_id,
     bool is_full_page_plugin) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(content::MimeHandlerViewMode::UsesCrossProcessFrame() ||
-         plugin_frame_routing_id == MSG_ROUTING_NONE);
+
   auto* manager = GetOrCreateGuestViewManager();
 
   auto* rfh = RenderFrameHost::FromID(render_process_id_, render_frame_id);
@@ -137,6 +171,12 @@
   if (!embedder_web_contents)
     return;
 
+  if (!AreRoutingIDsConsistent(rfh, plugin_frame_routing_id)) {
+    bad_message::ReceivedBadMessage(rfh->GetProcess(),
+                                    bad_message::MHVG_INVALID_PLUGIN_FRAME_ID);
+    return;
+  }
+
   GuestViewManager::WebContentsCreatedCallback callback = base::BindOnce(
       &ExtensionsGuestViewMessageFilter::MimeHandlerViewGuestCreatedCallback,
       this, element_instance_id, render_process_id_, render_frame_id,
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd
index b65d821..8fbb362 100644
--- a/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -85,13 +85,15 @@
       <include name="IDR_STORAGE_AREA_JS" file="storage_area.js" type="BINDATA" />
 
       <!-- Platform app support. -->
-      <include name="IDR_PLATFORM_APP_CSS" file="platform_app.css" type="BINDATA" />
       <include name="IDR_PLATFORM_APP_JS" file="platform_app.js" type="BINDATA" />
 
       <!-- Extension styles. -->
       <include name="IDR_EXTENSION_FONTS_CSS" file="extension_fonts.css" type="BINDATA"/>
     </includes>
     <structures>
+      <!-- Platform app support. -->
+      <structure name="IDR_PLATFORM_APP_CSS" file="platform_app.css" type="chrome_html" preprocess="true" />
+
       <!-- Extension styles. -->
       <structure name="IDR_EXTENSION_CSS" file="extension.css" type="chrome_html" flattenhtml="true" />
     </structures>
diff --git a/extensions/renderer/resources/platform_app.css b/extensions/renderer/resources/platform_app.css
index fa81131..4c2b6b40 100644
--- a/extensions/renderer/resources/platform_app.css
+++ b/extensions/renderer/resources/platform_app.css
@@ -8,12 +8,14 @@
 
 @namespace "http://www.w3.org/1999/xhtml";
 
+<if expr="not is_chromecast">
 body {
   -webkit-user-select: none;
   cursor: default;
   font-family: $FONTFAMILY;
   font-size: $FONTSIZE;
 }
+</if>
 
 webview, appview {
   display: inline-block;
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index f295efb..e379c9d2 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -893,6 +893,7 @@
   fuchsia_package("headless_shell_pkg") {
     binary = ":headless_shell"
     package_name_override = "headless_shell"
+    sandbox_policy = "//build/config/fuchsia/testing_sandbox_policy"
   }
 
   fuchsia_package_runner("headless_shell_fuchsia") {
diff --git a/ios/chrome/app/resources/Info.plist b/ios/chrome/app/resources/Info.plist
index 4646d6e..aae2d8c 100644
--- a/ios/chrome/app/resources/Info.plist
+++ b/ios/chrome/app/resources/Info.plist
@@ -72,6 +72,8 @@
 	<string>0.0.0</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
+	<key>LSSupportsOpeningDocumentsInPlace</key>
+	<true/>
 	<key>NSAppTransportSecurity</key>
 	<dict>
 		<key>NSAllowsArbitraryLoads</key>
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 549c2e02..9a5ab24 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -134,6 +134,7 @@
     "//ios/chrome/browser/ui/main:feature_flags",
     "//ios/chrome/browser/ui/omnibox",
     "//ios/chrome/browser/ui/toolbar/public:feature_flags",
+    "//ios/chrome/browser/ui/toolbar_container:feature_flags",
     "//ios/chrome/browser/web:feature_flags",
     "//ios/chrome/common",
     "//ios/components/io_thread",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index d37514af..1f22cd5 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -53,6 +53,7 @@
 #import "ios/chrome/browser/ui/history/features.h"
 #include "ios/chrome/browser/ui/main/main_feature_flags.h"
 #import "ios/chrome/browser/ui/toolbar/public/features.h"
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/web/features.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -383,6 +384,14 @@
     {"out-of-web-fullscreen", flag_descriptions::kOutOfWebFullscreenName,
      flag_descriptions::kOutOfWebFullscreenDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(web::features::kOutOfWebFullscreen)},
+    {"autofill-manual-fallback-phase-two",
+     flag_descriptions::kAutofillManualFallbackPhaseTwoName,
+     flag_descriptions::kAutofillManualFallbackPhaseTwoDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(autofill::features::kAutofillManualFallbackPhaseTwo)},
+    {"toolbar-container", flag_descriptions::kToolbarContainerName,
+     flag_descriptions::kToolbarContainerDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(toolbar_container::kToolbarContainerEnabled)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index 3d587a9..7c9cb4f 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -103,11 +103,16 @@
     "Delay between the different fields of a form being autofilled. In "
     "milliseconds.";
 
-const char kAutofillManualFallbackName[] = "Enable autofill manual fallback";
+const char kAutofillManualFallbackName[] = "Enable Autofill Manual Fallback";
 const char kAutofillManualFallbackDescription[] =
     "When enabled, it shows the autofill UI with manual fallback when filling "
     "forms.";
 
+const char kAutofillManualFallbackPhaseTwoName[] = "Enable Addresses and Cards";
+const char kAutofillManualFallbackPhaseTwoDescription[] =
+    "When enabled, it shows the credit cards and addresses buttons in manual "
+    "fallback.";
+
 const char kAutofillShowAllSuggestionsOnPrefilledFormsName[] =
     "Enable showing all suggestions when focusing prefilled field";
 const char kAutofillShowAllSuggestionsOnPrefilledFormsDescription[] =
@@ -246,6 +251,11 @@
     "BVC is visible, the tab switcher will remain in the VC hierarchy "
     "underneath it.";
 
+const char kToolbarContainerName[] = "Use Toolbar Containers";
+const char kToolbarContainerDescription[] =
+    "When enabled, the toolbars and their fullscreen animations will be "
+    "managed by the toolbar container coordinator rather than BVC.";
+
 const char kUIRefreshLocationBarName[] = "UI Refresh Location Bar";
 const char kUIRefreshLocationBarDescription[] =
     "When enabled, the UI Refresh location bar with a custom steady-state will "
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index a7bade9..c945991 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -83,6 +83,10 @@
 extern const char kAutofillManualFallbackName[];
 extern const char kAutofillManualFallbackDescription[];
 
+// Title and description for the flag to control if manual fallback is enabled.
+extern const char kAutofillManualFallbackPhaseTwoName[];
+extern const char kAutofillManualFallbackPhaseTwoDescription[];
+
 // Title and description for the flag to control if prefilled value filter
 // profiles.
 extern const char kAutofillShowAllSuggestionsOnPrefilledFormsName[];
@@ -204,6 +208,11 @@
 extern const char kTabSwitcherPresentsBVCName[];
 extern const char kTabSwitcherPresentsBVCDescription[];
 
+// Title and description for the flag to enable the toolbar container
+// implementation.
+extern const char kToolbarContainerName[];
+extern const char kToolbarContainerDescription[];
+
 // Title and description for the flag to enable the UI Refresh location bar.
 extern const char kUIRefreshLocationBarName[];
 extern const char kUIRefreshLocationBarDescription[];
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h
index 182e40c..988b4f2 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -38,7 +38,6 @@
   ~IOSChromeSyncClient() override;
 
   // SyncClient implementation.
-  void Initialize() override;
   syncer::SyncService* GetSyncService() override;
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 421a5a4..263ef613 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -156,13 +156,7 @@
 IOSChromeSyncClient::IOSChromeSyncClient(ios::ChromeBrowserState* browser_state)
     : browser_state_(browser_state),
       sync_sessions_client_(
-          std::make_unique<SyncSessionsClientImpl>(browser_state)) {}
-
-IOSChromeSyncClient::~IOSChromeSyncClient() {}
-
-void IOSChromeSyncClient::Initialize() {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-
+          std::make_unique<SyncSessionsClientImpl>(browser_state)) {
   profile_web_data_service_ =
       ios::WebDataServiceFactory::GetAutofillWebDataForBrowserState(
           browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
@@ -191,6 +185,8 @@
   }
 }
 
+IOSChromeSyncClient::~IOSChromeSyncClient() {}
+
 syncer::SyncService* IOSChromeSyncClient::GetSyncService() {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
   return ProfileSyncServiceFactory::GetForBrowserState(browser_state_);
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index 3a4bc200..ae8e5ce 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -146,8 +146,6 @@
   init_params.channel = ::GetChannel();
 
   auto pss = std::make_unique<ProfileSyncService>(std::move(init_params));
-
-  // Will also initialize the sync client.
   pss->Initialize();
   return pss;
 }
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 21753e8..134f070 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -410,6 +410,7 @@
     "//ios/chrome/browser/ui/toolbar/legacy",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/public:feature_flags",
+    "//ios/chrome/browser/ui/toolbar_container:feature_flags",
     "//ios/chrome/browser/ui/tools_menu",
     "//ios/chrome/browser/ui/tools_menu:configuration",
     "//ios/chrome/browser/ui/tools_menu/public",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 9d0000445..fe904589 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -233,7 +233,6 @@
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
 #import "ios/chrome/browser/web/error_page_content.h"
-#import "ios/chrome/browser/web/image_fetch_tab_helper.h"
 #import "ios/chrome/browser/web/load_timing_tab_helper.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #include "ios/chrome/browser/web/print_tab_helper.h"
@@ -548,6 +547,9 @@
   // when displaying voice search results.
   UIView<VoiceSearchBar>* _voiceSearchBar;
 
+  // The image fetcher used to save images and perform image-based searches.
+  std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher;
+
   // Cached pointer to the bookmarks model.
   bookmarks::BookmarkModel* _bookmarkModel;  // weak
 
@@ -2135,6 +2137,8 @@
   for (NSUInteger index = 0; index < count; ++index)
     [self installDelegatesForTab:[_model tabAtIndex:index]];
 
+  _imageFetcher = std::make_unique<image_fetcher::IOSImageDataFetcherWrapper>(
+      _browserState->GetSharedURLLoaderFactory());
   self.imageSaver = [[ImageSaver alloc] initWithBaseViewController:self];
   self.imageCopier = [[ImageCopier alloc] initWithBaseViewController:self];
 
@@ -3700,9 +3704,7 @@
     title = l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_SAVEIMAGE);
     action = ^{
       Record(ACTION_SAVE_IMAGE, isImage, isLink);
-      [weakSelf.imageSaver saveImageAtURL:imageUrl
-                                 referrer:referrer
-                                 webState:weakSelf.currentWebState];
+      [weakSelf saveImageAtURL:imageUrl referrer:referrer];
     };
     [_contextMenuCoordinator addItemWithTitle:title action:action];
     // Copy Image.
@@ -3711,6 +3713,7 @@
           l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_COPYIMAGE);
       action = ^{
         Record(ACTION_COPY_IMAGE, isImage, isLink);
+        DCHECK(imageUrl.is_valid());
         [weakSelf.imageCopier copyImageAtURL:imageUrl
                                     referrer:referrer
                                     webState:weakSelf.currentWebState];
@@ -3755,12 +3758,7 @@
                                       defaultURL->short_name());
       action = ^{
         Record(ACTION_SEARCH_BY_IMAGE, isImage, isLink);
-        ImageFetchTabHelper* image_fetcher =
-            ImageFetchTabHelper::FromWebState(self.currentWebState);
-        DCHECK(image_fetcher);
-        image_fetcher->GetImageData(imageUrl, referrer, ^(NSData* data) {
-          [weakSelf searchByImageData:data atURL:imageUrl];
-        });
+        [weakSelf searchByImageAtURL:imageUrl referrer:referrer];
       };
       [_contextMenuCoordinator addItemWithTitle:title action:action];
     }
@@ -3812,6 +3810,25 @@
   }
 }
 
+// Performs a search with the image at the given url. The referrer is used to
+// download the image.
+- (void)searchByImageAtURL:(const GURL&)url
+                  referrer:(const web::Referrer)referrer {
+  DCHECK(url.is_valid());
+  __weak BrowserViewController* weakSelf = self;
+  const GURL image_source_url = url;
+  image_fetcher::ImageDataFetcherBlock callback =
+      ^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
+        DCHECK(data);
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [weakSelf searchByImageData:data atURL:image_source_url];
+        });
+      };
+  _imageFetcher->FetchImageDataWebpDecoded(
+      url, callback, web::ReferrerHeaderValueForNavigation(url, referrer),
+      web::PolicyForNavigation(url, referrer));
+}
+
 // Performs a search using |data| and |imageURL| as inputs.
 - (void)searchByImageData:(NSData*)data atURL:(const GURL&)imageURL {
   NSData* imageData = data;
@@ -3855,6 +3872,21 @@
                    transition:ui::PAGE_TRANSITION_TYPED];
 }
 
+// Saves the image at the given URL on the system's album.  The referrer is used
+// to download the image.
+- (void)saveImageAtURL:(const GURL&)url
+              referrer:(const web::Referrer&)referrer {
+  DCHECK(url.is_valid());
+
+  image_fetcher::ImageDataFetcherBlock callback =
+      ^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
+        [self.imageSaver saveImageData:data withMetadata:metadata];
+      };
+  _imageFetcher->FetchImageDataWebpDecoded(
+      url, callback, web::ReferrerHeaderValueForNavigation(url, referrer),
+      web::PolicyForNavigation(url, referrer));
+}
+
 - (BOOL)isTabWithIDCurrent:(NSString*)sessionID {
   return self.visible && [sessionID isEqualToString:[_model currentTab].tabId];
 }
@@ -5052,6 +5084,12 @@
                    completion:nil];
 }
 
+- (void)focusFakebox {
+  id nativeController = [self nativeControllerForTab:[_model currentTab]];
+  DCHECK([nativeController isKindOfClass:[NewTabPageController class]]);
+  [nativeController focusFakebox];
+}
+
 #pragma mark - ToolbarOwner (Public)
 
 - (CGRect)toolbarFrame {
@@ -5424,7 +5462,7 @@
   // Exit fullscreen if needed.
   FullscreenControllerFactory::GetInstance()
       ->GetForBrowserState(_browserState)
-      ->ResetModel();
+      ->ExitFullscreen();
   const CGFloat kAnimatedViewSize = 50;
   BackgroundTabAnimationView* animatedView = [[BackgroundTabAnimationView alloc]
       initWithFrame:CGRectMake(0, 0, kAnimatedViewSize, kAnimatedViewSize)];
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 8deedff2..b7da21e 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -122,6 +122,10 @@
 // Shows the consent bump if it is required.
 - (void)showConsentBumpIfNeeded;
 
+// Animates the NTP fakebox to the focused position and focuses the real
+// omnibox.
+- (void)focusFakebox;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
index c9b4536d..548291b 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
@@ -69,6 +69,10 @@
 // Return the toolbar view;
 - (UIView*)toolBarView;
 
+// Animates the NTP fakebox to the focused position and focuses the real
+// omnibox.
+- (void)focusFakebox;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_HEADER_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index f45a384..9cecd82e 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -333,7 +333,7 @@
   self.searchHintLabel.isAccessibilityElement = NO;
   self.accessibilityButton = [[UIButton alloc] init];
   [self.accessibilityButton addTarget:self
-                               action:@selector(fakeOmniboxTapped)
+                               action:@selector(focusFakebox)
                      forControlEvents:UIControlEventTouchUpInside];
   // Because the visual fakebox background is implemented within
   // ContentSuggestionsHeaderView, KVO the highlight events of
@@ -381,7 +381,7 @@
       l10n_util::GetNSString(IDS_ACCNAME_LOCATION);
   [self.headerView addToolbarView:fakeTapButton];
   [fakeTapButton addTarget:self
-                    action:@selector(fakeOmniboxTapped)
+                    action:@selector(focusFakebox)
           forControlEvents:UIControlEventTouchUpInside];
 }
 
@@ -416,11 +416,11 @@
   [self.dispatcher preloadVoiceSearch];
 }
 
-- (void)fakeOmniboxTapped {
+- (void)focusFakebox {
   if (IsUIRefreshPhase1Enabled()) {
     [self shiftTilesUp];
   } else {
-    [self.dispatcher focusFakebox];
+    [self.dispatcher fakeboxFocused];
   }
 }
 
@@ -492,7 +492,7 @@
 - (void)shiftTilesUp {
   void (^completionBlock)() = ^{
     if (IsUIRefreshPhase1Enabled()) {
-      [self.dispatcher focusFakebox];
+      [self.dispatcher fakeboxFocused];
     }
     if ((IsUIRefreshPhase1Enabled() && IsSplitToolbarMode()) ||
         (!IsUIRefreshPhase1Enabled() &&
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
index 9c7caa7..c796a4b 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
@@ -57,9 +57,13 @@
   // 1.0 denotes that the toolbar should be completely visible.
   virtual CGFloat GetProgress() const = 0;
 
-  // Resets the model such that progress is reset to 1.0, animating in the
-  // headers and footers.
-  virtual void ResetModel() = 0;
+  // Enters fullscreen mode, animating away toolbars and resetting the progress
+  // to 0.0.  Calling this function while fullscreen is disabled has no effect.
+  virtual void EnterFullscreen() = 0;
+
+  // Exits fullscreen mode, animating in toolbars and resetting the progress to
+  // 1.0.
+  virtual void ExitFullscreen() = 0;
 
  private:
 
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.h b/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.h
index 2a7148d..73752124 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.h
@@ -5,14 +5,12 @@
 #ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_IMPL_H_
 #define IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_IMPL_H_
 
-#include <memory>
-
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h"
 
 @class ChromeBroadcastOberverBridge;
-class FullscreenMediator;
-class FullscreenModel;
-class FullscreenWebStateListObserver;
 @class FullscreenSystemNotificationObserver;
 
 // Implementation of FullscreenController.
@@ -30,7 +28,8 @@
   void IncrementDisabledCounter() override;
   void DecrementDisabledCounter() override;
   CGFloat GetProgress() const override;
-  void ResetModel() override;
+  void EnterFullscreen() override;
+  void ExitFullscreen() override;
 
  private:
   // KeyedService:
@@ -38,19 +37,16 @@
 
   // The broadcaster that drives the model.
   __strong ChromeBroadcaster* broadcaster_ = nil;
-  // The WebStateList for the Browser whose fullscreen is managed by this
-  // object.
-  WebStateList* web_state_list_ = nullptr;
   // The model used to calculate fullscreen state.
-  std::unique_ptr<FullscreenModel> model_;
+  FullscreenModel model_;
   // Object that manages sending signals to FullscreenControllerImplObservers.
-  std::unique_ptr<FullscreenMediator> mediator_;
+  FullscreenMediator mediator_;
+  // A WebStateListObserver that updates |model_| for WebStateList changes.
+  FullscreenWebStateListObserver web_state_list_observer_;
   // The bridge used to forward brodcasted UI to |model_|.
   __strong ChromeBroadcastOberverBridge* bridge_ = nil;
   // A helper object that listens for system notifications.
   __strong FullscreenSystemNotificationObserver* notification_observer_ = nil;
-  // A WebStateListObserver that updates |model_| for WebStateList changes.
-  std::unique_ptr<FullscreenWebStateListObserver> web_state_list_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(FullscreenControllerImpl);
 };
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.mm
index 334f97c..854af5d 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller_impl.mm
@@ -6,10 +6,7 @@
 
 #import "ios/chrome/browser/ui/broadcaster/chrome_broadcast_observer_bridge.h"
 #import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_system_notification_observer.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/fullscreen_provider.h"
 
@@ -20,13 +17,12 @@
 FullscreenControllerImpl::FullscreenControllerImpl()
     : FullscreenController(),
       broadcaster_([[ChromeBroadcaster alloc] init]),
-      model_(std::make_unique<FullscreenModel>()),
-      mediator_(std::make_unique<FullscreenMediator>(this, model_.get())),
-      bridge_(
-          [[ChromeBroadcastOberverBridge alloc] initWithObserver:model_.get()]),
+      mediator_(this, &model_),
+      web_state_list_observer_(this, &model_, &mediator_),
+      bridge_([[ChromeBroadcastOberverBridge alloc] initWithObserver:&model_]),
       notification_observer_([[FullscreenSystemNotificationObserver alloc]
           initWithController:this
-                    mediator:mediator_.get()]) {
+                    mediator:&mediator_]) {
   DCHECK(broadcaster_);
   [broadcaster_ addObserver:bridge_
                 forSelector:@selector(broadcastScrollViewSize:)];
@@ -60,53 +56,47 @@
 }
 
 void FullscreenControllerImpl::SetWebStateList(WebStateList* web_state_list) {
-  if (web_state_list_ == web_state_list)
-    return;
-  if (web_state_list_observer_)
-    web_state_list_observer_->Disconnect();
-  web_state_list_ = web_state_list;
-  web_state_list_observer_ =
-      web_state_list_
-          ? std::make_unique<FullscreenWebStateListObserver>(
-                this, model_.get(), web_state_list_, mediator_.get())
-          : nullptr;
+  web_state_list_observer_.SetWebStateList(web_state_list);
 }
 
 void FullscreenControllerImpl::AddObserver(
     FullscreenControllerObserver* observer) {
-  mediator_->AddObserver(observer);
+  mediator_.AddObserver(observer);
 }
 
 void FullscreenControllerImpl::RemoveObserver(
     FullscreenControllerObserver* observer) {
-  mediator_->RemoveObserver(observer);
+  mediator_.RemoveObserver(observer);
 }
 
 bool FullscreenControllerImpl::IsEnabled() const {
-  return model_->enabled();
+  return model_.enabled();
 }
 
 void FullscreenControllerImpl::IncrementDisabledCounter() {
-  model_->IncrementDisabledCounter();
+  model_.IncrementDisabledCounter();
 }
 
 void FullscreenControllerImpl::DecrementDisabledCounter() {
-  model_->DecrementDisabledCounter();
+  model_.DecrementDisabledCounter();
 }
 
 CGFloat FullscreenControllerImpl::GetProgress() const {
-  return model_->progress();
+  return model_.progress();
 }
 
-void FullscreenControllerImpl::ResetModel() {
-  mediator_->AnimateModelReset();
+void FullscreenControllerImpl::EnterFullscreen() {
+  mediator_.EnterFullscreen();
+}
+
+void FullscreenControllerImpl::ExitFullscreen() {
+  mediator_.ExitFullscreen();
 }
 
 void FullscreenControllerImpl::Shutdown() {
-  mediator_->Disconnect();
+  mediator_.Disconnect();
+  web_state_list_observer_.Disconnect();
   [notification_observer_ disconnect];
-  if (web_state_list_observer_)
-    web_state_list_observer_->Disconnect();
   [broadcaster_ removeObserver:bridge_
                    forSelector:@selector(broadcastScrollViewSize:)];
   [broadcaster_ removeObserver:bridge_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
index 3852866..4f731c2 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
@@ -43,14 +43,9 @@
   // Sets the WebState which view is to be resized.
   void SetWebState(web::WebState* webState);
 
-  // Instructs the mediator that a scroll-to-top animation has been triggered.
-  void ScrollToTop();
-
-  // Instructs the mediator that the app will be foregrounded.
-  void WillEnterForeground();
-
-  // Resets the model while animating changes.
-  void AnimateModelReset();
+  // Enters or exits fullscreen, animating the changes.
+  void EnterFullscreen();
+  void ExitFullscreen();
 
   // Instructs the mediator to stop observing its model.
   void Disconnect();
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
index c2442b3..26cd535b7 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
@@ -36,15 +36,12 @@
   resizer_.webState = webState;
 }
 
-void FullscreenMediator::ScrollToTop() {
-  AnimateWithStyle(FullscreenAnimatorStyle::EXIT_FULLSCREEN);
+void FullscreenMediator::EnterFullscreen() {
+  if (model_->enabled())
+    AnimateWithStyle(FullscreenAnimatorStyle::ENTER_FULLSCREEN);
 }
 
-void FullscreenMediator::WillEnterForeground() {
-  AnimateWithStyle(FullscreenAnimatorStyle::EXIT_FULLSCREEN);
-}
-
-void FullscreenMediator::AnimateModelReset() {
+void FullscreenMediator::ExitFullscreen() {
   // Instruct the model to ignore the remainder of the current scroll when
   // starting this animator.  This prevents the toolbar from immediately being
   // hidden if AnimateModelReset() is called while a scroll view is
@@ -95,7 +92,7 @@
   if (model_->is_scrolled_to_bottom() &&
       AreCGFloatsEqual(model_->progress(), 0.0) &&
       model_->can_collapse_toolbar()) {
-    AnimateModelReset();
+    ExitFullscreen();
   }
 }
 
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_system_notification_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_system_notification_observer.mm
index f1f4312..87c5557ec 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_system_notification_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_system_notification_observer.mm
@@ -116,7 +116,7 @@
 }
 
 - (void)applicationWillEnterForeground {
-  self.mediator->WillEnterForeground();
+  self.mediator->ExitFullscreen();
 }
 
 @end
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h
index 368a7466..f2b33ea 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h
@@ -24,10 +24,12 @@
   // navigation events that require the toolbar to be visible.
   FullscreenWebStateListObserver(FullscreenController* controller,
                                  FullscreenModel* model,
-                                 WebStateList* web_state_list,
                                  FullscreenMediator* mediator);
   ~FullscreenWebStateListObserver() override;
 
+  // Starts observing |web_state_list|.
+  void SetWebStateList(WebStateList* web_state_list);
+
   // Stops observing the the WebStateList.
   void Disconnect();
 
@@ -58,11 +60,11 @@
   bool HasWebStateBeenActivated(web::WebState* web_state);
 
   // The controller passed on construction.
-  FullscreenController* controller_;
+  FullscreenController* controller_ = nullptr;
   // The model passed on construction.
-  FullscreenModel* model_;
+  FullscreenModel* model_ = nullptr;
   // The WebStateList passed on construction.
-  WebStateList* web_state_list_;
+  WebStateList* web_state_list_ = nullptr;
   // The observer for the active WebState.
   FullscreenWebStateObserver web_state_observer_;
   // The WebStates that have been activated in |web_state_list_|.
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
index 67fcf6b..c9408d4 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
@@ -18,17 +18,12 @@
 FullscreenWebStateListObserver::FullscreenWebStateListObserver(
     FullscreenController* controller,
     FullscreenModel* model,
-    WebStateList* web_state_list,
     FullscreenMediator* mediator)
     : controller_(controller),
       model_(model),
-      web_state_list_(web_state_list),
       web_state_observer_(controller, model, mediator) {
   DCHECK(controller_);
   DCHECK(model_);
-  DCHECK(web_state_list_);
-  web_state_list_->AddObserver(this);
-  web_state_observer_.SetWebState(web_state_list_->GetActiveWebState());
 }
 
 FullscreenWebStateListObserver::~FullscreenWebStateListObserver() {
@@ -36,10 +31,23 @@
   DCHECK(!web_state_list_);
 }
 
+void FullscreenWebStateListObserver::SetWebStateList(
+    WebStateList* web_state_list) {
+  if (web_state_list_ == web_state_list)
+    return;
+  if (web_state_list_)
+    web_state_list_->RemoveObserver(this);
+  web_state_list_ = web_state_list;
+  if (web_state_list_) {
+    web_state_list_->AddObserver(this);
+    web_state_observer_.SetWebState(web_state_list_->GetActiveWebState());
+  } else {
+    web_state_observer_.SetWebState(nullptr);
+  }
+}
+
 void FullscreenWebStateListObserver::Disconnect() {
-  web_state_list_->RemoveObserver(this);
-  web_state_list_ = nullptr;
-  web_state_observer_.SetWebState(nullptr);
+  SetWebStateList(nullptr);
 }
 
 void FullscreenWebStateListObserver::WebStateInsertedAt(
@@ -48,8 +56,8 @@
     int index,
     bool activating) {
   DCHECK_EQ(web_state_list_, web_state_list);
-  if (activating && controller_->IsEnabled())
-    controller_->ResetModel();
+  if (activating)
+    controller_->ExitFullscreen();
 }
 
 void FullscreenWebStateListObserver::WebStateReplacedAt(
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
index 0bdd2f7..8fcfe22 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
@@ -55,7 +55,8 @@
         controller_(&model_),
         mediator_(&controller_, &model_),
         web_state_list_(&web_state_list_delegate_),
-        observer_(&controller_, &model_, &web_state_list_, &mediator_) {
+        observer_(&controller_, &model_, &mediator_) {
+    observer_.SetWebStateList(&web_state_list_);
   }
 
   ~FullscreenWebStateListObserverTest() override {
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
index 27ecd6fc..62a2edad 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -121,7 +121,7 @@
     // considered as being in the SameDocument by the NavigationContext, so the
     // toolbar isn't shown in the DidFinishNavigation. For example this is
     // needed to load AMP pages from Google Search Result Page.
-    controller_->ResetModel();
+    controller_->ExitFullscreen();
   }
 }
 
@@ -148,12 +148,12 @@
 }
 
 void FullscreenWebStateObserver::SetIsLoading(bool loading) {
-  if (IsUIRefreshPhase1Enabled())
-    return;
-
-  if (!!loading_disabler_.get() == loading)
-    return;
-  loading_disabler_ =
-      loading ? std::make_unique<ScopedFullscreenDisabler>(controller_)
-              : nullptr;
+  if (IsUIRefreshPhase1Enabled()) {
+    if (loading)
+      controller_->ExitFullscreen();
+  } else {
+    loading_disabler_ =
+        loading ? std::make_unique<ScopedFullscreenDisabler>(controller_)
+                : nullptr;
+  }
 }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.mm
index 921ed74..835d3065c 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.mm
@@ -57,15 +57,11 @@
 
 - (BOOL)webViewScrollViewShouldScrollToTop:
     (CRWWebViewScrollViewProxy*)webViewScrollViewProxy {
-  if (self.model->progress() > 0.05) {
-    // Inform FullscreenUIElements that the content is going to be scrolled to
-    // the top.
-    self.mediator->ScrollToTop();
-    return YES;
-  } else {
-    self.mediator->AnimateModelReset();
-    return NO;
-  }
+  // Exit fullscreen when the status bar is tapped, but don't allow the scroll-
+  // to-top animation to occur if the toolbars are fully collapsed.
+  BOOL scrollToTop = !AreCGFloatsEqual(self.model->progress(), 0.0);
+  self.mediator->ExitFullscreen();
+  return scrollToTop;
 }
 
 @end
diff --git a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.h b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.h
index f817f32..fd22a7b 100644
--- a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.h
+++ b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.h
@@ -29,7 +29,8 @@
   void IncrementDisabledCounter() override;
   void DecrementDisabledCounter() override;
   CGFloat GetProgress() const override;
-  void ResetModel() override;
+  void EnterFullscreen() override;
+  void ExitFullscreen() override;
 
   // KeyedService:
   void Shutdown() override;
diff --git a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.mm b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.mm
index 13b290e5..e50b6762 100644
--- a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.mm
+++ b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.mm
@@ -53,13 +53,15 @@
   return model_ ? model_->progress() : 0.0;
 }
 
-void TestFullscreenController::ResetModel() {
-  if (model_)
-    model_->ResetForNavigation();
-}
-
 void TestFullscreenController::Shutdown() {
   for (auto& observer : observers_) {
     observer.FullscreenControllerWillShutDown(this);
   }
 }
+
+void TestFullscreenController::EnterFullscreen() {}
+
+void TestFullscreenController::ExitFullscreen() {
+  if (model_)
+    model_->ResetForNavigation();
+}
diff --git a/ios/chrome/browser/ui/image_util/image_saver.h b/ios/chrome/browser/ui/image_util/image_saver.h
index 8d41f907..c9dce93 100644
--- a/ios/chrome/browser/ui/image_util/image_saver.h
+++ b/ios/chrome/browser/ui/image_util/image_saver.h
@@ -7,11 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-class GURL;
-namespace web {
-class WebState;
-struct Referrer;
-}
+#include "components/image_fetcher/core/request_metadata.h"
 
 // Object saving images to the system's album.
 @interface ImageSaver : NSObject
@@ -20,12 +16,9 @@
 - (instancetype)initWithBaseViewController:
     (UIViewController*)baseViewController;
 
-// Fetches and saves the image at |url| to the system's album. |web_state| is
-// used for fetching image data by JavaScript and must not be nullptr.
-// |referrer| is used for download.
-- (void)saveImageAtURL:(const GURL&)url
-              referrer:(const web::Referrer&)referrer
-              webState:(web::WebState*)webState;
+// Saves the image's |data|, with |metadata| to the system's album.
+- (void)saveImageData:(NSData*)data
+         withMetadata:(const image_fetcher::RequestMetadata&)metadata;
 
 @end
 
diff --git a/ios/chrome/browser/ui/image_util/image_saver.mm b/ios/chrome/browser/ui/image_util/image_saver.mm
index 2f21d27..1f5c793 100644
--- a/ios/chrome/browser/ui/image_util/image_saver.mm
+++ b/ios/chrome/browser/ui/image_util/image_saver.mm
@@ -12,13 +12,12 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
-#include "base/threading/thread_restrictions.h"
+#include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
-#import "ios/chrome/browser/ui/image_util/image_util.h"
-#import "ios/chrome/browser/web/image_fetch_tab_helper.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
+#include "net/base/mime_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -46,32 +45,28 @@
   return self;
 }
 
-- (void)saveImageAtURL:(const GURL&)url
-              referrer:(const web::Referrer&)referrer
-              webState:(web::WebState*)webState {
-  ImageFetchTabHelper* tabHelper = ImageFetchTabHelper::FromWebState(webState);
-  DCHECK(tabHelper);
+- (void)saveImageData:(NSData*)data
+         withMetadata:(const image_fetcher::RequestMetadata&)metadata {
+  DCHECK(data);
 
-  __weak ImageSaver* weakSelf = self;
-  tabHelper->GetImageData(url, referrer, ^(NSData* data) {
-    ImageSaver* strongSelf = weakSelf;
-    if (!strongSelf)
-      return;
+  if ([data length] == 0) {
+    [self
+        displayPrivacyErrorAlertOnMainQueue:
+            l10n_util::GetNSString(IDS_IOS_SAVE_IMAGE_NO_INTERNET_CONNECTION)];
+    return;
+  }
 
-    if (data.length == 0) {
-      [strongSelf displayPrivacyErrorAlertOnMainQueue:
-                      l10n_util::GetNSString(
-                          IDS_IOS_SAVE_IMAGE_NO_INTERNET_CONNECTION)];
-      return;
-    }
+  base::FilePath::StringType extension;
 
-    NSString* extension = GetImageExtensionFromData(data);
-    NSString* fileExtension =
-        [@"." stringByAppendingString:extension ? extension : @"png"];
+  bool extensionSuccess =
+      net::GetPreferredExtensionForMimeType(metadata.mime_type, &extension);
+  if (!extensionSuccess || extension.length() == 0) {
+    extension = "png";
+  }
 
-    [strongSelf managePermissionAndSaveImage:data
-                           withFileExtension:fileExtension];
-  });
+  NSString* fileExtension =
+      [@"." stringByAppendingString:base::SysUTF8ToNSString(extension)];
+  [self managePermissionAndSaveImage:data withFileExtension:fileExtension];
 }
 
 // Saves the image or display error message, based on privacy settings.
diff --git a/ios/chrome/browser/ui/image_util/image_util.h b/ios/chrome/browser/ui/image_util/image_util.h
index 7bea162..2dee4bc 100644
--- a/ios/chrome/browser/ui/image_util/image_util.h
+++ b/ios/chrome/browser/ui/image_util/image_util.h
@@ -31,8 +31,4 @@
                                NSInteger left_cap_width,
                                NSInteger top_cap_height);
 
-// Returns the extension by checking the first byte of image |data|. If |data|
-// is nil, empty, or cannot be recognized, nil will be returned.
-NSString* GetImageExtensionFromData(NSData* data);
-
 #endif  // IOS_CHROME_BROWSER_UI_IMAGE_UTIL_IMAGE_UTIL_H_
diff --git a/ios/chrome/browser/ui/image_util/image_util.mm b/ios/chrome/browser/ui/image_util/image_util.mm
index 4cd321d..8e2f0bd 100644
--- a/ios/chrome/browser/ui/image_util/image_util.mm
+++ b/ios/chrome/browser/ui/image_util/image_util.mm
@@ -49,37 +49,3 @@
 
   return StretchableImageFromUIImage(image, left_cap_width, top_cap_height);
 }
-
-// https://en.wikipedia.org/wiki/List_of_file_signatures
-NSString* GetImageExtensionFromData(NSData* data) {
-  if (!data || data.length < 16)
-    return nil;
-
-  const char* pdata = static_cast<const char*>(data.bytes);
-  switch (pdata[0]) {
-    case '\xFF':
-      return strncmp(pdata, "\xFF\xD8\xFF", 3) ? nil : @"jpg";
-    case '\x89':
-      return strncmp(pdata, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) ? nil
-                                                                   : @"png";
-    case 'G':
-      return (strncmp(pdata, "GIF87a", 6) && strncmp(pdata, "GIF89a", 6))
-                 ? nil
-                 : @"gif";
-    case '\x49':
-      return strncmp(pdata, "\x49\x49\x2A\x00", 4) ? nil : @"tif";
-    case '\x4D':
-      return strncmp(pdata, "\x4D\x4D\x00\x2A", 4) ? nil : @"tif";
-    case 'B':
-      return strncmp(pdata, "BM", 2) ? nil : @"bmp";
-    case 'R':
-      return (strncmp(pdata, "RIFF", 4) || strncmp(pdata + 8, "WEBP", 4))
-                 ? nil
-                 : @"webp";
-    case '\0':
-      return strncmp(pdata, "\x00\x00\x01\x00", 4) ? nil : @"ico";
-    default:
-      return nil;
-  }
-  return nil;
-}
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index 5082fa0..067db7c 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -53,6 +53,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/fullscreen",
     "//ios/chrome/browser/ui/fullscreen:ui",
+    "//ios/chrome/browser/ui/ntp:util",
     "//ios/chrome/browser/ui/omnibox:omnibox",
     "//ios/chrome/browser/ui/omnibox:omnibox_internal",
     "//ios/chrome/browser/ui/omnibox:omnibox_util",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 3ba22d7b..9931bed0 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -18,6 +18,7 @@
 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
+#include "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/commands/load_query_commands.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
@@ -27,6 +28,7 @@
 #import "ios/chrome/browser/ui/location_bar/location_bar_mediator.h"
 #import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h"
 #include "ios/chrome/browser/ui/location_bar/location_bar_view_controller.h"
+#import "ios/chrome/browser/ui/ntp/ntp_util.h"
 #include "ios/chrome/browser/ui/omnibox/location_bar_delegate.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_coordinator.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
@@ -206,7 +208,7 @@
   if (immediately) {
     [self loadURLForQuery:sanitizedQuery];
   } else {
-    [self focusOmnibox];
+    [self.omniboxCoordinator focusOmnibox];
     [self.omniboxCoordinator
         insertTextToOmnibox:base::SysUTF16ToNSString(sanitizedQuery)];
   }
@@ -251,10 +253,21 @@
   [self focusOmnibox];
 }
 
-- (void)focusOmnibox {
+- (void)focusOmniboxFromFakebox {
   [self.omniboxCoordinator focusOmnibox];
 }
 
+- (void)focusOmnibox {
+  // When the NTP and fakebox are visible, make the fakebox animates into place
+  // before focusing the omnibox.
+  if (IsVisibleUrlNewTabPage([self webState]) &&
+      !self.browserState->IsOffTheRecord()) {
+    [self.viewController.dispatcher focusFakebox];
+  } else {
+    [self.omniboxCoordinator focusOmnibox];
+  }
+}
+
 - (void)cancelOmniboxEdit {
   [self.omniboxCoordinator endEditing];
 }
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
index 8c6853f..8345639 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
@@ -83,6 +83,10 @@
 // bar hint text.
 - (BOOL)wantsLocationBarHintText;
 
+// Animates the NTP fakebox to the focused position and focuses the real
+// omnibox.
+- (void)focusFakebox;
+
 @end
 
 #pragma mark - Testing
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
index 67bf5c1..6cfc401e 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -185,6 +185,11 @@
   return self;
 }
 
+- (void)focusFakebox {
+  DCHECK(IsUIRefreshPhase1Enabled());
+  [self.contentSuggestionsCoordinator.headerController focusFakebox];
+}
+
 - (void)dealloc {
   // This is not an ideal place to put view controller contaimnent, rather a
   // //web -wasDismissed method on CRWNativeContent would be more accurate. If
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm
index 3de0cbf..64c71884 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm
@@ -243,7 +243,7 @@
 }
 
 - (void)focusOmnibox:(id)sender {
-  [self.dispatcher focusFakebox];
+  [self.dispatcher fakeboxFocused];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
index 59a9389..4447b29 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
@@ -171,13 +171,13 @@
 - (void)exitFullscreen {
   FullscreenControllerFactory::GetInstance()
       ->GetForBrowserState(self.browserState)
-      ->ResetModel();
+      ->ExitFullscreen();
 }
 
 #pragma mark - FakeboxFocuser
 
-- (void)focusFakebox {
-  [self.locationBarCoordinator focusOmnibox];
+- (void)fakeboxFocused {
+  [self.locationBarCoordinator focusOmniboxFromFakebox];
 }
 
 - (void)onFakeboxBlur {
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index 6c495b7..c2eb6be 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -377,7 +377,7 @@
 
 #pragma mark - FakeboxFocuser
 
-- (void)focusFakebox {
+- (void)fakeboxFocused {
   if (IsIPadIdiom()) {
     // On iPhone there is no visible omnibox, so there's no need to indicate
     // interaction was initiated from the fakebox.
diff --git a/ios/chrome/browser/ui/toolbar/public/fakebox_focuser.h b/ios/chrome/browser/ui/toolbar/public/fakebox_focuser.h
index d6c054d0..c0c9736 100644
--- a/ios/chrome/browser/ui/toolbar/public/fakebox_focuser.h
+++ b/ios/chrome/browser/ui/toolbar/public/fakebox_focuser.h
@@ -12,7 +12,7 @@
 @protocol FakeboxFocuser
 // Give focus to the omnibox, but indicate that the focus event was initiated
 // from the fakebox on the Google landing page.
-- (void)focusFakebox;
+- (void)fakeboxFocused;
 // Hides the toolbar when the fakebox is blurred.
 - (void)onFakeboxBlur;
 // Shows the toolbar when the fakebox has animated to full bleed.
diff --git a/ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h b/ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h
index b372bb4..631eeb1 100644
--- a/ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h
+++ b/ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h
@@ -9,10 +9,13 @@
 
 // This protocol provides callbacks for focusing the omnibox.
 @protocol OmniboxFocuser
-// Give focus to the omnibox, if it is visible. No-op if it is not visible.
+// Give focus to the omnibox, if it is visible. No-op if it is not visible.  If
+// current page is an NTP, first focus the NTP fakebox.
 - (void)focusOmnibox;
 // Set next focus source as SEARCH_BUTTON and then call -focusOmnibox.
 - (void)focusOmniboxFromSearchButton;
+// Focus the omnibox but skip the NTP check.
+- (void)focusOmniboxFromFakebox;
 // Cancel omnibox edit (from shield tap or cancel button tap).
 - (void)cancelOmniboxEdit;
 @end
diff --git a/ios/chrome/browser/ui/toolbar_container/BUILD.gn b/ios/chrome/browser/ui/toolbar_container/BUILD.gn
new file mode 100644
index 0000000..db64bbf
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/BUILD.gn
@@ -0,0 +1,16 @@
+# 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.
+
+source_set("feature_flags") {
+  sources = [
+    "toolbar_container_features.h",
+    "toolbar_container_features.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h
new file mode 100644
index 0000000..ad801815
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h
@@ -0,0 +1,17 @@
+// 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 IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_TOOLBAR_CONTAINER_FEATURES_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_TOOLBAR_CONTAINER_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace toolbar_container {
+
+// Used to move toolbar layout management to a container view.
+extern const base::Feature kToolbarContainerEnabled;
+
+}  // namespace toolbar_container
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_TOOLBAR_CONTAINER_FEATURES_H_
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm
new file mode 100644
index 0000000..c591526
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm
@@ -0,0 +1,16 @@
+// 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.
+
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace toolbar_container {
+
+const base::Feature kToolbarContainerEnabled{"ToolbarContainerEnabled",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace toolbar_container
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 5fa4e6d2..1367996 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -452,7 +452,7 @@
     "web_state/js/crw_js_injection_manager_unittest.mm",
     "web_state/js/crw_js_post_request_loader_unittest.mm",
     "web_state/js/crw_js_window_id_manager_unittest.mm",
-    "web_state/js/frame_messaging_js_unittest.mm",
+    "web_state/js/message_js_unittest.mm",
     "web_state/js/page_script_util_unittest.mm",
   ]
 }
@@ -627,7 +627,6 @@
     "web_state/js/resources/all_frames_web_bundle.js",
     "web_state/js/resources/base.js",
     "web_state/js/resources/common.js",
-    "web_state/js/resources/frame_messaging.js",
     "web_state/js/resources/message.js",
   ]
 }
diff --git a/ios/web/js_compile.gni b/ios/web/js_compile.gni
index 9fd25b1..83bcc0b 100644
--- a/ios/web/js_compile.gni
+++ b/ios/web/js_compile.gni
@@ -122,7 +122,6 @@
       _js_modules = [
         "//ios/web/web_state/js/resources/base.js",
         "//ios/web/web_state/js/resources/common.js",
-        "//ios/web/web_state/js/resources/frame_messaging.js",
         "//ios/web/web_state/js/resources/message.js",
       ]
       if (defined(invoker.js_modules)) {
diff --git a/ios/web/net/crw_cert_verification_controller.mm b/ios/web/net/crw_cert_verification_controller.mm
index 8a521fd..5b03747 100644
--- a/ios/web/net/crw_cert_verification_controller.mm
+++ b/ios/web/net/crw_cert_verification_controller.mm
@@ -25,6 +25,10 @@
 #error "This file requires ARC support."
 #endif
 
+using base::TaskShutdownBehavior;
+using base::TaskTraits;
+using web::WebThread;
+
 @interface CRWCertVerificationController () {
   // Used to remember user exceptions to invalid certs.
   scoped_refptr<web::CertificatePolicyCache> _certPolicyCache;
@@ -66,7 +70,7 @@
 
 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
   DCHECK(browserState);
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  DCHECK_CURRENTLY_ON(WebThread::UI);
   self = [super init];
   if (self) {
     _certPolicyCache =
@@ -78,12 +82,12 @@
 - (void)decideLoadPolicyForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
                             host:(NSString*)host
                completionHandler:(web::PolicyDecisionHandler)completionHandler {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  DCHECK_CURRENTLY_ON(WebThread::UI);
   DCHECK(completionHandler);
 
   [self verifyTrust:trust
       completionHandler:^(SecTrustResultType trustResult) {
-        DCHECK_CURRENTLY_ON(web::WebThread::UI);
+        DCHECK_CURRENTLY_ON(WebThread::UI);
         if (trustResult == kSecTrustResultProceed ||
             trustResult == kSecTrustResultUnspecified) {
           completionHandler(web::CERT_ACCEPT_POLICY_ALLOW, net::CertStatus());
@@ -99,7 +103,7 @@
 - (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
                           host:(NSString*)host
              completionHandler:(web::StatusQueryHandler)completionHandler {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  DCHECK_CURRENTLY_ON(WebThread::UI);
   DCHECK(completionHandler);
 
   [self verifyTrust:trust
@@ -116,7 +120,7 @@
 - (void)allowCert:(scoped_refptr<net::X509Certificate>)cert
           forHost:(NSString*)host
            status:(net::CertStatus)status {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  DCHECK_CURRENTLY_ON(WebThread::UI);
   // Store user decisions with the leaf cert, ignoring any intermediates.
   // This is because WKWebView returns the verified certificate chain in
   // |webView:didReceiveAuthenticationChallenge:completionHandler:|,
@@ -128,7 +132,7 @@
     DCHECK(cert);
   }
   DCHECK(cert->intermediate_buffers().empty());
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO}, base::BindOnce(^{
+  base::PostTaskWithTraits(FROM_HERE, {WebThread::IO}, base::BindOnce(^{
                              _certPolicyCache->AllowCertForHost(
                                  cert.get(), base::SysNSStringToUTF8(host),
                                  status);
@@ -163,10 +167,11 @@
                            serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
                                   host:(NSString*)host
                      completionHandler:(web::PolicyDecisionHandler)handler {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  DCHECK_CURRENTLY_ON(WebThread::UI);
   DCHECK(handler);
+  TaskTraits traits{WebThread::IO, TaskShutdownBehavior::BLOCK_SHUTDOWN};
   base::PostTaskWithTraits(
-      FROM_HERE, {web::WebThread::IO}, base::BindOnce(^{
+      FROM_HERE, traits, base::BindOnce(^{
         // |loadPolicyForRejectedTrustResult:certStatus:serverTrust:host:| can
         // only be called on IO thread.
         net::CertStatus certStatus =
@@ -178,8 +183,8 @@
                                        serverTrust:trust.get()
                                               host:host];
 
-        base::PostTaskWithTraits(FROM_HERE, {web::WebThread::UI},
-                                 base::BindOnce(^{
+        TaskTraits traits{WebThread::UI, TaskShutdownBehavior::BLOCK_SHUTDOWN};
+        base::PostTaskWithTraits(FROM_HERE, traits, base::BindOnce(^{
                                    handler(policy, certStatus);
                                  }));
       }));
@@ -187,12 +192,12 @@
 
 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
     completionHandler:(void (^)(SecTrustResultType))completionHandler {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  DCHECK_CURRENTLY_ON(WebThread::UI);
   DCHECK(completionHandler);
   // SecTrustEvaluate performs trust evaluation synchronously, possibly making
   // network requests. The UI thread should not be blocked by that operation.
   base::PostTaskWithTraits(
-      FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, base::BindOnce(^{
+      FROM_HERE, {TaskShutdownBehavior::BLOCK_SHUTDOWN}, base::BindOnce(^{
         SecTrustResultType trustResult = kSecTrustResultInvalid;
         if (SecTrustEvaluate(trust.get(), &trustResult) != errSecSuccess) {
           trustResult = kSecTrustResultInvalid;
@@ -210,7 +215,7 @@
                       certStatus:(net::CertStatus)certStatus
                      serverTrust:(SecTrustRef)trust
                             host:(NSString*)host {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
+  DCHECK_CURRENTLY_ON(WebThread::IO);
   DCHECK_NE(web::SECURITY_STYLE_AUTHENTICATED,
             web::GetSecurityStyleFromTrustResult(trustResult));
 
diff --git a/ios/web/web_state/js/frame_messaging_js_unittest.mm b/ios/web/web_state/js/message_js_unittest.mm
similarity index 82%
rename from ios/web/web_state/js/frame_messaging_js_unittest.mm
rename to ios/web/web_state/js/message_js_unittest.mm
index 00ea4380..f0e89987 100644
--- a/ios/web/web_state/js/frame_messaging_js_unittest.mm
+++ b/ios/web/web_state/js/message_js_unittest.mm
@@ -14,16 +14,16 @@
 
 namespace {
 // JavaScript to return a frame's frameId.
-NSString* const kGetFrameIdJs = @"__gCrWeb.frameMessaging.getFrameId();";
+NSString* const kGetFrameIdJs = @"__gCrWeb.message.getFrameId();";
 }  // namespace
 
 namespace web {
 
-// Test fixture to test frame_messaging.js.
-typedef web::WebTestWithWebState FrameMessagingJsTest;
+// Test fixture to test message.js.
+typedef web::WebTestWithWebState MessageJsTest;
 
 // Tests that a frameId is created.
-TEST_F(FrameMessagingJsTest, FrameId) {
+TEST_F(MessageJsTest, FrameId) {
   ASSERT_TRUE(LoadHtml("<p>"));
 
   NSString* frame_id = ExecuteJavaScript(kGetFrameIdJs);
@@ -34,7 +34,7 @@
 }
 
 // Tests that the frameId is unique between two page loads.
-TEST_F(FrameMessagingJsTest, UniqueFrameID) {
+TEST_F(MessageJsTest, UniqueFrameID) {
   ASSERT_TRUE(LoadHtml("<p>"));
   NSString* frame_id = ExecuteJavaScript(kGetFrameIdJs);
 
diff --git a/ios/web/web_state/js/resources/all_frames_web_bundle.js b/ios/web/web_state/js/resources/all_frames_web_bundle.js
index a2a4bdd..704c4dc 100644
--- a/ios/web/web_state/js/resources/all_frames_web_bundle.js
+++ b/ios/web/web_state/js/resources/all_frames_web_bundle.js
@@ -8,6 +8,5 @@
 goog.require('__crWeb.allFramesContextMenu');
 goog.require('__crWeb.base');
 goog.require('__crWeb.common');
-goog.require('__crWeb.frameMessaging');
 goog.require('__crWeb.message');
 
diff --git a/ios/web/web_state/js/resources/frame_messaging.js b/ios/web/web_state/js/resources/frame_messaging.js
deleted file mode 100644
index 88161460..0000000
--- a/ios/web/web_state/js/resources/frame_messaging.js
+++ /dev/null
@@ -1,303 +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.
-
-/**
- * @fileoverview API used for secure communication with frames.
- */
-
-goog.provide('__crWeb.frameMessaging');
-
-goog.require('__crWeb.base');
-
-/**
- * Namespace for this module.
- */
-__gCrWeb.frameMessaging = {};
-
-// Store message namespace object in a global __gCrWeb object referenced by a
-// string, so it does not get renamed by closure compiler during the
-// minification.
-__gCrWeb['frameMessaging'] = __gCrWeb.frameMessaging;
-
-/** Beginning of anonymous object */
-(function() {
-
-/**
- * Unique identifier for this frame.
- * @type {?string}
- * @private
- */
-var frameId_ = null;
-
-/**
- * The encryption key to decrypt messages received from native code.
- * @type {?webCrypto.CryptoKey}
- * @private
- */
-var frameSymmetricKey_ = null;
-
-/**
- * The ID of the last processed message. If a received message has an ID less
- * than or equal to |lastReceivedMessageId_|, it will be ignored.
- * @type {number}
- * @private
- */
-var lastReceivedMessageId_ = -1;
-
-/**
- * Returns the frameId associated with this frame. A new value will be created
- * for this frame the first time it is called. The frameId will persist as long
- * as this JavaScript context lives. For example, the frameId will be the same
- * when navigating 'back' to this frame.
- * @return {string} A string representing a unique identifier for this frame.
- */
-__gCrWeb.frameMessaging['getFrameId'] = function() {
-  if (!frameId_) {
-    // Generate 128 bit unique identifier.
-    var components = new Uint32Array(4);
-    window.crypto.getRandomValues(components);
-    frameId_ = '';
-    for (var i = 0; i < components.length; i++) {
-      // Convert value to base16 string and append to the |frameId_|.
-      frameId_ += components[i].toString(16);
-    }
-  }
-  return /** @type {string} */ (frameId_);
-};
-
-/**
- * Returns whether or not frame messaging is supported for this frame.
- * @returns true if frame messaging is supported, false otherwise.
- */
-var isFrameMessagingSupported_ = function() {
-  // - Only secure contexts support the crypto.subtle API.
-  // - Even though iOS 10 supports window.crypto.webkitSubtle instead of
-  //   window.crypto.subtle, the AES-GCM cipher suite is not supported, so
-  //   support will only be used from the official WebCrypto API.
-  //   TODO(crbug.com/872818): Remove comment once only iOS 11+ is supported.
-  return window.isSecureContext && typeof window.crypto.subtle === 'object';
-}
-
-/**
- * Exports |frameSymmetricKey_| as a base64 string. Key will be created if it
- * does not already exist.
- * @param {function(string)} callback A callback to be run with the exported
- *                           base64 key.
- */
-var exportKey_ = function(callback) {
-  // Early return with an empty key string if encryption is not supported in
-  // this frame.
-  if (!isFrameMessagingSupported_()) {
-    callback("");
-    return;
-  }
-  try {
-    getFrameSymmetricKey_(function(key) {
-      window.crypto.subtle.exportKey('raw', key)
-          .then(function(/** @type {ArrayBuffer} */ k) {
-        var keyBytes = new Uint8Array(k);
-        var key64 = btoa(String.fromCharCode.apply(null, keyBytes));
-        callback(key64);
-      });
-    });
-  } catch (error) {
-    // AES-GCM will not be supported if a web developer overrode
-    // window.crypto.subtle with window.crypto.webkitSubtle on iOS 10.
-    callback("");
-  }
-};
-
-/**
- * Runs |callback| with the key associated with this frame. The key will be
- * created if necessary. The key will persist as long as this JavaScript context
- * lives. For example, the key will be the same when navigating 'back' to this
- * frame.
- * @param {function(!webCrypto.CryptoKey)} callback A callback to be run with
- *                                         the key.
- */
-var getFrameSymmetricKey_ = function(callback) {
-  if (frameSymmetricKey_) {
-    callback(frameSymmetricKey_);
-    return;
-  }
-  window.crypto.subtle.generateKey(
-    {'name': 'AES-GCM', 'length': 256},
-    true,
-    ['decrypt', 'encrypt']
-  ).then(function(/** @type {!webCrypto.CryptoKey} */ key) {
-    frameSymmetricKey_ = key;
-    callback(frameSymmetricKey_);
-  });
-};
-
-
-/**
- * Sends |result| to the native application as the return value from the
- * execution of the message with |messageId|.
- * @param {number} messageId The message ID which the response is associated.
- * @param {?Object} result The response to send.
- */
-var replyWithResult_ = function(messageId, result) {
-  var replyCommand =
-      'frameMessaging_' + __gCrWeb.frameMessaging['getFrameId']() + '.reply';
-  var response = {
-    'command': replyCommand,
-    'messageId': messageId
-  };
-  if (result) {
-    response['result'] = result
-  }
-  __gCrWeb.message.invokeOnHost(response);
-};
-
-/**
- * Executes |functionName| on __gCrWeb with the given |parameters|.
- * @param {!string} functionPath The function to execute on __gCrWeb. Components
- *                  may be separated by periods. For example: messaging.function
- * @param {!Array} parameters The parameters to pass to |functionName|.
- * @return The return value of executing |functionName| or null if it couldn't
- *         be executed.
- */
-var callGCrWebFunction_ = function(functionPath, parameters) {
-  var functionReference = __gCrWeb;
-  var functionComponents = functionPath.split('.');
-  var numComponents = functionComponents.length;
-  for (var i = 0; i < numComponents; i++) {
-    var component = functionComponents[i];
-    functionReference = functionReference[component];
-    if (!functionReference) {
-      return null;
-    }
-  }
-  return functionReference.apply(null, parameters);
-}
-
-/**
- * Decrypts and executes the function specified in |payload|.
- * @param {!string} payload The encrypted message payload.
- * @param {!string} iv The initialization vector used to encrypt the |payload|.
- */
-var executeMessage_ = function(payload, iv) {
-  if (!frameSymmetricKey_) {
-    // Payload cannot be decrypted without a key. This message could be spam or
-    // sent by the native application by mistake.
-    return;
-  }
-
-  // Decode the base64 payload.
-  var encryptedFunctionArray =
-      new Uint8Array(Array.from(atob(payload)).map(function(a) {
-    return a.charCodeAt(0);
-  }));
-
-  // Decode the base64 initialization buffer.
-  var ivbuf = new Uint8Array(Array.from(atob(iv)).map(function(a) {
-    return a.charCodeAt(0);
-  }));
-
-  var algorithm = {'name': 'AES-GCM', iv: ivbuf};
-  getFrameSymmetricKey_(function(frameKey) {
-    window.crypto.subtle.decrypt(algorithm, frameKey, encryptedFunctionArray)
-        .then(function(decrypted) {
-      var callJSON =
-          String.fromCharCode.apply(null, new Uint8Array(decrypted));
-      var callDict = JSON.parse(callJSON);
-
-      // Verify that message id is valid.
-      if (!Number.isInteger(callDict['messageId']) ||
-          callDict['messageId'] <= lastReceivedMessageId_) {
-        return;
-      }
-
-      // Check that a function name and parameters are specified.
-      if (typeof callDict['functionName'] !== 'string' ||
-          callDict['functionName'].length < 1 ||
-          !Array.isArray(callDict['parameters'])) {
-        return;
-      }
-
-      lastReceivedMessageId_ = callDict['messageId'];
-      var result =
-          callGCrWebFunction_(callDict['functionName'], callDict['parameters']);
-      if (typeof callDict['replyWithResult'] === 'boolean' &&
-          callDict['replyWithResult']) {
-        replyWithResult_(callDict['messageId'], result);
-      }
-    });
-  });
-};
-
-/**
- * Routes an encrypted message to the targeted frame. Once the target frame is
- * found, the |payload| will be decrypted and executed. This function is called
- * by the native code.
- * @param {!string} payload The encrypted message payload.
- * @param {!string} iv The initialization vector used to encrypt the |payload|.
- * @param {!string} target_frame_id The |frameId_| of the frame which should
- *                  process the |payload|.
- */
-__gCrWeb.frameMessaging['routeMessage'] =
-    function(payload, iv, target_frame_id) {
-  if (!isFrameMessagingSupported_()) {
-    // API is unsupported.
-    return;
-  }
-
-  if (target_frame_id === __gCrWeb.frameMessaging['getFrameId']()) {
-    executeMessage_(payload, iv);
-    return;
-  }
-
-  var framecount = window.frames.length;
-  for (var i = 0; i < framecount; i++) {
-    window.frames[i].postMessage(
-      {
-        type: 'org.chromium.encryptedMessage',
-        payload: payload,
-        iv: iv,
-        target_frame_id: target_frame_id
-      },
-      '*'
-    );
-  }
-};
-
-/**
- * Creates (or gets the existing) encryption key and sends it to the native
- * application.
- */
-__gCrWeb.frameMessaging['registerFrame'] = function() {
-  exportKey_(function(frameKey) {
-    __gCrWeb.common.sendWebKitMessage('FrameBecameAvailable', {
-      'crwFrameId': __gCrWeb.frameMessaging['getFrameId'](),
-      'crwFrameKey': frameKey,
-      'crwFrameLastReceivedMessageId': lastReceivedMessageId_
-    });
-  });
-};
-
-/**
- * Registers this frame with the native code and forwards the message to any
- * child frames.
- * This needs to be called by the native application on each navigation
- * because no JavaScript events are fired reliably when a page is displayed and
- * hidden. This is especially important when a page remains alive and is re-used
- * from the WebKit page cache.
- * TODO(crbug.com/872134): In iOS 12, the JavaScript pageshow and pagehide
- *                         events seem reliable, so replace this exposed
- *                         function with a pageshow event listener.
- */
-__gCrWeb.frameMessaging['getExistingFrames'] = function() {
-  __gCrWeb.frameMessaging['registerFrame']();
-
-  var framecount = window['frames']['length'];
-  for (var i = 0; i < framecount; i++) {
-    window.frames[i].postMessage(
-        {type: 'org.chromium.registerForFrameMessaging',},
-        '*'
-    );
-  }
-};
-
-}());  // End of anonymous object
diff --git a/ios/web/web_state/js/resources/message.js b/ios/web/web_state/js/resources/message.js
index f1fb71e..611ece4 100644
--- a/ios/web/web_state/js/resources/message.js
+++ b/ios/web/web_state/js/resources/message.js
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Scripts for the message handler.
+/**
+ * @fileoverview API used for bi-directional communication between frames and
+ * the native code.
+ */
 
 goog.provide('__crWeb.message');
 
+goog.require('__crWeb.base');
 goog.require('__crWeb.common');
-goog.require('__crWeb.frameMessaging');
 
 /**
  * Namespace for this module.
@@ -39,6 +42,28 @@
 messageQueue_.reset();
 
 /**
+ * Unique identifier for this frame.
+ * @type {?string}
+ * @private
+ */
+var frameId_ = null;
+
+/**
+ * The encryption key to decrypt messages received from native code.
+ * @type {?webCrypto.CryptoKey}
+ * @private
+ */
+var frameSymmetricKey_ = null;
+
+/**
+ * The ID of the last processed message. If a received message has an ID less
+ * than or equal to |lastReceivedMessageId_|, it will be ignored.
+ * @type {number}
+ * @private
+ */
+var lastReceivedMessageId_ = -1;
+
+/**
  * Invokes a command on the Objective-C side.
  * @param {Object} command The command in a JavaScript object.
  * @public
@@ -78,7 +103,7 @@
   queueObject.queue.forEach(function(command) {
     __gCrWeb.common.sendWebKitMessage(queueObject.scheme, {
       'crwCommand': command,
-      'crwFrameId': __gCrWeb.frameMessaging['getFrameId'](),
+      'crwFrameId': __gCrWeb.message['getFrameId'](),
       'crwWindowId': window.top.__gCrWeb['windowId']
     });
   });
@@ -90,4 +115,259 @@
     Object.prototype.toJSON = originalObjectToJSON;
   }
 }
+
+/**
+ * Returns whether or not frame messaging is supported for this frame.
+ * @returns true if frame messaging is supported, false otherwise.
+ */
+var isFrameMessagingSupported_ = function() {
+  // - Only secure contexts support the crypto.subtle API.
+  // - Even though iOS 10 supports window.crypto.webkitSubtle instead of
+  //   window.crypto.subtle, the AES-GCM cipher suite is not supported, so
+  //   support will only be used from the official WebCrypto API.
+  //   TODO(crbug.com/872818): Remove comment once only iOS 11+ is supported.
+  return window.isSecureContext && typeof window.crypto.subtle === 'object';
+}
+
+/**
+ * Exports |frameSymmetricKey_| as a base64 string. Key will be created if it
+ * does not already exist.
+ * @param {function(string)} callback A callback to be run with the exported
+ *                           base64 key.
+ */
+var exportKey_ = function(callback) {
+  // Early return with an empty key string if encryption is not supported in
+  // this frame.
+  if (!isFrameMessagingSupported_()) {
+    callback("");
+    return;
+  }
+  try {
+    getFrameSymmetricKey_(function(key) {
+      window.crypto.subtle.exportKey('raw', key)
+          .then(function(/** @type {ArrayBuffer} */ k) {
+        var keyBytes = new Uint8Array(k);
+        var key64 = btoa(String.fromCharCode.apply(null, keyBytes));
+        callback(key64);
+      });
+    });
+  } catch (error) {
+    // AES-GCM will not be supported if a web developer overrode
+    // window.crypto.subtle with window.crypto.webkitSubtle on iOS 10.
+    callback("");
+  }
+};
+
+/**
+ * Runs |callback| with the key associated with this frame. The key will be
+ * created if necessary. The key will persist as long as this JavaScript context
+ * lives. For example, the key will be the same when navigating 'back' to this
+ * frame.
+ * @param {function(!webCrypto.CryptoKey)} callback A callback to be run with
+ *                                         the key.
+ */
+var getFrameSymmetricKey_ = function(callback) {
+  if (frameSymmetricKey_) {
+    callback(frameSymmetricKey_);
+    return;
+  }
+  window.crypto.subtle.generateKey(
+    {'name': 'AES-GCM', 'length': 256},
+    true,
+    ['decrypt', 'encrypt']
+  ).then(function(/** @type {!webCrypto.CryptoKey} */ key) {
+    frameSymmetricKey_ = key;
+    callback(frameSymmetricKey_);
+  });
+};
+
+
+/**
+ * Sends |result| to the native application as the return value from the
+ * execution of the message with |messageId|.
+ * @param {number} messageId The message ID which the response is associated.
+ * @param {?Object} result The response to send.
+ */
+var replyWithResult_ = function(messageId, result) {
+  var replyCommand = 'frameMessaging_' +
+      __gCrWeb.message['getFrameId']() + '.reply';
+  var response = {
+    'command': replyCommand,
+    'messageId': messageId
+  };
+  if (result) {
+    response['result'] = result
+  }
+  __gCrWeb.message.invokeOnHost(response);
+};
+
+/**
+ * Executes |functionName| on __gCrWeb with the given |parameters|.
+ * @param {!string} functionPath The function to execute on __gCrWeb. Components
+ *                  may be separated by periods. For example: messaging.function
+ * @param {!Array} parameters The parameters to pass to |functionName|.
+ * @return The return value of executing |functionName| or null if it couldn't
+ *         be executed.
+ */
+var callGCrWebFunction_ = function(functionPath, parameters) {
+  var functionReference = __gCrWeb;
+  var functionComponents = functionPath.split('.');
+  var numComponents = functionComponents.length;
+  for (var i = 0; i < numComponents; i++) {
+    var component = functionComponents[i];
+    functionReference = functionReference[component];
+    if (!functionReference) {
+      return null;
+    }
+  }
+  return functionReference.apply(null, parameters);
+}
+
+/**
+ * Decrypts and executes the function specified in |payload|.
+ * @param {!string} payload The encrypted message payload.
+ * @param {!string} iv The initialization vector used to encrypt the |payload|.
+ */
+var executeMessage_ = function(payload, iv) {
+  if (!frameSymmetricKey_) {
+    // Payload cannot be decrypted without a key. This message could be spam or
+    // sent by the native application by mistake.
+    return;
+  }
+
+  // Decode the base64 payload.
+  var encryptedFunctionArray =
+      new Uint8Array(Array.from(atob(payload)).map(function(a) {
+    return a.charCodeAt(0);
+  }));
+
+  // Decode the base64 initialization buffer.
+  var ivbuf = new Uint8Array(Array.from(atob(iv)).map(function(a) {
+    return a.charCodeAt(0);
+  }));
+
+  var algorithm = {'name': 'AES-GCM', iv: ivbuf};
+  getFrameSymmetricKey_(function(frameKey) {
+    window.crypto.subtle.decrypt(algorithm, frameKey, encryptedFunctionArray)
+        .then(function(decrypted) {
+      var callJSON =
+          String.fromCharCode.apply(null, new Uint8Array(decrypted));
+      var callDict = JSON.parse(callJSON);
+
+      // Verify that message id is valid.
+      if (!Number.isInteger(callDict['messageId']) ||
+          callDict['messageId'] <= lastReceivedMessageId_) {
+        return;
+      }
+
+      // Check that a function name and parameters are specified.
+      if (typeof callDict['functionName'] !== 'string' ||
+          callDict['functionName'].length < 1 ||
+          !Array.isArray(callDict['parameters'])) {
+        return;
+      }
+
+      lastReceivedMessageId_ = callDict['messageId'];
+      var result =
+          callGCrWebFunction_(callDict['functionName'], callDict['parameters']);
+      if (typeof callDict['replyWithResult'] === 'boolean' &&
+          callDict['replyWithResult']) {
+        replyWithResult_(callDict['messageId'], result);
+      }
+    });
+  });
+};
+
+/**
+ * Returns the frameId associated with this frame. A new value will be created
+ * for this frame the first time it is called. The frameId will persist as long
+ * as this JavaScript context lives. For example, the frameId will be the same
+ * when navigating 'back' to this frame.
+ * @return {string} A string representing a unique identifier for this frame.
+ */
+__gCrWeb.message['getFrameId'] = function() {
+  if (!frameId_) {
+    // Generate 128 bit unique identifier.
+    var components = new Uint32Array(4);
+    window.crypto.getRandomValues(components);
+    frameId_ = '';
+    for (var i = 0; i < components.length; i++) {
+      // Convert value to base16 string and append to the |frameId_|.
+      frameId_ += components[i].toString(16);
+    }
+  }
+  return /** @type {string} */ (frameId_);
+};
+
+/**
+ * Routes an encrypted message to the targeted frame. Once the target frame is
+ * found, the |payload| will be decrypted and executed. This function is called
+ * by the native code.
+ * @param {!string} payload The encrypted message payload.
+ * @param {!string} iv The initialization vector used to encrypt the |payload|.
+ * @param {!string} target_frame_id The |frameId_| of the frame which should
+ *                  process the |payload|.
+ */
+__gCrWeb.message['routeMessage'] = function(payload, iv, target_frame_id) {
+  if (!isFrameMessagingSupported_()) {
+    // API is unsupported.
+    return;
+  }
+
+  if (target_frame_id === __gCrWeb.message['getFrameId']()) {
+    executeMessage_(payload, iv);
+    return;
+  }
+
+  var framecount = window.frames.length;
+  for (var i = 0; i < framecount; i++) {
+    window.frames[i].postMessage(
+      {
+        type: 'org.chromium.encryptedMessage',
+        payload: payload,
+        iv: iv,
+        target_frame_id: target_frame_id
+      },
+      '*'
+    );
+  }
+};
+
+/**
+ * Creates (or gets the existing) encryption key and sends it to the native
+ * application.
+ */
+__gCrWeb.message['registerFrame'] = function() {
+  exportKey_(function(frameKey) {
+    __gCrWeb.common.sendWebKitMessage('FrameBecameAvailable', {
+      'crwFrameId': __gCrWeb.message['getFrameId'](),
+      'crwFrameKey': frameKey,
+      'crwFrameLastReceivedMessageId': lastReceivedMessageId_
+    });
+  });
+};
+
+/**
+ * Registers this frame with the native code and forwards the message to any
+ * child frames.
+ * This needs to be called by the native application on each navigation
+ * because no JavaScript events are fired reliably when a page is displayed and
+ * hidden. This is especially important when a page remains alive and is re-used
+ * from the WebKit page cache.
+ * TODO(crbug.com/872134): In iOS 12, the JavaScript pageshow and pagehide
+ *                         events seem reliable, so replace this exposed
+ *                         function with a pageshow event listener.
+ */
+__gCrWeb.message['getExistingFrames'] = function() {
+  __gCrWeb.message['registerFrame']();
+
+  var framecount = window['frames']['length'];
+  for (var i = 0; i < framecount; i++) {
+    window.frames[i].postMessage(
+        {type: 'org.chromium.registerForFrameMessaging',},
+        '*'
+    );
+  }
+};
+
 }());
diff --git a/ios/web/web_state/js/resources/setup_frame.js b/ios/web/web_state/js/resources/setup_frame.js
index f7f9a65..9a562078 100644
--- a/ios/web/web_state/js/resources/setup_frame.js
+++ b/ios/web/web_state/js/resources/setup_frame.js
@@ -12,7 +12,7 @@
 
 goog.provide('__crWeb.setupFrame');
 
-// Requires __crWeb.common and __crWeb.frameMessaging provided by
+// Requires __crWeb.common and __crWeb.message provided by
 // __crWeb.allFramesWebBundle.
 
 /* Beginning of anonymous object. */
@@ -20,7 +20,7 @@
 
 window.addEventListener('unload', function(event) {
   __gCrWeb.common.sendWebKitMessage('FrameBecameUnavailable',
-      __gCrWeb.frameMessaging.getFrameId());
+      __gCrWeb.message.getFrameId());
 });
 
 /**
@@ -34,13 +34,13 @@
   }
   if (payload.hasOwnProperty('type') &&
     payload.type == 'org.chromium.registerForFrameMessaging') {
-    __gCrWeb.frameMessaging['getExistingFrames']();
+    __gCrWeb.message['getExistingFrames']();
   } else if (payload.hasOwnProperty('type') &&
       payload.type == 'org.chromium.encryptedMessage') {
     if (payload.hasOwnProperty('payload') &&
         payload.hasOwnProperty('iv') &&
         payload.hasOwnProperty('target_frame_id')) {
-      __gCrWeb.frameMessaging['routeMessage'](
+      __gCrWeb.message['routeMessage'](
         payload['payload'],
         payload['iv'],
         payload['target_frame_id']
@@ -50,9 +50,9 @@
 });
 
 // Frame registration must be delayed until Document End script injection time.
-// (This file is injected at that time, but the frameMessaging API is defined at
+// (This file is injected at that time, but the message API is defined at
 // Document Start time.)
 // TODO(crbug.com/873730): Stop exposing registerFrame API.
-__gCrWeb.frameMessaging['registerFrame']();
+__gCrWeb.message['registerFrame']();
 
 }());  // End of anonymous object
diff --git a/ios/web/web_state/web_frame_impl.mm b/ios/web/web_state/web_frame_impl.mm
index ddbdcac9..83c5818 100644
--- a/ios/web/web_state/web_frame_impl.mm
+++ b/ios/web/web_state/web_frame_impl.mm
@@ -116,7 +116,7 @@
   std::string encoded_message;
   base::Base64Encode(ciphertext, &encoded_message);
   std::string script = base::StringPrintf(
-      "__gCrWeb.frameMessaging.routeMessage('%s', '%s', '%s')",
+      "__gCrWeb.message.routeMessage('%s', '%s', '%s')",
       encoded_message.c_str(), encoded_iv.c_str(), frame_id_.c_str());
   GetWebState()->ExecuteJavaScript(base::UTF8ToUTF16(script));
 
diff --git a/ios/web/web_state/web_frame_impl_inttest.mm b/ios/web/web_state/web_frame_impl_inttest.mm
index 59e0bdf..4ceaaa103 100644
--- a/ios/web/web_state/web_frame_impl_inttest.mm
+++ b/ios/web/web_state/web_frame_impl_inttest.mm
@@ -72,8 +72,7 @@
   __block bool called = false;
   std::vector<base::Value> params;
   main_frame->CallJavaScriptFunction(
-      "frameMessaging.getFrameId", params,
-      base::BindOnce(^(const base::Value* value) {
+      "message.getFrameId", params, base::BindOnce(^(const base::Value* value) {
         ASSERT_TRUE(value->is_string());
         EXPECT_EQ(value->GetString(), main_frame->GetFrameId());
         called = true;
@@ -108,8 +107,7 @@
   __block bool called = false;
   std::vector<base::Value> params;
   iframe->CallJavaScriptFunction(
-      "frameMessaging.getFrameId", params,
-      base::BindOnce(^(const base::Value* value) {
+      "message.getFrameId", params, base::BindOnce(^(const base::Value* value) {
         ASSERT_TRUE(value->is_string());
         EXPECT_EQ(value->GetString(), iframe->GetFrameId());
         called = true;
@@ -174,12 +172,12 @@
   // the iframe.
   ExecuteJavaScript(
       @"var sensitiveValue = 0;"
-       "__gCrWeb.frameMessaging.incrementSensitiveValue = function() {"
+       "__gCrWeb.message.incrementSensitiveValue = function() {"
        "  sensitiveValue = sensitiveValue + 1;"
        "  return sensitiveValue;"
        "};"
 
-       "var originalRouteMessage = __gCrWeb.frameMessaging.routeMessage;"
+       "var originalRouteMessage = __gCrWeb.message.routeMessage;"
        "var interceptedMessagePayload = '';"
        "var interceptedMessageIv = '';"
        "var interceptedMessageFrameId = '';"
@@ -192,7 +190,7 @@
        "  );"
        "};"
 
-       "__gCrWeb.frameMessaging.routeMessage ="
+       "__gCrWeb.message.routeMessage ="
        "    function(payload, iv, target_frame_id) {"
        "  interceptedMessagePayload = payload;"
        "  interceptedMessageIv = iv;"
@@ -207,7 +205,7 @@
   __block bool called = false;
   std::vector<base::Value> params;
   main_frame->CallJavaScriptFunction(
-      "frameMessaging.incrementSensitiveValue", params,
+      "message.incrementSensitiveValue", params,
       base::BindOnce(^(const base::Value* value) {
         ASSERT_TRUE(value->is_double());
         EXPECT_EQ(1, static_cast<int>(value->GetDouble()));
diff --git a/ios/web/web_state/web_frame_impl_unittest.mm b/ios/web/web_state/web_frame_impl_unittest.mm
index d5eb44e..4295fb13 100644
--- a/ios/web/web_state/web_frame_impl_unittest.mm
+++ b/ios/web/web_state/web_frame_impl_unittest.mm
@@ -102,7 +102,7 @@
 }
 
 // Tests that |CallJavaScriptFunction| encrypts the message and passes it to
-// __gCrWeb.frameMessaging.routeMessage in the main frame.
+// __gCrWeb.message.routeMessage in the main frame.
 TEST_F(WebFrameImplTest, CallJavaScriptFunction) {
   TestWebState test_web_state;
   GURL security_origin;
@@ -117,7 +117,7 @@
 
   NSString* last_script =
       base::SysUTF16ToNSString(test_web_state.GetLastExecutedJavascript());
-  EXPECT_TRUE([last_script hasPrefix:@"__gCrWeb.frameMessaging.routeMessage"]);
+  EXPECT_TRUE([last_script hasPrefix:@"__gCrWeb.message.routeMessage"]);
   // Verify the message does not contain the plaintext function name or
   // parameters.
   EXPECT_FALSE([last_script containsString:@"functionName"]);
diff --git a/ios/web/web_state/web_frames_manager_impl.mm b/ios/web/web_state/web_frames_manager_impl.mm
index 8d264cb..5f60ffa 100644
--- a/ios/web/web_state/web_frames_manager_impl.mm
+++ b/ios/web/web_state/web_frames_manager_impl.mm
@@ -102,7 +102,7 @@
 
 void WebFramesManagerImpl::RegisterExistingFrames() {
   web_state_->ExecuteJavaScript(
-      base::UTF8ToUTF16("__gCrWeb.frameMessaging.getExistingFrames();"));
+      base::UTF8ToUTF16("__gCrWeb.message.getExistingFrames();"));
 }
 
 }  // namespace
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
index a944787..0344133 100644
--- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
@@ -93,9 +93,7 @@
 
   auto profile_sync_service =
       std::make_unique<ProfileSyncService>(std::move(init_params));
-  // Will also initialize the sync client.
   profile_sync_service->Initialize();
-
   return profile_sync_service;
 }
 
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h
index 311e722..412193e 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.h
+++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -33,7 +33,6 @@
   ~WebViewSyncClient() override;
 
   // SyncClient implementation.
-  void Initialize() override;
   syncer::SyncService* GetSyncService() override;
   PrefService* GetPrefService() override;
   base::FilePath GetLocalSyncBackendFolder() override;
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 787fa58..d661a1a2 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -59,13 +59,7 @@
 }  // namespace
 
 WebViewSyncClient::WebViewSyncClient(WebViewBrowserState* browser_state)
-    : browser_state_(browser_state) {}
-
-WebViewSyncClient::~WebViewSyncClient() {}
-
-void WebViewSyncClient::Initialize() {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-
+    : browser_state_(browser_state) {
   profile_web_data_service_ =
       WebViewWebDataServiceWrapperFactory::GetAutofillWebDataForBrowserState(
           browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
@@ -93,6 +87,8 @@
       /*bookmark_sync_service=*/nullptr));
 }
 
+WebViewSyncClient::~WebViewSyncClient() {}
+
 syncer::SyncService* WebViewSyncClient::GetSyncService() {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
   return WebViewProfileSyncServiceFactory::GetForBrowserState(browser_state_);
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 4367019..3c9dc2e 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -24,9 +24,7 @@
   MediaMsgStart,
   PpapiMsgStart,
   DOMStorageMsgStart,
-  P2PMsgStart,
   ResourceMsgStart,
-  FileSystemMsgStart,
   BlobMsgStart,
   MidiMsgStart,
   ChromeMsgStart,
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
index 9dd4ff0..bc129f6 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -20,6 +20,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.MainDex;
+import org.chromium.base.compat.ApiHelperForN;
 
 import java.util.Arrays;
 import java.util.Iterator;
@@ -673,7 +674,7 @@
      */
     static void setPatternIfSupported(CryptoInfo cryptoInfo, int encrypt, int skip) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            cryptoInfo.setPattern(new CryptoInfo.Pattern(encrypt, skip));
+            ApiHelperForN.setCryptoInfoPattern(cryptoInfo, encrypt, skip);
         }
     }
 }
diff --git a/media/gpu/windows/d3d11_decryptor.cc b/media/gpu/windows/d3d11_decryptor.cc
index cab7d809..258e87d83 100644
--- a/media/gpu/windows/d3d11_decryptor.cc
+++ b/media/gpu/windows/d3d11_decryptor.cc
@@ -101,6 +101,26 @@
          subsamples.front().cypher_bytes == sample_size;
 }
 
+// Checks whether |device1| is the same component as |device2|.
+// Note that comparing COM pointers require using their IUnknowns.
+// https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-queryinterface(q_)
+bool SameDevices(Microsoft::WRL::ComPtr<ID3D11Device> device1,
+                 Microsoft::WRL::ComPtr<ID3D11Device> device2) {
+  // For the case where both are nullptrs, they aren't devices, so returning
+  // false here.
+  if (!device1 || !device2)
+    return false;
+  Microsoft::WRL::ComPtr<IUnknown> device1_iunknown;
+  Microsoft::WRL::ComPtr<IUnknown> device2_iunknown;
+  HRESULT hr = device1.CopyTo(device1_iunknown.ReleaseAndGetAddressOf());
+  if (FAILED(hr))
+    return false;
+  hr = device2.CopyTo(device2_iunknown.ReleaseAndGetAddressOf());
+  if (FAILED(hr))
+    return false;
+  return device1_iunknown == device2_iunknown;
+}
+
 }  // namespace
 
 D3D11Decryptor::D3D11Decryptor(CdmProxyContext* cdm_proxy_context)
@@ -217,9 +237,16 @@
 
 bool D3D11Decryptor::InitializeDecryptionBuffer(
     const CdmProxyContext::D3D11DecryptContext& decrypt_context) {
-  // TODO(crbug.com/877667): Check whether the crypto session's device is the
-  // same as device_, if so there is no reason to recreate buffers.
-  decrypt_context.crypto_session->GetDevice(device_.ReleaseAndGetAddressOf());
+  ComPtr<ID3D11Device> crypto_session_device;
+  decrypt_context.crypto_session->GetDevice(
+      crypto_session_device.ReleaseAndGetAddressOf());
+
+  // If they are the same devices, then there is no reason to reinitialize the
+  // buffers.
+  if (SameDevices(crypto_session_device, device_))
+    return true;
+
+  device_ = crypto_session_device;
   device_->GetImmediateContext(device_context_.ReleaseAndGetAddressOf());
 
   HRESULT hresult =
diff --git a/media/gpu/windows/d3d11_decryptor.h b/media/gpu/windows/d3d11_decryptor.h
index 3bbf1a3e..68c94d9 100644
--- a/media/gpu/windows/d3d11_decryptor.h
+++ b/media/gpu/windows/d3d11_decryptor.h
@@ -62,6 +62,9 @@
 
   template <class T>
   using ComPtr = Microsoft::WRL::ComPtr<T>;
+
+  // After a successful InitializeDecryptionBuffer() call, these are set for the
+  // current Decrypt() call.
   ComPtr<ID3D11Device> device_;
   ComPtr<ID3D11DeviceContext> device_context_;
   ComPtr<ID3D11VideoContext> video_context_;
diff --git a/media/gpu/windows/d3d11_decryptor_unittest.cc b/media/gpu/windows/d3d11_decryptor_unittest.cc
index a5dc0edd..806713b6 100644
--- a/media/gpu/windows/d3d11_decryptor_unittest.cc
+++ b/media/gpu/windows/d3d11_decryptor_unittest.cc
@@ -9,6 +9,7 @@
 #include <array>
 
 #include "base/bind.h"
+#include "base/containers/span.h"
 #include "base/stl_util.h"
 #include "media/base/cdm_proxy_context.h"
 #include "media/base/decoder_buffer.h"
@@ -21,6 +22,7 @@
 using ::testing::ElementsAreArray;
 using ::testing::Invoke;
 using ::testing::IsNull;
+using ::testing::Mock;
 using ::testing::Pointee;
 using ::testing::Return;
 using ::testing::SetArgPointee;
@@ -42,16 +44,19 @@
 constexpr base::TimeDelta kTestTimestamp =
     base::TimeDelta::FromMilliseconds(33);
 
+const uint8_t kAnyKeyBlob[] = {3, 5, 38, 19};
+const char kKeyId[] = "some 16 byte id.";
+const char kIv[] = "some 16 byte iv.";
+
 scoped_refptr<DecoderBuffer> TestDecoderBuffer(
     const uint8_t* input,
     size_t data_size,
     const std::string& key_id,
     const std::string& iv,
-    const SubsampleEntry& subsample) {
+    const std::vector<SubsampleEntry>& subsamples) {
   scoped_refptr<DecoderBuffer> encrypted_buffer =
       DecoderBuffer::CopyFrom(input, data_size);
 
-  std::vector<SubsampleEntry> subsamples = {subsample};
   encrypted_buffer->set_decrypt_config(
       DecryptConfig::CreateCencConfig(key_id, iv, subsamples));
   encrypted_buffer->set_timestamp(kTestTimestamp);
@@ -113,6 +118,7 @@
                               buffer->data() + buffer->data_size());
   return actual == expected;
 }
+
 }  // namespace
 
 class D3D11DecryptorTest : public ::testing::Test {
@@ -125,6 +131,138 @@
     video_context_mock_ = CreateD3D11Mock<D3D11VideoContextMock>();
   }
 
+  // Only sets mock expectations to the objects. Use this for the case where the
+  // buffers are expected to be created from |device_mock_|, that's accessible
+  // through |crypto_session_mock|'s GetDevice() function.
+  void SetExpectationsForSuccessfulBufferInitialization(
+      D3D11CryptoSessionMock* crypto_session_mock,
+      D3D11BufferMock* staging_buffer1,
+      D3D11BufferMock* staging_buffer2,
+      D3D11BufferMock* gpu_buffer,
+      CdmProxyContext::D3D11DecryptContext* decrypt_context) {
+    // As noted in the function comment, the device is accessible from the
+    // crypto session.
+    EXPECT_CALL(*crypto_session_mock, GetDevice(_))
+        .Times(AtLeast(1))
+        .WillRepeatedly(AddRefAndSetArgPointee<0>(device_mock_.Get()));
+
+    // The other components accessible (directly or indirectly) from the device.
+    EXPECT_CALL(*device_mock_.Get(), GetImmediateContext(_))
+        .Times(AtLeast(1))
+        .WillRepeatedly(AddRefAndSetArgPointee<0>(device_context_mock_.Get()));
+    EXPECT_CALL(*device_context_mock_.Get(),
+                QueryInterface(IID_ID3D11VideoContext, _))
+        .Times(AtLeast(1))
+        .WillRepeatedly(
+            DoAll(AddRefAndSetArgPointee<1>(video_context_mock_.Get()),
+                  Return(S_OK)));
+
+    EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
+        .WillOnce(Return(*decrypt_context));
+
+    // These return big enough size.
+    ON_CALL(*staging_buffer1, GetDesc(_))
+        .WillByDefault(SetBufferDescSize(20000));
+    ON_CALL(*staging_buffer2, GetDesc(_))
+        .WillByDefault(SetBufferDescSize(20000));
+    ON_CALL(*gpu_buffer, GetDesc(_)).WillByDefault(SetBufferDescSize(20000));
+
+    // It should be requesting for 2 staging buffers one for writing the data to
+    // a GPU buffer and one for reading from the a GPU buffer.
+    EXPECT_CALL(*device_mock_.Get(),
+                CreateBuffer(BufferDescHas(D3D11_USAGE_STAGING, 0u,
+                                           D3D11_CPU_ACCESS_READ |
+                                               D3D11_CPU_ACCESS_WRITE),
+                             nullptr, _))
+        .WillOnce(
+            DoAll(AddRefAndSetArgPointee<2>(staging_buffer1), Return(S_OK)))
+        .WillOnce(
+            DoAll(AddRefAndSetArgPointee<2>(staging_buffer2), Return(S_OK)));
+
+    // It should be requesting a GPU only accessible buffer to the decrypted
+    // output.
+    EXPECT_CALL(*device_mock_.Get(),
+                CreateBuffer(BufferDescHas(D3D11_USAGE_DEFAULT,
+                                           D3D11_BIND_RENDER_TARGET, 0u),
+                             nullptr, _))
+        .WillOnce(DoAll(AddRefAndSetArgPointee<2>(gpu_buffer), Return(S_OK)));
+  }
+
+  // |input| is the input to the Decrypt() function, the subsample information
+  // is in |subsamples| therefore |input| may not be entirely encrypted. The
+  // data that is encrypted in |input| should be |encrypted_input|.
+  // |whole_output| is the expected output from the Decrypt() call, reported by
+  // the callback. The decrypted result of |encrypted_input| should be
+  // |decrypted_output|.
+  void ExpectSuccessfulDecryption(D3D11CryptoSessionMock* crypto_session_mock,
+                                  D3D11BufferMock* staging_buffer1,
+                                  D3D11BufferMock* staging_buffer2,
+                                  D3D11BufferMock* gpu_buffer,
+                                  base::span<const uint8_t> input,
+                                  base::span<const uint8_t> encrypted_input,
+                                  base::span<const uint8_t> whole_output,
+                                  base::span<const uint8_t> decrypted_output,
+                                  const std::vector<SubsampleEntry>& subsamples,
+                                  D3D11Decryptor* decryptor) {
+    D3D11_MAPPED_SUBRESOURCE staging_buffer1_subresource = {};
+    auto staging_buffer1_subresource_buffer =
+        std::make_unique<uint8_t[]>(20000);
+    staging_buffer1_subresource.pData =
+        staging_buffer1_subresource_buffer.get();
+
+    // It should be requesting for a memory mapped buffer, from the staging
+    // buffer, to pass the encrypted data to the GPU.
+    EXPECT_CALL(*device_context_mock_.Get(),
+                Map(staging_buffer1, 0, D3D11_MAP_WRITE, _, _))
+        .WillOnce(
+            DoAll(SetArgPointee<4>(staging_buffer1_subresource), Return(S_OK)));
+    EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer1, 0));
+
+    EXPECT_CALL(
+        *video_context_mock_.Get(),
+        DecryptionBlt(crypto_session_mock,
+                      reinterpret_cast<ID3D11Texture2D*>(staging_buffer1),
+                      reinterpret_cast<ID3D11Texture2D*>(gpu_buffer),
+                      NumEncryptedBytesAtBeginningEquals(1u),
+                      sizeof(kAnyKeyBlob), kAnyKeyBlob, _, _));
+    EXPECT_CALL(*device_context_mock_.Get(),
+                CopyResource(staging_buffer2, gpu_buffer));
+
+    D3D11_MAPPED_SUBRESOURCE staging_buffer2_subresource = {};
+
+    // pData field is non-const void* so make a copy of kFakeDecryptedData that
+    // can be cast to void*.
+    std::unique_ptr<uint8_t[]> decrypted_data =
+        std::make_unique<uint8_t[]>(decrypted_output.size());
+    memcpy(decrypted_data.get(), decrypted_output.data(),
+           decrypted_output.size());
+    staging_buffer2_subresource.pData = decrypted_data.get();
+
+    // Tt should be requesting for a memory mapped buffer, from the staging
+    // buffer, to read the decrypted data out from the GPU buffer.
+    EXPECT_CALL(*device_context_mock_.Get(),
+                Map(staging_buffer2, 0, D3D11_MAP_READ, _, _))
+        .WillOnce(
+            DoAll(SetArgPointee<4>(staging_buffer2_subresource), Return(S_OK)));
+    EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer2, 0));
+
+    CallbackMock callbacks;
+    EXPECT_CALL(callbacks,
+                DecryptCallback(Decryptor::kSuccess,
+                                OutputDataEquals(whole_output.data(),
+                                                 whole_output.size())));
+
+    scoped_refptr<DecoderBuffer> encrypted_buffer =
+        TestDecoderBuffer(input.data(), input.size(), kKeyId, kIv, subsamples);
+    decryptor->Decrypt(Decryptor::kAudio, encrypted_buffer,
+                       base::BindRepeating(&CallbackMock::DecryptCallback,
+                                           base::Unretained(&callbacks)));
+
+    // Verify that the data copied to the GPU buffer is the encrypted portion.
+    EXPECT_TRUE(std::equal(encrypted_input.begin(), encrypted_input.end(),
+                           staging_buffer1_subresource_buffer.get()));
+  }
+
   std::unique_ptr<D3D11Decryptor> decryptor_;
   CdmProxyContextMock mock_proxy_;
 
@@ -146,9 +284,6 @@
   };
   static_assert(base::size(kFakeDecryptedData) == base::size(kInput),
                 "Fake input and output data size must match.");
-  const std::string kKeyId = "some 16 byte id.";
-  const std::string kIv = "some 16 byte iv.";
-  const uint8_t kAnyKeyBlob[] = {3, 5, 38, 19};
 
   CdmProxyContext::D3D11DecryptContext decrypt_context = {};
   ComPtr<D3D11CryptoSessionMock> crypto_session_mock =
@@ -158,95 +293,20 @@
   decrypt_context.key_blob_size = base::size(kAnyKeyBlob);
   decrypt_context.key_info_guid = TEST_GUID;
 
-  EXPECT_CALL(*crypto_session_mock.Get(), GetDevice(_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_mock_.Get()));
-  EXPECT_CALL(*device_mock_.Get(), GetImmediateContext(_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_context_mock_.Get()));
-
-  EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
-      .WillOnce(Return(decrypt_context));
-
-  EXPECT_CALL(*device_context_mock_.Get(),
-              QueryInterface(IID_ID3D11VideoContext, _))
-      .Times(AtLeast(1))
-      .WillRepeatedly(DoAll(
-          AddRefAndSetArgPointee<1>(video_context_mock_.Get()), Return(S_OK)));
-
   ComPtr<D3D11BufferMock> staging_buffer1 = CreateD3D11Mock<D3D11BufferMock>();
   ComPtr<D3D11BufferMock> staging_buffer2 = CreateD3D11Mock<D3D11BufferMock>();
   ComPtr<D3D11BufferMock> gpu_buffer = CreateD3D11Mock<D3D11BufferMock>();
-  // These return big enough size.
-  ON_CALL(*staging_buffer1.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
-  ON_CALL(*staging_buffer2.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
-  ON_CALL(*gpu_buffer.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
 
-  EXPECT_CALL(*device_mock_.Get(),
-              CreateBuffer(
-                  BufferDescHas(D3D11_USAGE_STAGING, 0u,
-                                D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE),
-                  nullptr, _))
-      .WillOnce(
-          DoAll(AddRefAndSetArgPointee<2>(staging_buffer1.Get()), Return(S_OK)))
-      .WillOnce(DoAll(AddRefAndSetArgPointee<2>(staging_buffer2.Get()),
-                      Return(S_OK)));
-  EXPECT_CALL(*device_mock_.Get(),
-              CreateBuffer(BufferDescHas(D3D11_USAGE_DEFAULT,
-                                         D3D11_BIND_RENDER_TARGET, 0u),
-                           nullptr, _))
-      .WillOnce(
-          DoAll(AddRefAndSetArgPointee<2>(gpu_buffer.Get()), Return(S_OK)));
+  SetExpectationsForSuccessfulBufferInitialization(
+      crypto_session_mock.Get(), staging_buffer1.Get(), staging_buffer2.Get(),
+      gpu_buffer.Get(), &decrypt_context);
 
-  D3D11_MAPPED_SUBRESOURCE staging_buffer1_subresource = {};
-  auto staging_buffer1_subresource_buffer = std::make_unique<uint8_t[]>(20000);
-  staging_buffer1_subresource.pData = staging_buffer1_subresource_buffer.get();
-  EXPECT_CALL(*device_context_mock_.Get(),
-              Map(staging_buffer1.Get(), 0, D3D11_MAP_WRITE, _, _))
-      .WillOnce(
-          DoAll(SetArgPointee<4>(staging_buffer1_subresource), Return(S_OK)));
-  EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer1.Get(), 0));
-
-  EXPECT_CALL(
-      *video_context_mock_.Get(),
-      DecryptionBlt(crypto_session_mock.Get(),
-                    reinterpret_cast<ID3D11Texture2D*>(staging_buffer1.Get()),
-                    reinterpret_cast<ID3D11Texture2D*>(gpu_buffer.Get()),
-                    NumEncryptedBytesAtBeginningEquals(1u), sizeof(kAnyKeyBlob),
-                    kAnyKeyBlob, _, _));
-  EXPECT_CALL(*device_context_mock_.Get(),
-              CopyResource(staging_buffer2.Get(), gpu_buffer.Get()));
-
-  D3D11_MAPPED_SUBRESOURCE staging_buffer2_subresource = {};
-
-  // pData field is non-const void* so make a copy of kFakeDecryptedData that
-  // can be cast to void*.
-  std::unique_ptr<uint8_t[]> decrypted_data =
-      std::make_unique<uint8_t[]>(base::size(kFakeDecryptedData));
-  memcpy(decrypted_data.get(), kFakeDecryptedData,
-         base::size(kFakeDecryptedData));
-
-  staging_buffer2_subresource.pData = decrypted_data.get();
-  EXPECT_CALL(*device_context_mock_.Get(),
-              Map(staging_buffer2.Get(), 0, D3D11_MAP_READ, _, _))
-      .WillOnce(
-          DoAll(SetArgPointee<4>(staging_buffer2_subresource), Return(S_OK)));
-  EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer2.Get(), 0));
-
-  CallbackMock callbacks;
-  EXPECT_CALL(callbacks, DecryptCallback(
-                             Decryptor::kSuccess,
-                             OutputDataEquals(kFakeDecryptedData,
-                                              base::size(kFakeDecryptedData))));
-
-  scoped_refptr<DecoderBuffer> encrypted_buffer =
-      TestDecoderBuffer(kInput, base::size(kInput), kKeyId, kIv, kSubsample);
-  decryptor_->Decrypt(Decryptor::kAudio, encrypted_buffer,
-                      base::BindRepeating(&CallbackMock::DecryptCallback,
-                                          base::Unretained(&callbacks)));
+  // The entire sample is encrypted so the encrypted/decrypted portions are the
+  // input/output.
+  ExpectSuccessfulDecryption(crypto_session_mock.Get(), staging_buffer1.Get(),
+                             staging_buffer2.Get(), gpu_buffer.Get(), kInput,
+                             kInput, kFakeDecryptedData, kFakeDecryptedData,
+                             {kSubsample}, decryptor_.get());
 }
 
 // Verify subsample decryption works.
@@ -288,9 +348,6 @@
                 "Fake input and output data size must match.");
   const std::vector<SubsampleEntry> subsamples = {SubsampleEntry(16, 16),
                                                   SubsampleEntry(5, 16)};
-  const std::string kKeyId = "some 16 byte id.";
-  const std::string kIv = "some 16 byte iv.";
-  const uint8_t kAnyKeyBlob[] = {3, 5, 38, 19};
 
   CdmProxyContext::D3D11DecryptContext decrypt_context = {};
   ComPtr<D3D11CryptoSessionMock> crypto_session_mock =
@@ -300,100 +357,18 @@
   decrypt_context.key_blob_size = base::size(kAnyKeyBlob);
   decrypt_context.key_info_guid = TEST_GUID;
 
-  EXPECT_CALL(*crypto_session_mock.Get(), GetDevice(_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_mock_.Get()));
-  EXPECT_CALL(*device_mock_.Get(), GetImmediateContext(_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_context_mock_.Get()));
-
-  EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
-      .WillOnce(Return(decrypt_context));
-
-  EXPECT_CALL(*device_context_mock_.Get(),
-              QueryInterface(IID_ID3D11VideoContext, _))
-      .Times(AtLeast(1))
-      .WillRepeatedly(DoAll(
-          AddRefAndSetArgPointee<1>(video_context_mock_.Get()), Return(S_OK)));
-
   ComPtr<D3D11BufferMock> staging_buffer1 = CreateD3D11Mock<D3D11BufferMock>();
   ComPtr<D3D11BufferMock> staging_buffer2 = CreateD3D11Mock<D3D11BufferMock>();
   ComPtr<D3D11BufferMock> gpu_buffer = CreateD3D11Mock<D3D11BufferMock>();
-  // These return big enough size.
-  ON_CALL(*staging_buffer1.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
-  ON_CALL(*staging_buffer2.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
-  ON_CALL(*gpu_buffer.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
 
-  EXPECT_CALL(*device_mock_.Get(),
-              CreateBuffer(
-                  BufferDescHas(D3D11_USAGE_STAGING, 0u,
-                                D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE),
-                  nullptr, _))
-      .WillOnce(
-          DoAll(AddRefAndSetArgPointee<2>(staging_buffer1.Get()), Return(S_OK)))
-      .WillOnce(DoAll(AddRefAndSetArgPointee<2>(staging_buffer2.Get()),
-                      Return(S_OK)));
-  EXPECT_CALL(*device_mock_.Get(),
-              CreateBuffer(BufferDescHas(D3D11_USAGE_DEFAULT,
-                                         D3D11_BIND_RENDER_TARGET, 0u),
-                           nullptr, _))
-      .WillOnce(
-          DoAll(AddRefAndSetArgPointee<2>(gpu_buffer.Get()), Return(S_OK)));
+  SetExpectationsForSuccessfulBufferInitialization(
+      crypto_session_mock.Get(), staging_buffer1.Get(), staging_buffer2.Get(),
+      gpu_buffer.Get(), &decrypt_context);
 
-  D3D11_MAPPED_SUBRESOURCE staging_buffer1_subresource = {};
-  auto staging_buffer1_subresource_buffer = std::make_unique<uint8_t[]>(20000);
-  staging_buffer1_subresource.pData = staging_buffer1_subresource_buffer.get();
-  EXPECT_CALL(*device_context_mock_.Get(),
-              Map(staging_buffer1.Get(), 0, D3D11_MAP_WRITE, _, _))
-      .WillOnce(
-          DoAll(SetArgPointee<4>(staging_buffer1_subresource), Return(S_OK)));
-  EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer1.Get(), 0));
-
-  EXPECT_CALL(
-      *video_context_mock_.Get(),
-      DecryptionBlt(crypto_session_mock.Get(),
-                    reinterpret_cast<ID3D11Texture2D*>(staging_buffer1.Get()),
-                    reinterpret_cast<ID3D11Texture2D*>(gpu_buffer.Get()),
-                    NumEncryptedBytesAtBeginningEquals(1u), sizeof(kAnyKeyBlob),
-                    kAnyKeyBlob, _, _));
-  EXPECT_CALL(*device_context_mock_.Get(),
-              CopyResource(staging_buffer2.Get(), gpu_buffer.Get()));
-
-  D3D11_MAPPED_SUBRESOURCE staging_buffer2_subresource = {};
-
-  // pData field is non-const void* so make a oc kFakeDecryptedData that can be
-  // cast to void*.
-  std::unique_ptr<uint8_t[]> decrypted_data =
-      std::make_unique<uint8_t[]>(base::size(kFakeDecryptedData));
-  memcpy(decrypted_data.get(), kFakeDecryptedData,
-         base::size(kFakeDecryptedData));
-
-  staging_buffer2_subresource.pData = decrypted_data.get();
-  EXPECT_CALL(*device_context_mock_.Get(),
-              Map(staging_buffer2.Get(), 0, D3D11_MAP_READ, _, _))
-      .WillOnce(
-          DoAll(SetArgPointee<4>(staging_buffer2_subresource), Return(S_OK)));
-  EXPECT_CALL(*device_context_mock_.Get(), Unmap(staging_buffer2.Get(), 0));
-
-  CallbackMock callbacks;
-  EXPECT_CALL(callbacks,
-              DecryptCallback(Decryptor::kSuccess,
-                              OutputDataEquals(kFakeOutputData,
-                                               base::size(kFakeOutputData))));
-
-  scoped_refptr<DecoderBuffer> encrypted_buffer =
-      DecoderBuffer::CopyFrom(kInput, base::size(kInput));
-  encrypted_buffer->set_decrypt_config(
-      DecryptConfig::CreateCencConfig(kKeyId, kIv, subsamples));
-  encrypted_buffer->set_timestamp(kTestTimestamp);
-  decryptor_->Decrypt(Decryptor::kAudio, encrypted_buffer,
-                      base::BindRepeating(&CallbackMock::DecryptCallback,
-                                          base::Unretained(&callbacks)));
-  EXPECT_EQ(0, memcmp(staging_buffer1_subresource_buffer.get(), kInputEncrypted,
-                      base::size(kInputEncrypted)));
+  ExpectSuccessfulDecryption(crypto_session_mock.Get(), staging_buffer1.Get(),
+                             staging_buffer2.Get(), gpu_buffer.Get(), kInput,
+                             kInputEncrypted, kFakeOutputData,
+                             kFakeDecryptedData, subsamples, decryptor_.get());
 }
 
 // Verify that if the input is too big, it fails. This may be removed if the
@@ -403,9 +378,6 @@
   // matter.
   std::array<uint8_t, 1000000> kInput;
   const SubsampleEntry kSubsample(0, base::size(kInput));
-  const std::string kKeyId = "some 16 byte id.";
-  const std::string kIv = "some 16 byte iv.";
-  const uint8_t kAnyKeyBlob[] = {3, 5, 38, 19};
 
   CdmProxyContext::D3D11DecryptContext decrypt_context = {};
   ComPtr<D3D11CryptoSessionMock> crypto_session_mock =
@@ -414,49 +386,20 @@
   decrypt_context.key_blob = kAnyKeyBlob;
   decrypt_context.key_blob_size = base::size(kAnyKeyBlob);
   decrypt_context.key_info_guid = TEST_GUID;
-  ON_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
-      .WillByDefault(Return(decrypt_context));
-
-  EXPECT_CALL(*crypto_session_mock.Get(), GetDevice(_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_mock_.Get()));
-  EXPECT_CALL(*device_mock_.Get(), GetImmediateContext(_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_context_mock_.Get()));
 
   ComPtr<D3D11BufferMock> staging_buffer1 = CreateD3D11Mock<D3D11BufferMock>();
   ComPtr<D3D11BufferMock> staging_buffer2 = CreateD3D11Mock<D3D11BufferMock>();
   ComPtr<D3D11BufferMock> gpu_buffer = CreateD3D11Mock<D3D11BufferMock>();
-  // These values must be smaller than the input size. Which triggers the
-  // function to fail.
-  ON_CALL(*staging_buffer1.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
-  ON_CALL(*staging_buffer2.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
-  ON_CALL(*gpu_buffer.Get(), GetDesc(_))
-      .WillByDefault(SetBufferDescSize(20000));
 
-  EXPECT_CALL(*device_mock_.Get(),
-              CreateBuffer(
-                  BufferDescHas(D3D11_USAGE_STAGING, 0u,
-                                D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE),
-                  nullptr, _))
-      .WillOnce(
-          DoAll(AddRefAndSetArgPointee<2>(staging_buffer1.Get()), Return(S_OK)))
-      .WillOnce(DoAll(AddRefAndSetArgPointee<2>(staging_buffer2.Get()),
-                      Return(S_OK)));
-  EXPECT_CALL(*device_mock_.Get(),
-              CreateBuffer(BufferDescHas(D3D11_USAGE_DEFAULT,
-                                         D3D11_BIND_RENDER_TARGET, 0u),
-                           nullptr, _))
-      .WillOnce(
-          DoAll(AddRefAndSetArgPointee<2>(gpu_buffer.Get()), Return(S_OK)));
+  SetExpectationsForSuccessfulBufferInitialization(
+      crypto_session_mock.Get(), staging_buffer1.Get(), staging_buffer2.Get(),
+      gpu_buffer.Get(), &decrypt_context);
 
   CallbackMock callbacks;
   EXPECT_CALL(callbacks, DecryptCallback(Decryptor::kError, IsNull()));
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = TestDecoderBuffer(
-      kInput.data(), base::size(kInput), kKeyId, kIv, kSubsample);
+      kInput.data(), base::size(kInput), kKeyId, kIv, {kSubsample});
   decryptor_->Decrypt(Decryptor::kAudio, encrypted_buffer,
                       base::BindRepeating(&CallbackMock::DecryptCallback,
                                           base::Unretained(&callbacks)));
@@ -485,8 +428,6 @@
   const uint8_t kInput[] = {
       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
   };
-  const std::string kKeyId = "some 16 byte id.";
-  const std::string kIv = "some 16 byte iv.";
   scoped_refptr<DecoderBuffer> encrypted_buffer =
       DecoderBuffer::CopyFrom(kInput, base::size(kInput));
   std::vector<SubsampleEntry> subsamples = {SubsampleEntry(0, 16)};
@@ -506,10 +447,8 @@
       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
   };
   const SubsampleEntry kSubsample(0, base::size(kInput));
-  const std::string kKeyId = "some 16 byte id.";
-  const std::string kIv = "some 16 byte iv.";
   scoped_refptr<DecoderBuffer> encrypted_buffer =
-      TestDecoderBuffer(kInput, base::size(kInput), kKeyId, kIv, kSubsample);
+      TestDecoderBuffer(kInput, base::size(kInput), kKeyId, kIv, {kSubsample});
 
   EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
       .WillOnce(Return(base::nullopt));
@@ -521,4 +460,57 @@
                                           base::Unretained(&callbacks)));
 }
 
+// Verify that if the crypto session's device is the same as the previous call,
+// the buffers aren't recreated.
+TEST_F(D3D11DecryptorTest, ReuseBuffers) {
+  const uint8_t kInput[] = {
+      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+  };
+  const SubsampleEntry kSubsample(0, base::size(kInput));
+
+  CdmProxyContext::D3D11DecryptContext decrypt_context = {};
+  ComPtr<D3D11CryptoSessionMock> crypto_session_mock =
+      CreateD3D11Mock<D3D11CryptoSessionMock>();
+  decrypt_context.crypto_session = crypto_session_mock.Get();
+  decrypt_context.key_blob = kAnyKeyBlob;
+  decrypt_context.key_blob_size = base::size(kAnyKeyBlob);
+  decrypt_context.key_info_guid = TEST_GUID;
+
+  ComPtr<D3D11BufferMock> staging_buffer1 = CreateD3D11Mock<D3D11BufferMock>();
+  ComPtr<D3D11BufferMock> staging_buffer2 = CreateD3D11Mock<D3D11BufferMock>();
+  ComPtr<D3D11BufferMock> gpu_buffer = CreateD3D11Mock<D3D11BufferMock>();
+
+  SetExpectationsForSuccessfulBufferInitialization(
+      crypto_session_mock.Get(), staging_buffer1.Get(), staging_buffer2.Get(),
+      gpu_buffer.Get(), &decrypt_context);
+
+  // This test doesn't require checking the output or the correctness of the
+  // decyrption, so just pass the input buffer for output.
+  ExpectSuccessfulDecryption(crypto_session_mock.Get(), staging_buffer1.Get(),
+                             staging_buffer2.Get(), gpu_buffer.Get(), kInput,
+                             kInput, kInput, kInput, {kSubsample},
+                             decryptor_.get());
+  Mock::VerifyAndClearExpectations(crypto_session_mock.Get());
+  Mock::VerifyAndClearExpectations(device_mock_.Get());
+  Mock::VerifyAndClearExpectations(video_context_mock_.Get());
+  Mock::VerifyAndClearExpectations(device_context_mock_.Get());
+  Mock::VerifyAndClearExpectations(&mock_proxy_);
+
+  EXPECT_CALL(*crypto_session_mock.Get(), GetDevice(_))
+      .Times(AtLeast(1))
+      .WillRepeatedly(AddRefAndSetArgPointee<0>(device_mock_.Get()));
+  EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
+      .WillOnce(Return(decrypt_context));
+
+  // Buffers should not be (re)initialized on the next call to decrypt because
+  // it's the same device as the previous call.
+  EXPECT_CALL(*device_mock_.Get(), CreateBuffer(_, _, _)).Times(0);
+
+  // This calls Decrypt() so that the expectations above are triggered.
+  ExpectSuccessfulDecryption(crypto_session_mock.Get(), staging_buffer1.Get(),
+                             staging_buffer2.Get(), gpu_buffer.Get(), kInput,
+                             kInput, kInput, kInput, {kSubsample},
+                             decryptor_.get());
+}
+
 }  // namespace media
diff --git a/net/BUILD.gn b/net/BUILD.gn
index d6b84c9..140a294 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1337,6 +1337,8 @@
       "third_party/quic/core/frames/quic_goaway_frame.h",
       "third_party/quic/core/frames/quic_max_stream_id_frame.cc",
       "third_party/quic/core/frames/quic_max_stream_id_frame.h",
+      "third_party/quic/core/frames/quic_message_frame.cc",
+      "third_party/quic/core/frames/quic_message_frame.h",
       "third_party/quic/core/frames/quic_mtu_discovery_frame.h",
       "third_party/quic/core/frames/quic_new_connection_id_frame.cc",
       "third_party/quic/core/frames/quic_new_connection_id_frame.h",
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index d0410ac..a8e8bd1 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -353,7 +353,6 @@
     deps = [
       "//base",
       "//net",
-      "//net:net_with_v8",
     ]
 
     public_deps = [
diff --git a/net/features.gni b/net/features.gni
index 49c6dcd8..59352fa4 100644
--- a/net/features.gni
+++ b/net/features.gni
@@ -42,5 +42,5 @@
 }
 
 declare_args() {
-  enable_net_mojo = !is_ios && !is_proto_quic
+  enable_net_mojo = !is_proto_quic
 }
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 63b3185..648ace6 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -393,6 +393,7 @@
     case CONNECTION_INFO_QUIC_42:
     case CONNECTION_INFO_QUIC_43:
     case CONNECTION_INFO_QUIC_44:
+    case CONNECTION_INFO_QUIC_45:
     case CONNECTION_INFO_QUIC_99:
       return true;
     case NUM_OF_CONNECTION_INFOS:
@@ -452,6 +453,8 @@
       return "http/2+quic/43";
     case CONNECTION_INFO_QUIC_44:
       return "http/2+quic/44";
+    case CONNECTION_INFO_QUIC_45:
+      return "http/2+quic/45";
     case CONNECTION_INFO_QUIC_99:
       return "http/2+quic/99";
     case CONNECTION_INFO_HTTP0_9:
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index 0c7e4a4b..bac2637 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -57,6 +57,7 @@
     CONNECTION_INFO_QUIC_43 = 21,
     CONNECTION_INFO_QUIC_99 = 22,
     CONNECTION_INFO_QUIC_44 = 23,
+    CONNECTION_INFO_QUIC_45 = 24,
     NUM_OF_CONNECTION_INFOS,
   };
 
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 0c8d332..aca1b2a 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -896,7 +896,6 @@
     { "name": "vmoagents.com", "policy": "custom", "mode": "force-https" },
     { "name": "pult.co", "policy": "custom", "mode": "force-https" },
     { "name": "www.eternalgoth.co.uk", "policy": "custom", "mode": "force-https" },
-    { "name": "airbnb.com", "policy": "custom", "mode": "force-https" },
     { "name": "usaa.com", "policy": "custom", "mode": "force-https" },
     { "name": "www.usaa.com", "policy": "custom", "mode": "force-https" },
     { "name": "mobile.usaa.com", "policy": "custom", "mode": "force-https" },
@@ -1123,7 +1122,6 @@
     { "name": "harvestapp.com", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
     { "name": "anycoin.me", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
     { "name": "noexpect.org", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
-    { "name": "www.airbnb.com", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
     { "name": "subrosa.io", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
     { "name": "manageprojects.com", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
     { "name": "vocaloid.my", "policy": "bulk-legacy", "mode": "force-https", "include_subdomains": true },
@@ -57882,6 +57880,8 @@
     { "name": "aka.ms", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     { "name": "go.microsoft.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     { "name": "typewritten.net", "policy": "custom", "mode": "force-https", "include_subdomains": true },
+    { "name": "airbnb.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
+    { "name": "airbnb.tools", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     // IP Address
     { "name": "1.0.0.1", "policy": "custom", "mode": "force-https", "include_subdomains": false },
     // No subdomains
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index d784566..ff2be3a 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -229,3 +229,12 @@
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_stop_reading_when_level_triggered,
           false)
+
+// If true, mark packets for loss retransmission even they do not contain
+// retransmittable frames.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_fix_mark_for_loss_retransmission,
+          false)
+
+// If true, enable version 45.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_45, false)
\ No newline at end of file
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 22b105f..13a2d9aa 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -88,6 +88,8 @@
       return HttpResponseInfo::CONNECTION_INFO_QUIC_43;
     case quic::QUIC_VERSION_44:
       return HttpResponseInfo::CONNECTION_INFO_QUIC_44;
+    case quic::QUIC_VERSION_45:
+      return HttpResponseInfo::CONNECTION_INFO_QUIC_45;
     case quic::QUIC_VERSION_99:
       return HttpResponseInfo::CONNECTION_INFO_QUIC_99;
   }
diff --git a/net/test/run_all_unittests.cc b/net/test/run_all_unittests.cc
index 5786dfe..3e3eaf9e 100644
--- a/net/test/run_all_unittests.cc
+++ b/net/test/run_all_unittests.cc
@@ -11,10 +11,7 @@
 #include "net/socket/client_socket_pool_base.h"
 #include "net/test/net_test_suite.h"
 #include "url/url_features.h"
-
-#if !defined(OS_IOS)
 #include "mojo/core/embedder/embedder.h"  // nogncheck
-#endif
 
 using net::internal::ClientSocketPoolBaseHelper;
 
@@ -57,9 +54,7 @@
   NetTestSuite test_suite(argc, argv);
   ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(false);
 
-#if !defined(OS_IOS)
   mojo::core::Init();
-#endif
 
   return base::LaunchUnitTests(
       argc, argv, base::Bind(&NetTestSuite::Run,
diff --git a/net/third_party/quic/core/chlo_extractor.cc b/net/third_party/quic/core/chlo_extractor.cc
index 3fc898b..60ac9654 100644
--- a/net/third_party/quic/core/chlo_extractor.cc
+++ b/net/third_party/quic/core/chlo_extractor.cc
@@ -58,6 +58,7 @@
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
   bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
+  bool OnMessageFrame(const QuicMessageFrame& frame) override;
   void OnPacketComplete() override {}
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
@@ -208,6 +209,10 @@
   return true;
 }
 
+bool ChloFramerVisitor::OnMessageFrame(const QuicMessageFrame& frame) {
+  return true;
+}
+
 bool ChloFramerVisitor::IsValidStatelessResetToken(QuicUint128 token) const {
   return false;
 }
diff --git a/net/third_party/quic/core/frames/quic_frame.cc b/net/third_party/quic/core/frames/quic_frame.cc
index 6378515..6a1902a 100644
--- a/net/third_party/quic/core/frames/quic_frame.cc
+++ b/net/third_party/quic/core/frames/quic_frame.cc
@@ -66,6 +66,9 @@
 QuicFrame::QuicFrame(QuicStopSendingFrame* frame)
     : type(STOP_SENDING_FRAME), stop_sending_frame(frame) {}
 
+QuicFrame::QuicFrame(QuicMessageFrame* frame)
+    : type(MESSAGE_FRAME), message_frame(frame) {}
+
 void DeleteFrames(QuicFrames* frames) {
   for (QuicFrame& frame : *frames) {
     DeleteFrame(&frame);
@@ -119,6 +122,9 @@
     case PATH_RESPONSE_FRAME:
       delete frame->path_response_frame;
       break;
+    case MESSAGE_FRAME:
+      delete frame->message_frame;
+      break;
 
     case NUM_FRAME_TYPES:
       DCHECK(false) << "Cannot delete type: " << frame->type;
@@ -295,6 +301,9 @@
     case STOP_SENDING_FRAME:
       os << "type { STOP_SENDING } " << *(frame.stop_sending_frame);
       break;
+    case MESSAGE_FRAME:
+      os << "type { MESSAGE_FRAME }" << *(frame.message_frame);
+      break;
     default: {
       QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type;
       break;
diff --git a/net/third_party/quic/core/frames/quic_frame.h b/net/third_party/quic/core/frames/quic_frame.h
index cf1a1fb..ab712a9b 100644
--- a/net/third_party/quic/core/frames/quic_frame.h
+++ b/net/third_party/quic/core/frames/quic_frame.h
@@ -14,6 +14,7 @@
 #include "net/third_party/quic/core/frames/quic_connection_close_frame.h"
 #include "net/third_party/quic/core/frames/quic_goaway_frame.h"
 #include "net/third_party/quic/core/frames/quic_max_stream_id_frame.h"
+#include "net/third_party/quic/core/frames/quic_message_frame.h"
 #include "net/third_party/quic/core/frames/quic_mtu_discovery_frame.h"
 #include "net/third_party/quic/core/frames/quic_new_connection_id_frame.h"
 #include "net/third_party/quic/core/frames/quic_padding_frame.h"
@@ -54,6 +55,7 @@
   explicit QuicFrame(QuicPathResponseFrame* frame);
   explicit QuicFrame(QuicPathChallengeFrame* frame);
   explicit QuicFrame(QuicStopSendingFrame* frame);
+  explicit QuicFrame(QuicMessageFrame* message_frame);
 
   QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
                                                       const QuicFrame& frame);
@@ -91,6 +93,7 @@
         QuicPathResponseFrame* path_response_frame;
         QuicPathChallengeFrame* path_challenge_frame;
         QuicStopSendingFrame* stop_sending_frame;
+        QuicMessageFrame* message_frame;
       };
     };
   };
diff --git a/net/third_party/quic/core/frames/quic_message_frame.cc b/net/third_party/quic/core/frames/quic_message_frame.cc
new file mode 100644
index 0000000..7c686c5
--- /dev/null
+++ b/net/third_party/quic/core/frames/quic_message_frame.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 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 "net/third_party/quic/core/frames/quic_message_frame.h"
+
+#include "net/third_party/quic/core/quic_constants.h"
+#include "net/third_party/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicMessageFrame::QuicMessageFrame() : message_id(0) {}
+
+QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id,
+                                   QuicStringPiece message_data)
+    : message_id(message_id), message_data(message_data) {}
+
+QuicMessageFrame::~QuicMessageFrame() {}
+
+std::ostream& operator<<(std::ostream& os, const QuicMessageFrame& s) {
+  os << " message_id: " << s.message_id
+     << ", message_length: " << s.message_data.length() << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/net/third_party/quic/core/frames/quic_message_frame.h b/net/third_party/quic/core/frames/quic_message_frame.h
new file mode 100644
index 0000000..83d7808
--- /dev/null
+++ b/net/third_party/quic/core/frames/quic_message_frame.h
@@ -0,0 +1,32 @@
+// Copyright (c) 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 NET_THIRD_PARTY_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
+#define NET_THIRD_PARTY_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
+
+#include "net/third_party/quic/core/quic_types.h"
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicMessageFrame {
+  QuicMessageFrame();
+  QuicMessageFrame(QuicMessageId message_id, QuicStringPiece message_data);
+  ~QuicMessageFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicMessageFrame& s);
+
+  // message_id is only used on the sender side and does not get serialized on
+  // wire.
+  QuicMessageId message_id;
+  // The actual data is not owned.
+  QuicStringPiece message_data;
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
diff --git a/net/third_party/quic/core/http/end_to_end_test.cc b/net/third_party/quic/core/http/end_to_end_test.cc
index b73cb288..b4ddb1f 100644
--- a/net/third_party/quic/core/http/end_to_end_test.cc
+++ b/net/third_party/quic/core/http/end_to_end_test.cc
@@ -3216,6 +3216,58 @@
   EXPECT_EQ(QUIC_STREAM_TTL_EXPIRED, client_->stream_error());
 }
 
+TEST_P(EndToEndTest, SendMessages) {
+  SetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission, true);
+  ASSERT_TRUE(Initialize());
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+  QuicSession* client_session = client_->client()->client_session();
+  QuicConnection* client_connection = client_session->connection();
+  if (client_connection->transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+
+  SetPacketLossPercentage(30);
+  ASSERT_GT(kMaxPacketSize, client_session->GetLargestMessagePayload());
+  ASSERT_LT(0, client_session->GetLargestMessagePayload());
+
+  QuicString message_string(kMaxPacketSize, 'a');
+  QuicStringPiece message_buffer(message_string);
+  QuicRandom* random =
+      QuicConnectionPeer::GetHelper(client_connection)->GetRandomGenerator();
+  {
+    QuicConnection::ScopedPacketFlusher flusher(
+        client_session->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+    // Verify the largest message gets successfully sent.
+    EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1),
+              client_session->SendMessage(
+                  QuicStringPiece(message_buffer.data(),
+                                  client_session->GetLargestMessagePayload())));
+    // Send more messages with size (0, largest_payload] until connection is
+    // write blocked.
+    const int kTestMaxNumberOfMessages = 100;
+    for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) {
+      size_t message_length =
+          random->RandUint64() % client_session->GetLargestMessagePayload() + 1;
+      MessageResult result = client_session->SendMessage(
+          QuicStringPiece(message_buffer.data(), message_length));
+      if (result.status == MESSAGE_STATUS_BLOCKED) {
+        // Connection is write blocked.
+        break;
+      }
+      EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, i), result);
+    }
+  }
+
+  client_->WaitForDelayedAcks();
+  EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE,
+            client_session
+                ->SendMessage(QuicStringPiece(
+                    message_buffer.data(),
+                    client_session->GetLargestMessagePayload() + 1))
+                .status);
+  EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
+}
+
 class EndToEndPacketReorderingTest : public EndToEndTest {
  public:
   void CreateClientWithWriter() override {
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc
index 4237b432..d953d76 100644
--- a/net/third_party/quic/core/quic_connection.cc
+++ b/net/third_party/quic/core/quic_connection.cc
@@ -1179,6 +1179,21 @@
   return true;
 }
 
+bool QuicConnection::OnMessageFrame(const QuicMessageFrame& frame) {
+  DCHECK(connected_);
+
+  // Since a message frame was received, this is not a connectivity probe.
+  // A probe only contains a PING and full padding.
+  UpdatePacketContent(NOT_PADDED_PING);
+
+  if (debug_visitor_ != nullptr) {
+    debug_visitor_->OnMessageFrame(frame);
+  }
+  visitor_->OnMessageReceived(frame.message_data);
+  should_last_packet_instigate_acks_ = true;
+  return connected_;
+}
+
 bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
   DCHECK(connected_);
 
@@ -3205,5 +3220,26 @@
               GetQuicFlag(FLAGS_quic_pace_time_into_future_srtt_fraction)));
 }
 
+MessageStatus QuicConnection::SendMessage(QuicMessageId message_id,
+                                          QuicStringPiece message) {
+  if (transport_version() <= QUIC_VERSION_44) {
+    QUIC_BUG << "MESSAGE frame is not supported for version "
+             << transport_version();
+    return MESSAGE_STATUS_UNSUPPORTED;
+  }
+  if (message.length() > GetLargestMessagePayload()) {
+    return MESSAGE_STATUS_TOO_LARGE;
+  }
+  if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+    return MESSAGE_STATUS_BLOCKED;
+  }
+  ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING);
+  return packet_generator_.AddMessageFrame(message_id, message);
+}
+
+QuicPacketLength QuicConnection::GetLargestMessagePayload() const {
+  return packet_generator_.GetLargestMessagePayload();
+}
+
 #undef ENDPOINT  // undef for jumbo builds
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h
index d0bd6612..b7b5c19 100644
--- a/net/third_party/quic/core/quic_connection.h
+++ b/net/third_party/quic/core/quic_connection.h
@@ -110,6 +110,9 @@
   // Called when the connection is going away according to the peer.
   virtual void OnGoAway(const QuicGoAwayFrame& frame) = 0;
 
+  // Called when |message| has been received.
+  virtual void OnMessageReceived(QuicStringPiece message) = 0;
+
   // Called when the connection is closed either locally by the framer, or
   // remotely by the peer.
   virtual void OnConnectionClosed(QuicErrorCode error,
@@ -255,6 +258,9 @@
   // Called when a BlockedFrame has been parsed.
   virtual void OnBlockedFrame(const QuicBlockedFrame& frame) {}
 
+  // Called when a MessageFrame has been parsed.
+  virtual void OnMessageFrame(const QuicMessageFrame& frame) {}
+
   // Called when a public reset packet has been received.
   virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {}
 
@@ -485,6 +491,7 @@
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
   bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
+  bool OnMessageFrame(const QuicMessageFrame& frame) override;
   void OnPacketComplete() override;
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
@@ -713,6 +720,13 @@
   // Set long header type of next sending packets.
   void SetLongHeaderType(QuicLongHeaderType type);
 
+  // Tries to send |message| and returns the message status.
+  virtual MessageStatus SendMessage(QuicMessageId message_id,
+                                    QuicStringPiece message);
+
+  // Returns the largest payload that will fit into a single MESSAGE frame.
+  QuicPacketLength GetLargestMessagePayload() const;
+
   // Return the id of the cipher of the primary decrypter of the framer.
   uint32_t cipher_id() const { return framer_.decrypter()->cipher_id(); }
 
diff --git a/net/third_party/quic/core/quic_connection_test.cc b/net/third_party/quic/core/quic_connection_test.cc
index b8725137..ecfd00b 100644
--- a/net/third_party/quic/core/quic_connection_test.cc
+++ b/net/third_party/quic/core/quic_connection_test.cc
@@ -419,6 +419,10 @@
     return framer_.ping_frames();
   }
 
+  const std::vector<QuicMessageFrame>& message_frames() const {
+    return framer_.message_frames();
+  }
+
   const std::vector<QuicWindowUpdateFrame>& window_update_frames() const {
     return framer_.window_update_frames();
   }
@@ -7058,6 +7062,38 @@
   ProcessAckPacket(1, &frame);
 }
 
+TEST_P(QuicConnectionTest, SendMessage) {
+  if (connection_.transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+  QuicString message(connection_.GetLargestMessagePayload() * 2, 'a');
+  QuicStringPiece message_data(message);
+  {
+    QuicConnection::ScopedPacketFlusher flusher(&connection_,
+                                                QuicConnection::SEND_ACK);
+    connection_.SendStreamData3();
+    // Send a message which cannot fit into current open packet, and 2 packets
+    // get sent, one contains stream frame, and the other only contains the
+    // message frame.
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+    EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
+              connection_.SendMessage(
+                  1, QuicStringPiece(message_data.data(),
+                                     connection_.GetLargestMessagePayload())));
+  }
+  // Fail to send a message if connection is congestion control blocked.
+  EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false));
+  EXPECT_EQ(MESSAGE_STATUS_BLOCKED, connection_.SendMessage(2, "message"));
+
+  // Always fail to send a message which cannot fit into one packet.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+  EXPECT_EQ(
+      MESSAGE_STATUS_TOO_LARGE,
+      connection_.SendMessage(
+          3, QuicStringPiece(message_data.data(),
+                             connection_.GetLargestMessagePayload() + 1)));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_dispatcher.cc b/net/third_party/quic/core/quic_dispatcher.cc
index 590058f..7a7ba076 100644
--- a/net/third_party/quic/core/quic_dispatcher.cc
+++ b/net/third_party/quic/core/quic_dispatcher.cc
@@ -799,6 +799,11 @@
   return false;
 }
 
+bool QuicDispatcher::OnMessageFrame(const QuicMessageFrame& frame) {
+  DCHECK(false);
+  return false;
+}
+
 void QuicDispatcher::OnPacketComplete() {
   DCHECK(false);
 }
diff --git a/net/third_party/quic/core/quic_dispatcher.h b/net/third_party/quic/core/quic_dispatcher.h
index 61c6392..8984e47c 100644
--- a/net/third_party/quic/core/quic_dispatcher.h
+++ b/net/third_party/quic/core/quic_dispatcher.h
@@ -156,6 +156,7 @@
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
   bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
+  bool OnMessageFrame(const QuicMessageFrame& frame) override;
   void OnPacketComplete() override;
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
diff --git a/net/third_party/quic/core/quic_dispatcher_test.cc b/net/third_party/quic/core/quic_dispatcher_test.cc
index 0a43b2e..68c87ae7a 100644
--- a/net/third_party/quic/core/quic_dispatcher_test.cc
+++ b/net/third_party/quic/core/quic_dispatcher_test.cc
@@ -635,11 +635,12 @@
 }
 
 TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 5u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicFlag(&FLAGS_quic_enable_version_99, true);
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
@@ -692,6 +693,39 @@
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
 
+  // Turn off version 45.
+  SetQuicReloadableFlag(quic_enable_version_45, false);
+  ++connection_id;
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq")))
+      .Times(0);
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
+  // Turn on version 45.
+  SetQuicReloadableFlag(quic_enable_version_45, true);
+  ++connection_id;
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq")))
+      .WillOnce(testing::Return(CreateSession(
+          dispatcher_.get(), config_, connection_id, client_address,
+          &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+  EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+              ProcessUdpPacket(_, _, _))
+      .WillOnce(WithArg<2>(
+          Invoke([this, connection_id](const QuicEncryptedPacket& packet) {
+            ValidatePacket(connection_id, packet);
+          })));
+  EXPECT_CALL(*dispatcher_,
+              ShouldCreateOrBufferPacketForConnection(connection_id));
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
   // Turn off version 44.
   SetQuicReloadableFlag(quic_enable_version_44, false);
   ++connection_id;
diff --git a/net/third_party/quic/core/quic_error_codes.cc b/net/third_party/quic/core/quic_error_codes.cc
index 83f6d4d..6178c0e 100644
--- a/net/third_party/quic/core/quic_error_codes.cc
+++ b/net/third_party/quic/core/quic_error_codes.cc
@@ -148,6 +148,7 @@
     RETURN_STRING_LITERAL(QUIC_INVALID_PATH_CHALLENGE_DATA);
     RETURN_STRING_LITERAL(QUIC_INVALID_PATH_RESPONSE_DATA);
     RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED);
+    RETURN_STRING_LITERAL(QUIC_INVALID_MESSAGE_DATA);
     RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
     // Intentionally have no default case, so we'll break the build
     // if we add errors and don't put them here.
diff --git a/net/third_party/quic/core/quic_error_codes.h b/net/third_party/quic/core/quic_error_codes.h
index dc532ad1..0bf21cd 100644
--- a/net/third_party/quic/core/quic_error_codes.h
+++ b/net/third_party/quic/core/quic_error_codes.h
@@ -107,6 +107,8 @@
   QUIC_INVALID_PATH_CLOSE_DATA = 78,
   // ACK frame data is malformed.
   QUIC_INVALID_ACK_DATA = 9,
+  // Message frame data is malformed.
+  QUIC_INVALID_MESSAGE_DATA = 112,
 
   // Version negotiation packet is malformed.
   QUIC_INVALID_VERSION_NEGOTIATION_PACKET = 10,
@@ -304,7 +306,7 @@
   QUIC_INVALID_PATH_RESPONSE_DATA = 110,
 
   // No error. Used as bound while iterating.
-  QUIC_LAST_ERROR = 112,
+  QUIC_LAST_ERROR = 113,
 };
 // QuicErrorCodes is encoded as a single octet on-the-wire.
 static_assert(static_cast<int>(QUIC_LAST_ERROR) <=
diff --git a/net/third_party/quic/core/quic_framer.cc b/net/third_party/quic/core/quic_framer.cc
index f58fe93..890cf46d 100644
--- a/net/third_party/quic/core/quic_framer.cc
+++ b/net/third_party/quic/core/quic_framer.cc
@@ -64,16 +64,20 @@
 // Special Frame Types encode both a Frame Type and corresponding flags
 // all in the Frame Type byte. Currently defined Special Frame Types
 // are:
-// Stream             : 0b 11xxxxxx
-// Ack                : 0b 101xxxxx
+// Stream             : 0b 1xxxxxxx
+// Ack                : 0b 01xxxxxx
 //
 // Semantics of the flag bits above (the x bits) depends on the frame type.
 
 // Masks to determine if the frame type is a special use
 // and for specific special frame types.
-const uint8_t kQuicFrameTypeSpecialMask = 0xE0;  // 0b 11100000
+const uint8_t kQuicFrameTypeBrokenMask = 0xE0;   // 0b 11100000
+const uint8_t kQuicFrameTypeSpecialMask = 0xC0;  // 0b 11000000
 const uint8_t kQuicFrameTypeStreamMask = 0x80;
 const uint8_t kQuicFrameTypeAckMask = 0x40;
+static_assert(kQuicFrameTypeSpecialMask ==
+                  (kQuicFrameTypeStreamMask | kQuicFrameTypeAckMask),
+              "Invalid kQuicFrameTypeSpecialMask");
 
 // The stream type format is 1FDOOOSS, where
 //    F is the fin bit.
@@ -269,6 +273,17 @@
 }
 
 // static
+size_t QuicFramer::GetMessageFrameSize(QuicTransportVersion version,
+                                       bool last_frame_in_packet,
+                                       QuicByteCount length) {
+  QUIC_BUG_IF(version <= QUIC_VERSION_44)
+      << "Try to serialize MESSAGE frame in " << version;
+  return kQuicFrameTypeSize +
+         (last_frame_in_packet ? 0 : QuicDataWriter::GetVarInt62Len(length)) +
+         length;
+}
+
+// static
 size_t QuicFramer::GetMinAckFrameSize(
     QuicTransportVersion version,
     QuicPacketNumberLength largest_observed_length) {
@@ -456,6 +471,7 @@
     case STOP_WAITING_FRAME:
     case MTU_DISCOVERY_FRAME:
     case PADDING_FRAME:
+    case MESSAGE_FRAME:
     case NUM_FRAME_TYPES:
       DCHECK(false);
       return 0;
@@ -610,8 +626,8 @@
   size_t i = 0;
   for (const QuicFrame& frame : frames) {
     // Determine if we should write stream frame length in header.
-    const bool no_stream_frame_length = i == frames.size() - 1;
-    if (!AppendTypeByte(frame, no_stream_frame_length, &writer)) {
+    const bool last_frame_in_packet = i == frames.size() - 1;
+    if (!AppendTypeByte(frame, last_frame_in_packet, &writer)) {
       QUIC_BUG << "AppendTypeByte failed";
       return 0;
     }
@@ -625,7 +641,7 @@
         }
         break;
       case STREAM_FRAME:
-        if (!AppendStreamFrame(frame.stream_frame, no_stream_frame_length,
+        if (!AppendStreamFrame(frame.stream_frame, last_frame_in_packet,
                                &writer)) {
           QUIC_BUG << "AppendStreamFrame failed";
           return 0;
@@ -709,6 +725,13 @@
         set_detailed_error(
             "Attempt to append STOP_SENDING frame and not in version 99.");
         return RaiseError(QUIC_INTERNAL_ERROR);
+      case MESSAGE_FRAME:
+        if (!AppendMessageFrameAndTypeByte(*frame.message_frame,
+                                           last_frame_in_packet, &writer)) {
+          QUIC_BUG << "AppendMessageFrame failed";
+          return 0;
+        }
+        break;
 
       default:
         RaiseError(QUIC_INVALID_FRAME_DATA);
@@ -734,8 +757,8 @@
   size_t i = 0;
   for (const QuicFrame& frame : frames) {
     // Determine if we should write stream frame length in header.
-    const bool no_stream_frame_length = i == frames.size() - 1;
-    if (!AppendIetfTypeByte(frame, no_stream_frame_length, &writer)) {
+    const bool last_frame_in_packet = i == frames.size() - 1;
+    if (!AppendIetfTypeByte(frame, last_frame_in_packet, &writer)) {
       QUIC_BUG << "AppendIetfTypeByte failed";
       return 0;
     }
@@ -749,7 +772,7 @@
         }
         break;
       case STREAM_FRAME:
-        if (!AppendStreamFrame(frame.stream_frame, no_stream_frame_length,
+        if (!AppendStreamFrame(frame.stream_frame, last_frame_in_packet,
                                &writer)) {
           QUIC_BUG << "AppendStreamFrame failed";
           return 0;
@@ -853,6 +876,13 @@
           return 0;
         }
         break;
+      case MESSAGE_FRAME:
+        if (!AppendMessageFrameAndTypeByte(*frame.message_frame,
+                                           last_frame_in_packet, &writer)) {
+          QUIC_BUG << "AppendMessageFrame failed";
+          return 0;
+        }
+        break;
       default:
         RaiseError(QUIC_INVALID_FRAME_DATA);
         QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
@@ -1881,8 +1911,10 @@
       set_detailed_error("Unable to read frame type.");
       return RaiseError(QUIC_INVALID_FRAME_DATA);
     }
-
-    if (frame_type & kQuicFrameTypeSpecialMask) {
+    const uint8_t special_mask = transport_version() <= QUIC_VERSION_44
+                                     ? kQuicFrameTypeBrokenMask
+                                     : kQuicFrameTypeSpecialMask;
+    if (frame_type & special_mask) {
       // Stream Frame
       if (frame_type & kQuicFrameTypeStreamMask) {
         QuicStreamFrame frame;
@@ -2020,6 +2052,23 @@
         }
         continue;
       }
+      case IETF_EXTENSION_MESSAGE_NO_LENGTH:
+        QUIC_FALLTHROUGH_INTENDED;
+      case IETF_EXTENSION_MESSAGE: {
+        QuicMessageFrame message_frame;
+        if (!ProcessMessageFrame(reader,
+                                 frame_type == IETF_EXTENSION_MESSAGE_NO_LENGTH,
+                                 &message_frame)) {
+          return RaiseError(QUIC_INVALID_MESSAGE_DATA);
+        }
+        if (!visitor_->OnMessageFrame(message_frame)) {
+          QUIC_DVLOG(1) << ENDPOINT
+                        << "Visitor asked to stop further processing.";
+          // Returning true since there was no parsing error.
+          return true;
+        }
+        break;
+      }
 
       default:
         set_detailed_error("Illegal frame type.");
@@ -2249,6 +2298,23 @@
           }
           break;
         }
+        case IETF_EXTENSION_MESSAGE_NO_LENGTH:
+          QUIC_FALLTHROUGH_INTENDED;
+        case IETF_EXTENSION_MESSAGE: {
+          QuicMessageFrame message_frame;
+          if (!ProcessMessageFrame(
+                  reader, frame_type == IETF_EXTENSION_MESSAGE_NO_LENGTH,
+                  &message_frame)) {
+            return RaiseError(QUIC_INVALID_MESSAGE_DATA);
+          }
+          if (!visitor_->OnMessageFrame(message_frame)) {
+            QUIC_DVLOG(1) << ENDPOINT
+                          << "Visitor asked to stop further processing.";
+            // Returning true since there was no parsing error.
+            return true;
+          }
+          break;
+        }
 
         default:
           set_detailed_error("Illegal frame type.");
@@ -2851,6 +2917,27 @@
   }
 }
 
+bool QuicFramer::ProcessMessageFrame(QuicDataReader* reader,
+                                     bool no_message_length,
+                                     QuicMessageFrame* frame) {
+  if (no_message_length) {
+    frame->message_data = reader->ReadRemainingPayload();
+    return true;
+  }
+
+  uint64_t message_length;
+  if (!reader->ReadVarInt62(&message_length)) {
+    set_detailed_error("Unable to read message length");
+    return false;
+  }
+  if (!reader->ReadStringPiece(&frame->message_data, message_length)) {
+    set_detailed_error("Unable to read message data");
+    return false;
+  }
+
+  return true;
+}
+
 // static
 QuicStringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
     QuicTransportVersion version,
@@ -3158,6 +3245,10 @@
     case MTU_DISCOVERY_FRAME:
       // MTU discovery frames are serialized as ping frames.
       return kQuicFrameTypeSize;
+    case MESSAGE_FRAME:
+      return GetMessageFrameSize(version_.transport_version,
+                                 last_frame_in_packet,
+                                 frame.message_frame->message_data.length());
     case PADDING_FRAME:
       DCHECK(false);
       return 0;
@@ -3231,6 +3322,8 @@
       set_detailed_error(
           "Attempt to append STOP_SENDING frame and not in version 99.");
       return RaiseError(QUIC_INTERNAL_ERROR);
+    case MESSAGE_FRAME:
+      return true;
 
     default:
       type_byte = static_cast<uint8_t>(frame.type);
@@ -3322,6 +3415,8 @@
     case STOP_SENDING_FRAME:
       type_byte = IETF_STOP_SENDING;
       break;
+    case MESSAGE_FRAME:
+      return true;
     default:
       QUIC_BUG << "Attempt to generate a frame type for an unsupported value: "
                << frame.type;
@@ -3917,6 +4012,22 @@
   return writer->WritePaddingBytes(frame.num_padding_bytes - 1);
 }
 
+bool QuicFramer::AppendMessageFrameAndTypeByte(const QuicMessageFrame& frame,
+                                               bool last_frame_in_packet,
+                                               QuicDataWriter* writer) {
+  uint8_t type_byte = last_frame_in_packet ? IETF_EXTENSION_MESSAGE_NO_LENGTH
+                                           : IETF_EXTENSION_MESSAGE;
+  if (!writer->WriteUInt8(type_byte)) {
+    return false;
+  }
+  if (!last_frame_in_packet &&
+      !writer->WriteVarInt62(frame.message_data.length())) {
+    return false;
+  }
+  return writer->WriteBytes(frame.message_data.data(),
+                            frame.message_data.length());
+}
+
 bool QuicFramer::RaiseError(QuicErrorCode error) {
   QUIC_DLOG(INFO) << ENDPOINT << "Error: " << QuicErrorCodeToString(error)
                   << " detail: " << detailed_error_;
diff --git a/net/third_party/quic/core/quic_framer.h b/net/third_party/quic/core/quic_framer.h
index 61cd65d..aa2a19e 100644
--- a/net/third_party/quic/core/quic_framer.h
+++ b/net/third_party/quic/core/quic_framer.h
@@ -165,6 +165,9 @@
   virtual bool OnNewConnectionIdFrame(
       const QuicNewConnectionIdFrame& frame) = 0;
 
+  // Called when a message frame has been parsed.
+  virtual bool OnMessageFrame(const QuicMessageFrame& frame) = 0;
+
   // Called when a packet has been completely processed.
   virtual void OnPacketComplete() = 0;
 
@@ -245,6 +248,9 @@
                                       QuicStreamOffset offset,
                                       bool last_frame_in_packet,
                                       QuicPacketLength data_length);
+  static size_t GetMessageFrameSize(QuicTransportVersion version,
+                                    bool last_frame_in_packet,
+                                    QuicByteCount length);
   // Size in bytes of all ack frame fields without the missing packets or ack
   // blocks.
   static size_t GetMinAckFrameSize(
@@ -549,6 +555,9 @@
                                 QuicWindowUpdateFrame* frame);
   bool ProcessBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame);
   void ProcessPaddingFrame(QuicDataReader* reader, QuicPaddingFrame* frame);
+  bool ProcessMessageFrame(QuicDataReader* reader,
+                           bool no_message_length,
+                           QuicMessageFrame* frame);
 
   bool DecryptPayload(QuicDataReader* encrypted_reader,
                       const QuicPacketHeader& header,
@@ -646,6 +655,9 @@
                           QuicDataWriter* writer);
   bool AppendPaddingFrame(const QuicPaddingFrame& frame,
                           QuicDataWriter* writer);
+  bool AppendMessageFrameAndTypeByte(const QuicMessageFrame& frame,
+                                     bool last_frame_in_packet,
+                                     QuicDataWriter* writer);
 
   // IETF frame processing methods.
   bool ProcessIetfStreamFrame(QuicDataReader* reader,
diff --git a/net/third_party/quic/core/quic_framer_test.cc b/net/third_party/quic/core/quic_framer_test.cc
index 06136039..cd231c4b 100644
--- a/net/third_party/quic/core/quic_framer_test.cc
+++ b/net/third_party/quic/core/quic_framer_test.cc
@@ -248,6 +248,12 @@
     return true;
   }
 
+  bool OnMessageFrame(const QuicMessageFrame& frame) override {
+    ++frame_count_;
+    message_frames_.push_back(QuicMakeUnique<QuicMessageFrame>(frame));
+    return true;
+  }
+
   void OnPacketComplete() override { ++complete_packets_; }
 
   bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
@@ -339,6 +345,7 @@
   std::vector<std::unique_ptr<QuicStopWaitingFrame>> stop_waiting_frames_;
   std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_;
   std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_;
+  std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_;
   QuicRstStreamFrame rst_stream_frame_;
   QuicConnectionCloseFrame connection_close_frame_;
   QuicApplicationCloseFrame application_close_frame_;
@@ -4545,6 +4552,56 @@
   // No need to check the PING frame boundaries because it has no payload.
 }
 
+TEST_P(QuicFramerTest, MessageFrame) {
+  if (framer_.transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+  // clang-format off
+  PacketFragments packet45 = {
+       // type (short header, 4 byte packet number)
+       {"",
+        {0x32}},
+       // connection_id
+       {"",
+        {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+       // packet number
+       {"",
+        {0x12, 0x34, 0x56, 0x78}},
+       // message frame type.
+       {"",
+        { 0x21 }},
+       // message length
+       {"Unable to read message length",
+        {0x07}},
+       // message data
+       {"Unable to read message data",
+        {'m', 'e', 's', 's', 'a', 'g', 'e'}},
+        // message frame no length.
+        {"",
+         { 0x20 }},
+        // message data
+        {{},
+         {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}},
+   };
+  // clang-format on
+
+  std::unique_ptr<QuicEncryptedPacket> encrypted(
+      AssemblePacketFromFragments(packet45));
+  EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(
+      *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+      PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+  ASSERT_EQ(2u, visitor_.message_frames_.size());
+  EXPECT_EQ(7u, visitor_.message_frames_[0]->message_data.length());
+  EXPECT_EQ(8u, visitor_.message_frames_[1]->message_data.length());
+
+  CheckFramingBoundaries(packet45, QUIC_INVALID_MESSAGE_DATA);
+}
+
 TEST_P(QuicFramerTest, PublicResetPacketV33) {
   // clang-format off
   PacketFragments packet = {
@@ -7717,6 +7774,50 @@
                                                     : QUIC_ARRAYSIZE(packet));
 }
 
+TEST_P(QuicFramerTest, BuildMessagePacket) {
+  if (framer_.transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+  QuicPacketHeader header;
+  header.destination_connection_id = kConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+
+  QuicMessageFrame frame(1, "message");
+  QuicMessageFrame frame2(2, "message2");
+  QuicFrames frames = {QuicFrame(&frame), QuicFrame(&frame2)};
+
+  // clang-format off
+  unsigned char packet45[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (message frame)
+    0x21,
+    // Length
+    0x07,
+    // Message Data
+    'm', 'e', 's', 's', 'a', 'g', 'e',
+    // frame type (message frame no length)
+    0x20,
+    // Message Data
+    'm', 'e', 's', 's', 'a', 'g', 'e', '2'
+  };
+  // clang-format on
+
+  std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+  ASSERT_TRUE(data != nullptr);
+
+  test::CompareCharArraysWithHexError("constructed packet", data->data(),
+                                      data->length(), AsChars(packet45),
+                                      QUIC_ARRAYSIZE(packet45));
+}
+
 // Test that the connectivity probing packet is serialized correctly as a
 // padded PING packet.
 TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) {
diff --git a/net/third_party/quic/core/quic_ietf_framer_test.cc b/net/third_party/quic/core/quic_ietf_framer_test.cc
index 8ecf4d87..e93524a 100644
--- a/net/third_party/quic/core/quic_ietf_framer_test.cc
+++ b/net/third_party/quic/core/quic_ietf_framer_test.cc
@@ -125,6 +125,8 @@
 
   bool OnPingFrame(const QuicPingFrame& frame) override { return true; }
 
+  bool OnMessageFrame(const QuicMessageFrame& frame) override { return true; }
+
   void OnPacketComplete() override {}
 
   bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
diff --git a/net/third_party/quic/core/quic_packet_creator.cc b/net/third_party/quic/core/quic_packet_creator.cc
index 17f666d..4b2605f8 100644
--- a/net/third_party/quic/core/quic_packet_creator.cc
+++ b/net/third_party/quic/core/quic_packet_creator.cc
@@ -160,6 +160,11 @@
                                            offset, true, data_size);
 }
 
+bool QuicPacketCreator::HasRoomForMessageFrame(QuicByteCount length) {
+  return BytesFree() >= QuicFramer::GetMessageFrameSize(
+                            framer_->transport_version(), true, length);
+}
+
 // TODO(fkastenholz): this method should not use constant values for
 // the last-frame-in-packet and data-length parameters to
 // GetMinStreamFrameSize.  Proper values should be plumbed in from
@@ -418,9 +423,17 @@
 }
 
 size_t QuicPacketCreator::ExpansionOnNewFrame() const {
+  // If the last frame in the packet is a message frame, then it will expand to
+  // include the varint message length when a new frame is added.
+  const bool has_trailing_message_frame =
+      !queued_frames_.empty() && queued_frames_.back().type == MESSAGE_FRAME;
+  if (has_trailing_message_frame) {
+    return QuicDataWriter::GetVarInt62Len(
+        queued_frames_.back().message_frame->message_data.length());
+  }
   // If the last frame in the packet is a stream frame, then it will expand to
   // include the stream_length field when a new frame is added.
-  bool has_trailing_stream_frame =
+  const bool has_trailing_stream_frame =
       !queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME;
   if (!has_trailing_stream_frame) {
     return 0;
@@ -744,6 +757,20 @@
   long_header_type_ = type;
 }
 
+QuicPacketLength QuicPacketCreator::GetLargestMessagePayload() const {
+  if (framer_->transport_version() <= QUIC_VERSION_44) {
+    return 0;
+  }
+  const size_t packet_header_size = GetPacketHeaderSize(
+      framer_->transport_version(), GetDestinationConnectionIdLength(),
+      GetSourceConnectionIdLength(), IncludeVersionInHeader(),
+      IncludeNonceInPublicHeader(), GetPacketNumberLength());
+  // This is the largest possible message payload when the length field is
+  // omitted.
+  return max_plaintext_size_ -
+         std::min(max_plaintext_size_, packet_header_size + kQuicFrameTypeSize);
+}
+
 bool QuicPacketCreator::HasIetfLongHeader() const {
   return framer_->transport_version() > QUIC_VERSION_43 &&
          packet_.encryption_level < ENCRYPTION_FORWARD_SECURE;
diff --git a/net/third_party/quic/core/quic_packet_creator.h b/net/third_party/quic/core/quic_packet_creator.h
index 2e670a07..b45005d 100644
--- a/net/third_party/quic/core/quic_packet_creator.h
+++ b/net/third_party/quic/core/quic_packet_creator.h
@@ -103,6 +103,10 @@
                              QuicStreamOffset offset,
                              size_t data_size);
 
+  // Returns true if current open packet can accomoodate a message frame of
+  // |length|.
+  bool HasRoomForMessageFrame(QuicByteCount length);
+
   // Re-serializes frames with the original packet's packet number length.
   // Used for retransmitting packets to ensure they aren't too long.
   void ReserializeAllFrames(const QuicPendingRetransmission& retransmission,
@@ -215,6 +219,9 @@
   // Sets long header type of next constructed packets.
   void SetLongHeaderType(QuicLongHeaderType type);
 
+  // Returns the largest payload that will fit into a single MESSAGE frame.
+  QuicPacketLength GetLargestMessagePayload() const;
+
   void set_debug_delegate(DebugDelegate* debug_delegate) {
     debug_delegate_ = debug_delegate;
   }
diff --git a/net/third_party/quic/core/quic_packet_creator_test.cc b/net/third_party/quic/core/quic_packet_creator_test.cc
index a05a0d2..9088b3dbe 100644
--- a/net/third_party/quic/core/quic_packet_creator_test.cc
+++ b/net/third_party/quic/core/quic_packet_creator_test.cc
@@ -1158,6 +1158,80 @@
   SerializeAllFrames(frames_);
 }
 
+TEST_P(QuicPacketCreatorTest, AddMessageFrame) {
+  if (client_framer_.transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .Times(3)
+      .WillRepeatedly(
+          Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacketForTests));
+  // Verify that there is enough room for the largest message payload.
+  EXPECT_TRUE(
+      creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload()));
+  QuicString message(creator_.GetLargestMessagePayload(), 'a');
+  EXPECT_TRUE(
+      creator_.AddSavedFrame(QuicFrame(new QuicMessageFrame(1, message))));
+  EXPECT_TRUE(creator_.HasPendingFrames());
+  creator_.Flush();
+
+  EXPECT_TRUE(
+      creator_.AddSavedFrame(QuicFrame(new QuicMessageFrame(2, "message"))));
+  EXPECT_TRUE(creator_.HasPendingFrames());
+  // Verify if a new frame is added, 1 byte message length will be added.
+  EXPECT_EQ(1u, creator_.ExpansionOnNewFrame());
+  EXPECT_TRUE(
+      creator_.AddSavedFrame(QuicFrame(new QuicMessageFrame(3, "message2"))));
+  EXPECT_EQ(1u, creator_.ExpansionOnNewFrame());
+  creator_.Flush();
+
+  QuicFrame frame;
+  MakeIOVector("test", &iov_);
+  EXPECT_TRUE(creator_.ConsumeData(kCryptoStreamId, &iov_, 1u, iov_.iov_len, 0u,
+                                   0u, false, false, &frame));
+  EXPECT_TRUE(
+      creator_.AddSavedFrame(QuicFrame(new QuicMessageFrame(1, "message"))));
+  EXPECT_TRUE(creator_.HasPendingFrames());
+  // Verify there is not enough room for largest payload.
+  EXPECT_FALSE(
+      creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload()));
+  // Add largest message will causes the flush of the stream frame.
+  QuicMessageFrame message_frame(2, message);
+  EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&message_frame)));
+  EXPECT_FALSE(creator_.HasPendingFrames());
+}
+
+TEST_P(QuicPacketCreatorTest, MessageFrameConsumption) {
+  if (client_framer_.transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+  QuicString message_data(kDefaultMaxPacketSize, 'a');
+  QuicStringPiece message_buffer(message_data);
+  // Test all possible size of message frames.
+  for (size_t message_size = 0;
+       message_size <= creator_.GetLargestMessagePayload(); ++message_size) {
+    EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(new QuicMessageFrame(
+        0, QuicStringPiece(message_buffer.data(), message_size)))));
+    EXPECT_TRUE(creator_.HasPendingFrames());
+
+    size_t expansion_bytes = message_size >= 64 ? 2 : 1;
+    EXPECT_EQ(expansion_bytes, creator_.ExpansionOnNewFrame());
+    // Verify BytesFree returns bytes available for the next frame, which should
+    // subtract the message length.
+    size_t expected_bytes_free =
+        creator_.GetLargestMessagePayload() - message_size < expansion_bytes
+            ? 0
+            : creator_.GetLargestMessagePayload() - expansion_bytes -
+                  message_size;
+    EXPECT_EQ(expected_bytes_free, creator_.BytesFree());
+    EXPECT_CALL(delegate_, OnSerializedPacket(_))
+        .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+    creator_.Flush();
+    ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+    DeleteSerializedPacket();
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_packet_generator.cc b/net/third_party/quic/core/quic_packet_generator.cc
index 01ad810..c52510b 100644
--- a/net/third_party/quic/core/quic_packet_generator.cc
+++ b/net/third_party/quic/core/quic_packet_generator.cc
@@ -387,4 +387,29 @@
   packet_creator_.set_can_set_transmission_type(can_set_transmission_type);
 }
 
+MessageStatus QuicPacketGenerator::AddMessageFrame(QuicMessageId message_id,
+                                                   QuicStringPiece message) {
+  QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
+                                     "generator tries to add message frame.";
+  if (message.length() > GetLargestMessagePayload()) {
+    return MESSAGE_STATUS_TOO_LARGE;
+  }
+  SendQueuedFrames(/*flush=*/false);
+  if (!packet_creator_.HasRoomForMessageFrame(message.length())) {
+    packet_creator_.Flush();
+  }
+  QuicMessageFrame* frame = new QuicMessageFrame(message_id, message);
+  const bool success = packet_creator_.AddSavedFrame(QuicFrame(frame));
+  if (!success) {
+    QUIC_BUG << "Failed to send message " << message_id;
+    delete frame;
+    return MESSAGE_STATUS_INTERNAL_ERROR;
+  }
+  return MESSAGE_STATUS_SUCCESS;
+}
+
+QuicPacketLength QuicPacketGenerator::GetLargestMessagePayload() const {
+  return packet_creator_.GetLargestMessagePayload();
+}
+
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_packet_generator.h b/net/third_party/quic/core/quic_packet_generator.h
index 44fb7eba..30708df 100644
--- a/net/third_party/quic/core/quic_packet_generator.h
+++ b/net/third_party/quic/core/quic_packet_generator.h
@@ -194,6 +194,13 @@
   // Allow/Disallow setting transmission type of next constructed packets.
   void SetCanSetTransmissionType(bool can_set_transmission_type);
 
+  // Tries to add a message frame containing |message| and returns the status.
+  MessageStatus AddMessageFrame(QuicMessageId message_id,
+                                QuicStringPiece message);
+
+  // Returns the largest payload that will fit into a single MESSAGE frame.
+  QuicPacketLength GetLargestMessagePayload() const;
+
   void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) {
     packet_creator_.set_debug_delegate(debug_delegate);
   }
diff --git a/net/third_party/quic/core/quic_packet_generator_test.cc b/net/third_party/quic/core/quic_packet_generator_test.cc
index bf93e18e..cd523e9f 100644
--- a/net/third_party/quic/core/quic_packet_generator_test.cc
+++ b/net/third_party/quic/core/quic_packet_generator_test.cc
@@ -1248,5 +1248,32 @@
   }
 }
 
+TEST_F(QuicPacketGeneratorTest, AddMessageFrame) {
+  if (framer_.transport_version() <= QUIC_VERSION_44) {
+    return;
+  }
+  delegate_.SetCanWriteAnything();
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+  MakeIOVector("foo", &iov_);
+  generator_.ConsumeData(kHeadersStreamId, &iov_, 1u, iov_.iov_len, 0, FIN);
+  EXPECT_EQ(MESSAGE_STATUS_SUCCESS, generator_.AddMessageFrame(1, "message"));
+  EXPECT_TRUE(generator_.HasQueuedFrames());
+  EXPECT_TRUE(generator_.HasRetransmittableFrames());
+
+  // Add a message which causes the flush of current packet.
+  EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
+            generator_.AddMessageFrame(
+                2, QuicString(generator_.GetLargestMessagePayload(), 'a')));
+  EXPECT_TRUE(generator_.HasRetransmittableFrames());
+
+  // Failed to send messages which cannot fit into one packet.
+  EXPECT_EQ(
+      MESSAGE_STATUS_TOO_LARGE,
+      generator_.AddMessageFrame(
+          3, QuicString(generator_.GetLargestMessagePayload() + 10, 'a')));
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_sent_packet_manager.cc b/net/third_party/quic/core/quic_sent_packet_manager.cc
index 11c70f5..9583edf 100644
--- a/net/third_party/quic/core/quic_sent_packet_manager.cc
+++ b/net/third_party/quic/core/quic_sent_packet_manager.cc
@@ -112,7 +112,9 @@
       rtt_updated_(false),
       acked_packets_iter_(last_ack_frame_.packets.rbegin()),
       aggregate_acked_stream_frames_(
-          GetQuicReloadableFlag(quic_aggregate_acked_stream_frames)) {
+          GetQuicReloadableFlag(quic_aggregate_acked_stream_frames)),
+      fix_mark_for_loss_retransmission_(
+          GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
   SetSendAlgorithm(congestion_control_type);
 }
 
@@ -385,20 +387,26 @@
   QuicTransmissionInfo* transmission_info =
       unacked_packets_.GetMutableTransmissionInfo(packet_number);
   // When session decides what to write, a previous RTO retransmission may cause
-  // connection close.
-  QUIC_BUG_IF(!unacked_packets_.HasRetransmittableFrames(*transmission_info) &&
-              (!session_decides_what_to_write() ||
-               transmission_type != RTO_RETRANSMISSION))
+  // connection close; packets without retransmittable frames can be marked for
+  // loss retransmissions.
+  QUIC_BUG_IF((transmission_type != LOSS_RETRANSMISSION &&
+               (!session_decides_what_to_write() ||
+                transmission_type != RTO_RETRANSMISSION)) &&
+              !unacked_packets_.HasRetransmittableFrames(*transmission_info))
       << "transmission_type: "
       << QuicUtils::TransmissionTypeToString(transmission_type);
   // Handshake packets should never be sent as probing retransmissions.
   DCHECK(!transmission_info->has_crypto_handshake ||
          transmission_type != PROBING_RETRANSMISSION);
   if (!RetransmissionLeavesBytesInFlight(transmission_type)) {
-    unacked_packets_.RemoveFromInFlight(packet_number);
+    unacked_packets_.RemoveFromInFlight(transmission_info);
   }
 
   if (!session_decides_what_to_write()) {
+    if (fix_mark_for_loss_retransmission_ &&
+        !unacked_packets_.HasRetransmittableFrames(*transmission_info)) {
+      return;
+    }
     if (!QuicContainsKey(pending_retransmissions_, packet_number)) {
       pending_retransmissions_[packet_number] = transmission_type;
     }
@@ -415,6 +423,7 @@
 void QuicSentPacketManager::HandleRetransmission(
     TransmissionType transmission_type,
     QuicTransmissionInfo* transmission_info) {
+  DCHECK(session_decides_what_to_write());
   if (ShouldForceRetransmission(transmission_type)) {
     // TODO(fayang): Consider to make RTO and PROBING retransmission
     // strategies be configurable by applications. Today, TLP, RTO and PROBING
@@ -429,7 +438,8 @@
   }
 
   unacked_packets_.NotifyFramesLost(*transmission_info, transmission_type);
-  if (!unacked_packets_.fix_is_useful_for_retransmission()) {
+  if (!unacked_packets_.fix_is_useful_for_retransmission() ||
+      transmission_info->retransmittable_frames.empty()) {
     return;
   }
 
@@ -808,8 +818,12 @@
                                     time);
     }
 
-    // TODO(ianswett): This could be optimized.
-    if (unacked_packets_.HasRetransmittableFrames(packet.packet_number)) {
+    if (fix_mark_for_loss_retransmission_ ||
+        unacked_packets_.HasRetransmittableFrames(packet.packet_number)) {
+      if (fix_mark_for_loss_retransmission_) {
+        QUIC_FLAG_COUNT(
+            quic_reloadable_flag_quic_fix_mark_for_loss_retransmission);
+      }
       MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION);
     } else {
       // Since we will not retransmit this, we need to remove it from
diff --git a/net/third_party/quic/core/quic_sent_packet_manager.h b/net/third_party/quic/core/quic_sent_packet_manager.h
index 558bb08..87ed9df 100644
--- a/net/third_party/quic/core/quic_sent_packet_manager.h
+++ b/net/third_party/quic/core/quic_sent_packet_manager.h
@@ -567,6 +567,10 @@
 
   // Latched value of quic_reloadable_flag_quic_aggregate_acked_stream_frames.
   const bool aggregate_acked_stream_frames_;
+
+  // Latched value of
+  // quic_reloadable_flag_quic_fix_mark_for_loss_retransmission.
+  const bool fix_mark_for_loss_retransmission_;
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_sent_packet_manager_test.cc b/net/third_party/quic/core/quic_sent_packet_manager_test.cc
index f01310c..e0efa8a5 100644
--- a/net/third_party/quic/core/quic_sent_packet_manager_test.cc
+++ b/net/third_party/quic/core/quic_sent_packet_manager_test.cc
@@ -489,14 +489,26 @@
   if (manager_.session_decides_what_to_write()) {
     // Frames in all packets are acked.
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Notify session that stream frame in packet 2 gets lost although it is
+      // not outstanding.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
+    }
   }
   manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
   manager_.OnAckRange(3, 6);
   manager_.OnAckRange(1, 2);
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
-  // No packets remain unacked.
-  VerifyUnackedPackets(nullptr, 0);
+  if (manager_.session_decides_what_to_write() &&
+      GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission) &&
+      GetQuicReloadableFlag(quic_fix_is_useful_for_retrans)) {
+    QuicPacketNumber unacked[] = {2};
+    VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
+  } else {
+    // No packets remain unacked.
+    VerifyUnackedPackets(nullptr, 0);
+  }
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
   VerifyRetransmittablePackets(nullptr, 0);
 
@@ -596,15 +608,27 @@
   ExpectAckAndLoss(true, 5, 2);
   EXPECT_CALL(debug_delegate, OnPacketLoss(2, LOSS_RETRANSMISSION, _));
   if (manager_.session_decides_what_to_write()) {
-    // Frames in all packetss are acked.
+    // Frames in all packets are acked.
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Notify session that stream frame in packet 2 gets lost although it is
+      // not outstanding.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
+    }
   }
   manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
   manager_.OnAckRange(3, 6);
   manager_.OnAckRange(1, 2);
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
-  VerifyUnackedPackets(nullptr, 0);
+  if (manager_.session_decides_what_to_write() &&
+      GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission) &&
+      GetQuicReloadableFlag(quic_fix_is_useful_for_retrans)) {
+    QuicPacketNumber unacked[] = {2};
+    VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
+  } else {
+    VerifyUnackedPackets(nullptr, 0);
+  }
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
   if (manager_.session_decides_what_to_write()) {
     // Spurious retransmission is detected when packet 3 gets acked. We cannot
@@ -824,6 +848,11 @@
   if (manager_.session_decides_what_to_write()) {
     // Frames in all packets are acked.
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Notify session that stream frame in packets 1 and 2 get lost although
+      // they are not outstanding.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2);
+    }
   }
   manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
   manager_.OnAckRange(3, 6);
@@ -925,14 +954,27 @@
                   true, _, _, Pointwise(PacketNumberEq(), {largest_acked}), _));
   EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
   if (manager_.session_decides_what_to_write()) {
-    // Frames in packet 3 gets acked as packet 103 gets acked.
-    EXPECT_CALL(notifier_, IsFrameOutstanding(_))
-        .WillOnce(Return(true))
-        .WillOnce(Return(true))
-        .WillOnce(Return(false))
-        .WillRepeatedly(Return(true));
-    // Packets 1, 2 and [4, 102] are lost.
-    EXPECT_CALL(notifier_, OnFrameLost(_)).Times(101);
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Although frames in packet 3 gets acked, it would be kept for another
+      // RTT.
+      EXPECT_CALL(notifier_, IsFrameOutstanding(_))
+          .WillRepeatedly(Return(true));
+    } else {
+      // Frames in packet 3 gets acked as packet 103 gets acked.
+      EXPECT_CALL(notifier_, IsFrameOutstanding(_))
+          .WillOnce(Return(true))
+          .WillOnce(Return(true))
+          .WillOnce(Return(false))
+          .WillRepeatedly(Return(true));
+    }
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Packets [1, 102] are lost, although stream frame in packet 3 is not
+      // outstanding.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102);
+    } else {
+      // Packets 1, 2 and [4, 102] are lost.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(101);
+    }
   }
   manager_.OnAckFrameStart(103, QuicTime::Delta::Infinite(), clock_.Now());
   manager_.OnAckRange(103, 104);
@@ -1287,16 +1329,27 @@
     EXPECT_CALL(debug_delegate, OnPacketLoss(i, LOSS_RETRANSMISSION, _));
   }
   if (manager_.session_decides_what_to_write()) {
-    EXPECT_CALL(notifier_, IsFrameOutstanding(_))
-        .WillOnce(Return(true))
-        // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not
-        // ideal.
-        .WillOnce(Return(true))
-        .WillOnce(Return(false))
-        .WillRepeatedly(Return(true));
-    // Packets [1, 99] are considered as lost, but packets 2 does not have
-    // retransmittable frames as packet 102 is acked.
-    EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      EXPECT_CALL(notifier_, IsFrameOutstanding(_))
+          .WillRepeatedly(Return(true));
+    } else {
+      EXPECT_CALL(notifier_, IsFrameOutstanding(_))
+          .WillOnce(Return(true))
+          // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not
+          // ideal.
+          .WillOnce(Return(true))
+          .WillOnce(Return(false))
+          .WillRepeatedly(Return(true));
+    }
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Packets [1, 99] are considered as lost, although stream frame in packet
+      // 2 is not outstanding.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99);
+    } else {
+      // Packets [1, 99] are considered as lost, but packets 2 does not have
+      // retransmittable frames as packet 102 is acked.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
+    }
   }
   manager_.OnAckFrameStart(102, QuicTime::Delta::Zero(), clock_.Now());
   manager_.OnAckRange(102, 103);
@@ -1404,16 +1457,27 @@
                                 /*lost_packets=*/Not(IsEmpty())));
   EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
   if (manager_.session_decides_what_to_write()) {
-    EXPECT_CALL(notifier_, IsFrameOutstanding(_))
-        .WillOnce(Return(true))
-        // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not
-        // ideal.
-        .WillOnce(Return(true))
-        .WillOnce(Return(false))
-        .WillRepeatedly(Return(true));
-    // Packets [1, 99] are considered as lost, but packets 2 does not have
-    // retransmittable frames as packet 102 is acked.
-    EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      EXPECT_CALL(notifier_, IsFrameOutstanding(_))
+          .WillRepeatedly(Return(true));
+    } else {
+      EXPECT_CALL(notifier_, IsFrameOutstanding(_))
+          .WillOnce(Return(true))
+          // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not
+          // ideal.
+          .WillOnce(Return(true))
+          .WillOnce(Return(false))
+          .WillRepeatedly(Return(true));
+    }
+    if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+      // Packets [1, 99] are considered as lost, although stream frame in packet
+      // 2 is not outstanding.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99);
+    } else {
+      // Packets [1, 99] are considered as lost, but packets 2 does not have
+      // retransmittable frames as packet 102 is acked.
+      EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
+    }
   }
   manager_.OnAckFrameStart(102, QuicTime::Delta::Zero(), clock_.Now());
   manager_.OnAckRange(102, 103);
diff --git a/net/third_party/quic/core/quic_session.cc b/net/third_party/quic/core/quic_session.cc
index 4136c6e..245aa5b 100644
--- a/net/third_party/quic/core/quic_session.cc
+++ b/net/third_party/quic/core/quic_session.cc
@@ -53,7 +53,8 @@
       goaway_sent_(false),
       goaway_received_(false),
       faster_get_stream_(GetQuicReloadableFlag(quic_session_faster_get_stream)),
-      control_frame_manager_(this) {
+      control_frame_manager_(this),
+      last_message_id_(0) {
   if (faster_get_stream_) {
     QUIC_FLAG_COUNT(quic_reloadable_flag_quic_session_faster_get_stream);
   }
@@ -159,6 +160,11 @@
   goaway_received_ = true;
 }
 
+void QuicSession::OnMessageReceived(QuicStringPiece message) {
+  QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
+                << ", " << message;
+}
+
 void QuicSession::OnConnectionClosed(QuicErrorCode error,
                                      const QuicString& error_details,
                                      ConnectionCloseSource source) {
@@ -1056,6 +1062,10 @@
 
 bool QuicSession::OnFrameAcked(const QuicFrame& frame,
                                QuicTime::Delta ack_delay_time) {
+  if (frame.type == MESSAGE_FRAME) {
+    OnMessageAcked(frame.message_frame->message_id);
+    return true;
+  }
   if (frame.type != STREAM_FRAME) {
     return control_frame_manager_.OnControlFrameAcked(frame);
   }
@@ -1089,6 +1099,10 @@
 }
 
 void QuicSession::OnFrameLost(const QuicFrame& frame) {
+  if (frame.type == MESSAGE_FRAME) {
+    OnMessageLost(frame.message_frame->message_id);
+    return;
+  }
   if (frame.type != STREAM_FRAME) {
     control_frame_manager_.OnControlFrameLost(frame);
     return;
@@ -1114,6 +1128,10 @@
       connection_, QuicConnection::NO_ACK);
   SetTransmissionType(type);
   for (const QuicFrame& frame : frames) {
+    if (frame.type == MESSAGE_FRAME) {
+      // Do not retransmit MESSAGE frames.
+      continue;
+    }
     if (frame.type != STREAM_FRAME) {
       if (!control_frame_manager_.RetransmitControlFrame(frame)) {
         break;
@@ -1131,6 +1149,9 @@
 }
 
 bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
+  if (frame.type == MESSAGE_FRAME) {
+    return false;
+  }
   if (frame.type != STREAM_FRAME) {
     return control_frame_manager_.IsControlFrameOutstanding(frame);
   }
@@ -1238,9 +1259,37 @@
   connection_->SetTransmissionType(type);
 }
 
+MessageResult QuicSession::SendMessage(QuicStringPiece message) {
+  if (!IsEncryptionEstablished()) {
+    return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
+  }
+  if (connection_->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
+    connection_->SetLongHeaderType(ZERO_RTT_PROTECTED);
+  }
+  MessageStatus result =
+      connection_->SendMessage(last_message_id_ + 1, message);
+  if (result == MESSAGE_STATUS_SUCCESS) {
+    return {result, ++last_message_id_};
+  }
+  return {result, 0};
+}
+
+void QuicSession::OnMessageAcked(QuicMessageId message_id) {
+  QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
+}
+
+void QuicSession::OnMessageLost(QuicMessageId message_id) {
+  QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
+                << " is considered lost";
+}
+
 bool QuicSession::session_decides_what_to_write() const {
   return connection_->session_decides_what_to_write();
 }
 
+QuicPacketLength QuicSession::GetLargestMessagePayload() const {
+  return connection_->GetLargestMessagePayload();
+}
+
 #undef ENDPOINT  // undef for jumbo builds
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_session.h b/net/third_party/quic/core/quic_session.h
index 00ce187..d18f8a7 100644
--- a/net/third_party/quic/core/quic_session.h
+++ b/net/third_party/quic/core/quic_session.h
@@ -93,6 +93,7 @@
   void OnStreamFrame(const QuicStreamFrame& frame) override;
   void OnRstStream(const QuicRstStreamFrame& frame) override;
   void OnGoAway(const QuicGoAwayFrame& frame) override;
+  void OnMessageReceived(QuicStringPiece message) override;
   void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   void OnBlockedFrame(const QuicBlockedFrame& frame) override;
   void OnConnectionClosed(QuicErrorCode error,
@@ -152,6 +153,22 @@
                                       QuicStreamOffset offset,
                                       StreamSendingState state);
 
+  // Called by application to send |message|. Returns the message result which
+  // includes the message status and message ID (valid if the write succeeds).
+  // SendMessage flushes a message packet even it is not full. If the
+  // application wants to bundle other data in the same packet, please consider
+  // adding a packet flusher around the SendMessage and/or WritevData calls. If
+  // a packet flusher is added, ensure the |message|'s buffer is not modified or
+  // deleted before exiting the flusher's scope. OnMessageAcked and
+  // OnMessageLost are called when a particular message gets acked or lost.
+  MessageResult SendMessage(QuicStringPiece message);
+
+  // Called when message with |message_id| gets acked.
+  virtual void OnMessageAcked(QuicMessageId message_id);
+
+  // Called when message with |message_id| is considered as lost.
+  virtual void OnMessageLost(QuicMessageId message_id);
+
   // Called by control frame manager when it wants to write control frames to
   // the peer. Returns true if |frame| is consumed, false otherwise.
   virtual bool WriteControlFrame(const QuicFrame& frame);
@@ -273,6 +290,11 @@
   // connection, or in a write-blocked stream.
   bool HasDataToWrite() const;
 
+  // Returns the largest payload that will fit into a single MESSAGE frame.
+  // Because overhead can vary during a connection, this method should be
+  // checked for every message.
+  QuicPacketLength GetLargestMessagePayload() const;
+
   bool goaway_sent() const { return goaway_sent_; }
 
   bool goaway_received() const { return goaway_received_; }
@@ -557,6 +579,9 @@
 
   QuicControlFrameManager control_frame_manager_;
 
+  // Id of latest successfully sent message.
+  QuicMessageId last_message_id_;
+
   // TODO(fayang): switch to linked_hash_set when chromium supports it. The bool
   // is not used here.
   // List of streams with pending retransmissions.
diff --git a/net/third_party/quic/core/quic_session_test.cc b/net/third_party/quic/core/quic_session_test.cc
index e299bef..2d570cc 100644
--- a/net/third_party/quic/core/quic_session_test.cc
+++ b/net/third_party/quic/core/quic_session_test.cc
@@ -1428,6 +1428,47 @@
   session_.OnCanWrite();
 }
 
+TEST_P(QuicSessionTestServer, SendMessage) {
+  // Cannot send message when encryption is not established.
+  EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
+  EXPECT_EQ(MessageResult(MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0),
+            session_.SendMessage(""));
+
+  // Finish handshake.
+  CryptoHandshakeMessage handshake_message;
+  session_.GetMutableCryptoStream()->OnHandshakeMessage(handshake_message);
+  EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
+
+  QuicStringPiece message;
+  QuicMessageFrame frame(1, message);
+  EXPECT_CALL(*connection_, SendMessage(1, _))
+      .WillOnce(Return(MESSAGE_STATUS_SUCCESS));
+  EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1),
+            session_.SendMessage(message));
+  // Verify message_id increases.
+  EXPECT_CALL(*connection_, SendMessage(2, _))
+      .WillOnce(Return(MESSAGE_STATUS_TOO_LARGE));
+  EXPECT_EQ(MessageResult(MESSAGE_STATUS_TOO_LARGE, 0),
+            session_.SendMessage(message));
+  // Verify unsent message does not consume a message_id.
+  EXPECT_CALL(*connection_, SendMessage(2, _))
+      .WillOnce(Return(MESSAGE_STATUS_SUCCESS));
+  QuicMessageFrame frame2(2, message);
+  EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 2),
+            session_.SendMessage(message));
+
+  EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame)));
+  EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame2)));
+
+  // Lost message 2.
+  session_.OnMessageLost(2);
+  EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame2)));
+
+  // message 1 gets acked.
+  session_.OnMessageAcked(1);
+  EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame)));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_trace_visitor.cc b/net/third_party/quic/core/quic_trace_visitor.cc
index 21bfd43..ca1112d8 100644
--- a/net/third_party/quic/core/quic_trace_visitor.cc
+++ b/net/third_party/quic/core/quic_trace_visitor.cc
@@ -87,6 +87,7 @@
       case PATH_RESPONSE_FRAME:
       case PATH_CHALLENGE_FRAME:
       case STOP_SENDING_FRAME:
+      case MESSAGE_FRAME:
         break;
 
       // Ignore gQUIC-specific frames.
@@ -211,6 +212,7 @@
     case PATH_RESPONSE_FRAME:
     case PATH_CHALLENGE_FRAME:
     case STOP_SENDING_FRAME:
+    case MESSAGE_FRAME:
       break;
 
     case NUM_FRAME_TYPES:
diff --git a/net/third_party/quic/core/quic_types.cc b/net/third_party/quic/core/quic_types.cc
index 35bff6a..5ceb1466 100644
--- a/net/third_party/quic/core/quic_types.cc
+++ b/net/third_party/quic/core/quic_types.cc
@@ -47,4 +47,7 @@
   return os;
 }
 
+MessageResult::MessageResult(MessageStatus status, QuicMessageId message_id)
+    : status(status), message_id(message_id) {}
+
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_types.h b/net/third_party/quic/core/quic_types.h
index 2de2beb..4b1d0c3 100644
--- a/net/third_party/quic/core/quic_types.h
+++ b/net/third_party/quic/core/quic_types.h
@@ -19,6 +19,7 @@
 typedef uint16_t QuicPacketLength;
 typedef uint32_t QuicControlFrameId;
 typedef uint32_t QuicHeaderId;
+typedef uint32_t QuicMessageId;
 typedef uint32_t QuicStreamId;
 typedef uint64_t QuicByteCount;
 typedef uint64_t QuicConnectionId;
@@ -182,6 +183,7 @@
   PATH_RESPONSE_FRAME,
   PATH_CHALLENGE_FRAME,
   STOP_SENDING_FRAME,
+  MESSAGE_FRAME,
 
   NUM_FRAME_TYPES
 };
@@ -215,6 +217,10 @@
   // whether the frame is a stream frame or not, and then examine each
   // bit specifically when/as needed.
   IETF_STREAM = 0x10,
+  // MESSAGE frame type is not yet determined, use 0x2x temporarily to give
+  // stream frame some wiggle room.
+  IETF_EXTENSION_MESSAGE_NO_LENGTH = 0x20,
+  IETF_EXTENSION_MESSAGE = 0x21,
 };
 // Masks for the bits that indicate the frame is a Stream frame vs the
 // bits used as flags.
@@ -483,6 +489,35 @@
   FLAGS_LONG_HEADER = 1 << 7,
 };
 
+enum MessageStatus {
+  MESSAGE_STATUS_SUCCESS,
+  MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED,  // Failed to send message because
+                                              // encryption is not established
+                                              // yet.
+  MESSAGE_STATUS_UNSUPPORTED,  // Failed to send message because MESSAGE frame
+                               // is not supported by the connection.
+  MESSAGE_STATUS_BLOCKED,      // Failed to send message because connection is
+                           // congestion control blocked or underlying socket is
+                           // write blocked.
+  MESSAGE_STATUS_TOO_LARGE,  // Failed to send message because the message is
+                             // too large to fit into a single packet.
+  MESSAGE_STATUS_INTERNAL_ERROR,  // Failed to send message because connection
+                                  // reaches an invalid state.
+};
+
+// Used to return the result of SendMessage calls
+struct QUIC_EXPORT_PRIVATE MessageResult {
+  MessageResult(MessageStatus status, QuicMessageId message_id);
+
+  bool operator==(const MessageResult& other) const {
+    return status == other.status && message_id == other.message_id;
+  }
+
+  MessageStatus status;
+  // Only valid when status is MESSAGE_STATUS_SUCCESS.
+  QuicMessageId message_id;
+};
+
 }  // namespace quic
 
 #endif  // NET_THIRD_PARTY_QUIC_CORE_QUIC_TYPES_H_
diff --git a/net/third_party/quic/core/quic_version_manager.cc b/net/third_party/quic/core/quic_version_manager.cc
index 6e55a52..a2a14c5 100644
--- a/net/third_party/quic/core/quic_version_manager.cc
+++ b/net/third_party/quic/core/quic_version_manager.cc
@@ -15,6 +15,7 @@
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
     : enable_version_99_(GetQuicFlag(FLAGS_quic_enable_version_99)),
+      enable_version_45_(GetQuicReloadableFlag(quic_enable_version_45)),
       enable_version_44_(GetQuicReloadableFlag(quic_enable_version_44)),
       enable_version_43_(GetQuicReloadableFlag(quic_enable_version_43)),
       disable_version_35_(GetQuicReloadableFlag(quic_disable_version_35)),
@@ -37,10 +38,12 @@
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
   if (enable_version_99_ != GetQuicFlag(FLAGS_quic_enable_version_99) ||
+      enable_version_45_ != GetQuicReloadableFlag(quic_enable_version_45) ||
       enable_version_44_ != GetQuicReloadableFlag(quic_enable_version_44) ||
       enable_version_43_ != GetQuicReloadableFlag(quic_enable_version_43) ||
       disable_version_35_ != GetQuicReloadableFlag(quic_disable_version_35)) {
     enable_version_99_ = GetQuicFlag(FLAGS_quic_enable_version_99);
+    enable_version_45_ = GetQuicReloadableFlag(quic_enable_version_45);
     enable_version_44_ = GetQuicReloadableFlag(quic_enable_version_44);
     enable_version_43_ = GetQuicReloadableFlag(quic_enable_version_43);
     disable_version_35_ = GetQuicReloadableFlag(quic_disable_version_35);
diff --git a/net/third_party/quic/core/quic_version_manager.h b/net/third_party/quic/core/quic_version_manager.h
index 6548a179..903fac3 100644
--- a/net/third_party/quic/core/quic_version_manager.h
+++ b/net/third_party/quic/core/quic_version_manager.h
@@ -37,6 +37,8 @@
  private:
   // FLAGS_quic_enable_version_99
   bool enable_version_99_;
+  // FLAGS_quic_reloadable_flag_quic_enable_version_45
+  bool enable_version_45_;
   // FLAGS_quic_reloadable_flag_quic_enable_version_44
   bool enable_version_44_;
   // FLAGS_quic_reloadable_flag_quic_enable_version_43
diff --git a/net/third_party/quic/core/quic_version_manager_test.cc b/net/third_party/quic/core/quic_version_manager_test.cc
index 0123aee..8724dab6 100644
--- a/net/third_party/quic/core/quic_version_manager_test.cc
+++ b/net/third_party/quic/core/quic_version_manager_test.cc
@@ -16,9 +16,10 @@
 class QuicVersionManagerTest : public QuicTest {};
 
 TEST_F(QuicVersionManagerTest, QuicVersionManager) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 5u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
                 "Supported versions out of sync");
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
+  SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_43, false);
   SetQuicReloadableFlag(quic_disable_version_35, true);
@@ -44,12 +45,18 @@
                                         QUIC_VERSION_39, QUIC_VERSION_35}),
             manager.GetSupportedTransportVersions());
 
-  SetQuicFlag(&FLAGS_quic_enable_version_99, true);
-  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_44,
+  SetQuicReloadableFlag(quic_enable_version_45, true);
+  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_45, QUIC_VERSION_44,
                                         QUIC_VERSION_43, QUIC_VERSION_39,
                                         QUIC_VERSION_35}),
             manager.GetSupportedTransportVersions());
 
+  SetQuicFlag(&FLAGS_quic_enable_version_99, true);
+  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_45,
+                                        QUIC_VERSION_44, QUIC_VERSION_43,
+                                        QUIC_VERSION_39, QUIC_VERSION_35}),
+            manager.GetSupportedTransportVersions());
+
   // Ensure that all versions are now supported.
   EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
             manager.GetSupportedTransportVersions());
diff --git a/net/third_party/quic/core/quic_versions.cc b/net/third_party/quic/core/quic_versions.cc
index 71e16339..4247021 100644
--- a/net/third_party/quic/core/quic_versions.cc
+++ b/net/third_party/quic/core/quic_versions.cc
@@ -62,6 +62,8 @@
       return MakeVersionLabel(proto, '0', '4', '3');
     case QUIC_VERSION_44:
       return MakeVersionLabel(proto, '0', '4', '4');
+    case QUIC_VERSION_45:
+      return MakeVersionLabel(proto, '0', '4', '5');
     case QUIC_VERSION_99:
       return MakeVersionLabel(proto, '0', '9', '9');
     default:
@@ -155,6 +157,13 @@
   for (ParsedQuicVersion version : versions) {
     if (version.transport_version == QUIC_VERSION_99) {
       if (GetQuicFlag(FLAGS_quic_enable_version_99) &&
+          GetQuicReloadableFlag(quic_enable_version_45) &&
+          GetQuicReloadableFlag(quic_enable_version_44) &&
+          GetQuicReloadableFlag(quic_enable_version_43)) {
+        filtered_versions.push_back(version);
+      }
+    } else if (version.transport_version == QUIC_VERSION_45) {
+      if (GetQuicReloadableFlag(quic_enable_version_45) &&
           GetQuicReloadableFlag(quic_enable_version_44) &&
           GetQuicReloadableFlag(quic_enable_version_43)) {
         filtered_versions.push_back(version);
@@ -265,6 +274,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_39);
     RETURN_STRING_LITERAL(QUIC_VERSION_43);
     RETURN_STRING_LITERAL(QUIC_VERSION_44);
+    RETURN_STRING_LITERAL(QUIC_VERSION_45);
     RETURN_STRING_LITERAL(QUIC_VERSION_99);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
diff --git a/net/third_party/quic/core/quic_versions.h b/net/third_party/quic/core/quic_versions.h
index f100066dd..4c3cf15 100644
--- a/net/third_party/quic/core/quic_versions.h
+++ b/net/third_party/quic/core/quic_versions.h
@@ -100,6 +100,7 @@
   QUIC_VERSION_43 = 43,  // PRIORITY frames are sent by client and accepted by
                          // server.
   QUIC_VERSION_44 = 44,  // Use IETF header format.
+  QUIC_VERSION_45 = 45,  // Added MESSAGE frame.
   QUIC_VERSION_99 = 99,  // Dumping ground for IETF QUIC changes which are not
                          // yet ready for production.
 };
@@ -160,8 +161,8 @@
 //
 // See go/new-quic-version for more details on how to roll out new versions.
 static const QuicTransportVersion kSupportedTransportVersions[] = {
-    QUIC_VERSION_99, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39,
-    QUIC_VERSION_35};
+    QUIC_VERSION_99, QUIC_VERSION_45, QUIC_VERSION_44,
+    QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
 
 // This vector contains all crypto handshake protocols that are supported.
 static const HandshakeProtocol kSupportedHandshakeProtocols[] = {
diff --git a/net/third_party/quic/core/quic_versions_test.cc b/net/third_party/quic/core/quic_versions_test.cc
index 9b1fd46..596def5 100644
--- a/net/third_party/quic/core/quic_versions_test.cc
+++ b/net/third_party/quic/core/quic_versions_test.cc
@@ -138,6 +138,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '4')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
+            ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '5')));
 
   // Test a TLS version:
   FLAGS_quic_supports_tls_handshake = true;
@@ -149,6 +151,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
 
   FLAGS_quic_supports_tls_handshake = false;
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
@@ -167,6 +171,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
 }
 
 TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
@@ -182,6 +188,9 @@
   EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '4'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44)));
+  EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '5'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45)));
 
   // Test a TLS version:
   FLAGS_quic_supports_tls_handshake = true;
@@ -197,6 +206,9 @@
   EXPECT_EQ(MakeVersionLabel('T', '0', '4', '4'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44)));
+  EXPECT_EQ(MakeVersionLabel('T', '0', '4', '5'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45)));
 
   FLAGS_quic_supports_tls_handshake = false;
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
@@ -215,6 +227,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
 }
 
 TEST_F(QuicVersionsTest, QuicVersionLabelToString) {
@@ -301,14 +315,15 @@
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicFlag(&FLAGS_quic_enable_version_99, true);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
     parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
   }
   QuicTransportVersionVector expected_versions = {
-      QUIC_VERSION_99, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39,
-      QUIC_VERSION_35};
+      QUIC_VERSION_99, QUIC_VERSION_45, QUIC_VERSION_44,
+      QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
   ParsedQuicVersionVector expected_parsed_versions;
   for (QuicTransportVersion version : expected_versions) {
     expected_parsed_versions.push_back(
@@ -324,6 +339,31 @@
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicFlag(&FLAGS_quic_enable_version_99, false);
+  ParsedQuicVersionVector parsed_versions;
+  for (QuicTransportVersion version : all_versions) {
+    parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+  QuicTransportVersionVector expected_versions = {
+      QUIC_VERSION_45, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39,
+      QUIC_VERSION_35};
+  ParsedQuicVersionVector expected_parsed_versions;
+  for (QuicTransportVersion version : expected_versions) {
+    expected_parsed_versions.push_back(
+        ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+
+  ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
+  ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
+}
+
+TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo45) {
+  QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  SetQuicReloadableFlag(quic_disable_version_35, false);
+  SetQuicReloadableFlag(quic_enable_version_43, true);
+  SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -346,6 +386,7 @@
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, false);
+  SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -368,6 +409,7 @@
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
+  SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -390,6 +432,7 @@
   SetQuicReloadableFlag(quic_disable_version_35, true);
   SetQuicReloadableFlag(quic_enable_version_43, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
+  SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -446,12 +489,13 @@
 // yet a typo was made in doing the #defines and it was caught
 // only in some test far removed from here... Better safe than sorry.
 TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 5u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_35, 35);
   EXPECT_EQ(QUIC_VERSION_39, 39);
   EXPECT_EQ(QUIC_VERSION_43, 43);
   EXPECT_EQ(QUIC_VERSION_44, 44);
+  EXPECT_EQ(QUIC_VERSION_45, 45);
   EXPECT_EQ(QUIC_VERSION_99, 99);
 }
 }  // namespace
diff --git a/net/third_party/quic/test_tools/quic_test_utils.cc b/net/third_party/quic/test_tools/quic_test_utils.cc
index 18b1219..2822297 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.cc
+++ b/net/third_party/quic/test_tools/quic_test_utils.cc
@@ -267,6 +267,10 @@
   return true;
 }
 
+bool NoOpFramerVisitor::OnMessageFrame(const QuicMessageFrame& frame) {
+  return true;
+}
+
 bool NoOpFramerVisitor::IsValidStatelessResetToken(QuicUint128 token) const {
   return false;
 }
diff --git a/net/third_party/quic/test_tools/quic_test_utils.h b/net/third_party/quic/test_tools/quic_test_utils.h
index 9f5c5ae..5941316 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.h
+++ b/net/third_party/quic/test_tools/quic_test_utils.h
@@ -276,6 +276,7 @@
                bool(const QuicStreamIdBlockedFrame& frame));
   MOCK_METHOD1(OnWindowUpdateFrame, bool(const QuicWindowUpdateFrame& frame));
   MOCK_METHOD1(OnBlockedFrame, bool(const QuicBlockedFrame& frame));
+  MOCK_METHOD1(OnMessageFrame, bool(const QuicMessageFrame& frame));
   MOCK_METHOD0(OnPacketComplete, void());
   MOCK_CONST_METHOD1(IsValidStatelessResetToken, bool(QuicUint128));
   MOCK_METHOD1(OnAuthenticatedIetfStatelessResetPacket,
@@ -319,6 +320,7 @@
   bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override;
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
+  bool OnMessageFrame(const QuicMessageFrame& frame) override;
   void OnPacketComplete() override {}
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
@@ -338,6 +340,7 @@
   MOCK_METHOD1(OnBlockedFrame, void(const QuicBlockedFrame& frame));
   MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame));
   MOCK_METHOD1(OnGoAway, void(const QuicGoAwayFrame& frame));
+  MOCK_METHOD1(OnMessageReceived, void(QuicStringPiece message));
   MOCK_METHOD3(OnConnectionClosed,
                void(QuicErrorCode error,
                     const QuicString& error_details,
@@ -481,6 +484,7 @@
 
   MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode));
   MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame));
+  MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicStringPiece));
 
   MOCK_METHOD1(OnError, void(QuicFramer* framer));
   void QuicConnection_OnError(QuicFramer* framer) {
diff --git a/net/third_party/quic/test_tools/simple_quic_framer.cc b/net/third_party/quic/test_tools/simple_quic_framer.cc
index c84585d..cad44e3 100644
--- a/net/third_party/quic/test_tools/simple_quic_framer.cc
+++ b/net/third_party/quic/test_tools/simple_quic_framer.cc
@@ -156,6 +156,11 @@
     return true;
   }
 
+  bool OnMessageFrame(const QuicMessageFrame& frame) override {
+    message_frames_.push_back(frame);
+    return true;
+  }
+
   void OnPacketComplete() override {}
 
   bool IsValidStatelessResetToken(QuicUint128 token) const override {
@@ -197,6 +202,9 @@
     return stop_waiting_frames_;
   }
   const std::vector<QuicPingFrame>& ping_frames() const { return ping_frames_; }
+  const std::vector<QuicMessageFrame>& message_frames() const {
+    return message_frames_;
+  }
   const std::vector<QuicWindowUpdateFrame>& window_update_frames() const {
     return window_update_frames_;
   }
@@ -231,6 +239,7 @@
   std::vector<QuicWindowUpdateFrame> window_update_frames_;
   std::vector<QuicBlockedFrame> blocked_frames_;
   std::vector<QuicNewConnectionIdFrame> new_connection_id_frames_;
+  std::vector<QuicMessageFrame> message_frames_;
   std::vector<std::unique_ptr<QuicString>> stream_data_;
 };
 
@@ -293,6 +302,10 @@
   return visitor_->ping_frames();
 }
 
+const std::vector<QuicMessageFrame>& SimpleQuicFramer::message_frames() const {
+  return visitor_->message_frames();
+}
+
 const std::vector<QuicWindowUpdateFrame>&
 SimpleQuicFramer::window_update_frames() const {
   return visitor_->window_update_frames();
diff --git a/net/third_party/quic/test_tools/simple_quic_framer.h b/net/third_party/quic/test_tools/simple_quic_framer.h
index 37d20f1..466539a 100644
--- a/net/third_party/quic/test_tools/simple_quic_framer.h
+++ b/net/third_party/quic/test_tools/simple_quic_framer.h
@@ -40,6 +40,7 @@
   const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const;
   const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const;
   const std::vector<QuicPingFrame>& ping_frames() const;
+  const std::vector<QuicMessageFrame>& message_frames() const;
   const std::vector<QuicWindowUpdateFrame>& window_update_frames() const;
   const std::vector<QuicGoAwayFrame>& goaway_frames() const;
   const std::vector<QuicRstStreamFrame>& rst_stream_frames() const;
diff --git a/net/third_party/quic/test_tools/simulator/quic_endpoint.h b/net/third_party/quic/test_tools/simulator/quic_endpoint.h
index 8a0e51e..689f88b 100644
--- a/net/third_party/quic/test_tools/simulator/quic_endpoint.h
+++ b/net/third_party/quic/test_tools/simulator/quic_endpoint.h
@@ -89,6 +89,7 @@
   void OnBlockedFrame(const QuicBlockedFrame& frame) override {}
   void OnRstStream(const QuicRstStreamFrame& frame) override {}
   void OnGoAway(const QuicGoAwayFrame& frame) override {}
+  void OnMessageReceived(QuicStringPiece message) override {}
   void OnConnectionClosed(QuicErrorCode error,
                           const std::string& error_details,
                           ConnectionCloseSource source) override {}
diff --git a/net/third_party/quic/tools/quic_packet_printer_bin.cc b/net/third_party/quic/tools/quic_packet_printer_bin.cc
index 743d114..723c4b4 100644
--- a/net/third_party/quic/tools/quic_packet_printer_bin.cc
+++ b/net/third_party/quic/tools/quic_packet_printer_bin.cc
@@ -178,6 +178,10 @@
     std::cerr << "OnBlockedFrame: " << frame;
     return true;
   }
+  bool OnMessageFrame(const QuicMessageFrame& frame) override {
+    std::cerr << "OnMessageFrame: " << frame;
+    return true;
+  }
   void OnPacketComplete() override { std::cerr << "OnPacketComplete\n"; }
   bool IsValidStatelessResetToken(QuicUint128 token) const override {
     std::cerr << "IsValidStatelessResetToken\n";
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn
index cbb9efa..cc6902f8 100644
--- a/remoting/android/BUILD.gn
+++ b/remoting/android/BUILD.gn
@@ -60,7 +60,10 @@
 }
 
 remoting_android_client_java_tmpl("remoting_android_client_java") {
-  play_services_package = "//third_party/android_tools"
+  # This should always be the public play services libraries since it is only
+  # used by non-_google apks. Explicitly use the string literal rather than
+  # google_play_services_package to ensure this.
+  play_services_package = "//third_party/android_deps"
 }
 
 remoting_apk_tmpl("remoting_apk") {
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index f5986d7..699c352 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -209,17 +209,13 @@
     deps += [ "//sandbox/win:sandbox" ]
   }
 
-  # TODO(sdefresne): This depends on net's enable_net_mojo getting turned on for
-  # iOS, which depends on net_with_v8 as well. http://crbug.com/803149
-  if (!is_ios) {
-    sources += [
-      "proxy_resolver_factory_mojo.cc",
-      "proxy_resolver_factory_mojo.h",
-      "proxy_service_mojo.cc",
-      "proxy_service_mojo.h",
-    ]
-    deps += [ "//net/dns:mojo_service" ]
-  }
+  sources += [
+    "proxy_resolver_factory_mojo.cc",
+    "proxy_resolver_factory_mojo.h",
+    "proxy_service_mojo.cc",
+    "proxy_service_mojo.h",
+  ]
+  deps += [ "//net/dns:mojo_service" ]
 
   defines = [ "IS_NETWORK_SERVICE_IMPL" ]
 
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 51dca86..63fdf14 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -3748,13 +3748,6 @@
 
   EXPECT_EQ(0u, request_errors.size());
 
-// TODO(https://crbug.com/881124): Mocking proxy resolution doesn't work
-//                                 on iOS.
-#if defined(OS_IOS)
-  if (pac_errors.empty())
-    return;
-#endif
-
   ASSERT_EQ(1u, pac_errors.size());
   EXPECT_EQ(pac_errors[0].line, 42);
   EXPECT_EQ(pac_errors[0].details,
diff --git a/services/network/url_request_context_builder_mojo.cc b/services/network/url_request_context_builder_mojo.cc
index 0013f02..5a9f95f 100644
--- a/services/network/url_request_context_builder_mojo.cc
+++ b/services/network/url_request_context_builder_mojo.cc
@@ -10,10 +10,7 @@
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "services/network/network_context.h"
 #include "services/network/public/cpp/features.h"
-
-#if !defined(OS_IOS)
 #include "services/network/proxy_service_mojo.h"
-#endif
 
 namespace network {
 
@@ -43,7 +40,6 @@
   DCHECK(url_request_context);
   DCHECK(host_resolver);
 
-#if !defined(OS_IOS)
   if (mojo_proxy_resolver_factory_) {
     std::unique_ptr<net::DhcpPacFileFetcher> dhcp_pac_file_fetcher =
         dhcp_fetcher_factory_->Create(url_request_context);
@@ -63,7 +59,6 @@
         std::move(dhcp_pac_file_fetcher), host_resolver, net_log,
         network_delegate);
   }
-#endif
 
   return net::URLRequestContextBuilder::CreateProxyResolutionService(
       std::move(proxy_config_service), url_request_context, host_resolver,
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
index dc3e335..8e110be8 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
@@ -183,6 +183,9 @@
 # Failing on ASAN bot. crbug.com/882631
 -ExtensionWebRequestApiTest.WebRequestTypes
 
+# Crashing flakily. https://crbug.com/883371
+-ExtensionDisabledGlobalErrorTest.UninstallWhilePromptBeingShown
+
 # Immersive mode tests.
 -ImmersiveModeBrowserViewTest.TabNavigationAcceleratorsFullscreenBrowser/material
 
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
index 8d1f5bdc..93921f7 100644
--- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -15,23 +15,17 @@
 # --gtest_repeat=5, but might pass on a single invocation).
 
 # Chrome Desktop failures (Mac, Linux, Windows).
--CrSettingsLanguagesPageTest.InputMethods
--CrSettingsMainPageTest.MainPage
 -CrSettingsMenuTest.SettingsMenu
 -CrSettingsPeoplePageSyncAccountControlTest.All
 -CrSettingsPeoplePageSyncPageTest.All
 -CrSettingsPeoplePageTest.All
--CrSettingsRouteDynamicParametersTest.All
--CrSettingsSiteDataTest.All
 -CrSettingsSiteListTest.SiteList
--CrSettingsSubpageTest.All
 -CrSettingsZoomLevelsTest.All
 -MediaRouterElementsBrowserTest.MediaRouterContainerCastModeList
 -MediaRouterElementsBrowserTest.MediaRouterContainerFilterPart1
 -MediaRouterElementsBrowserTest.MediaRouterContainerFirstRunFlow
 -MediaRouterElementsBrowserTest.MediaRouterContainerSinkList
 -MediaRouterElementsBrowserTest.MediaRouterRouteDetails
--PasswordsAndFormsBrowserTest.uiTests
 -SettingsAdvancedPageBrowserTest.Load
 
 # Mac only failure. See crbug.com/876990
@@ -195,6 +189,7 @@
 CrSettingsImportDataDialogTest.*
 CrSettingsLanguagesPageTest.InputMethods
 CrSettingsLanguagesTest.*
+CrSettingsMainPageTest.*
 CrSettingsMultideviceFeatureItemTest.*
 CrSettingsMultideviceFeatureToggleTest.*
 CrSettingsMultidevicePageTest.*
@@ -213,12 +208,14 @@
 CrSettingsProtocolHandlersTest.*
 CrSettingsResetPageTest.*
 CrSettingsResetProfileBannerTest.*
+CrSettingsRouteDynamicParametersTest.*
 CrSettingsRouteTest.*
 CrSettingsSearchEnginesTest.*
 CrSettingsSearchPageTest.*
 CrSettingsSearchTest.*
 CrSettingsSiteDataDetailsTest.*
 CrSettingsSiteDataTest.*
+CrSettingsSiteDataTest.*
 CrSettingsSiteDetailsPermissionTest.*
 CrSettingsSiteDetailsTest.*
 CrSettingsSiteEntryTest.*
@@ -227,6 +224,7 @@
 CrSettingsSliderTest.*
 CrSettingsSmbPageTest.*
 CrSettingsStartupUrlsPageTest.*
+CrSettingsSubpageTest.*
 CrSettingsSyncPageTest.*
 CrSettingsSystemPageTest.*
 CrSettingsTextareaTest.*
@@ -298,6 +296,7 @@
 MultiProfileFilesAppBrowserTest.*
 NetInternalsTest.*
 NTP4WebUITest.*
+PasswordsAndFormsBrowserTest.*
 PrintPreviewAdvancedDialogTest.*
 PrintPreviewAdvancedItemTest.*
 PrintPreviewBaseSettingsSectionTest.*
diff --git a/testing/test.gni b/testing/test.gni
index 3ddc57f..006489c 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -275,7 +275,6 @@
 
     fuchsia_package(_pkg_target) {
       testonly = true
-      sandbox_policy = "//build/config/fuchsia/testing_sandbox_policy"
       binary = ":$_exec_target"
       package_name_override = _output_name
     }
diff --git a/third_party/PRESUBMIT.py b/third_party/PRESUBMIT.py
index c5773b3..f3db8291 100644
--- a/third_party/PRESUBMIT.py
+++ b/third_party/PRESUBMIT.py
@@ -7,7 +7,7 @@
   'Android Software Development Kit License',
   'Apache( Version)? 2(\.0)?',
   '(New )?([23]-Clause )?BSD( [23]-Clause)?( with advertising clause)?',
-  'L?GPL ?v?2(\.[01])?( or later)?',
+  'L?GPL ?v?2(\.[01])?( or later)?( with the classpath exception)?',
   'MIT(/X11)?(-like)?',
   'MPL 1\.1 ?/ ?GPL 2(\.0)? ?/ ?LGPL 2\.1',
   'MPL 2(\.0)?',
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index e6aca14..4144d25 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -17,12 +17,6 @@
 # NG doesn't have bug 450202, so the following test will never pass.
 crbug.com/450202 fast/multicol/span/overflow-on-multicol.html [ Skip ]
 
-# Fails because we don't yet special-case marquee like legacy does:
-# https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/layout/layout_block.cc?l=1372&rcl=0e081149ecd6a83f6289e3aee5797936008a1e10
-crbug.com/591099 fast/block/marquee-width-shrinks-to-fit-in-fixed-size-container.html [ Failure ]
-
-# Whitespace differences only
-
 # Wrong quirks mode line height for pattern <div><a><img></a></div>
 crbug.com/854840 fast/table/backgr_border-table-quirks-collapsed-border.html [ Failure ]
 crbug.com/854840 fast/table/backgr_border-table-quirks.html [ Failure ]
@@ -63,7 +57,6 @@
 crbug.com/591099 fast/dom/nodesFromRect/nodesFromRect-basic.html [ Failure ]
 
 # New failures are appended below by the script.
-crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
 crbug.com/728378 compositing/culling/tile-occlusion-boundaries.html [ Failure ]
 crbug.com/591099 compositing/iframes/floating-self-painting-frame.html [ Failure ]
 crbug.com/591099 compositing/layer-creation/overlap-animation.html [ Crash ]
@@ -348,7 +341,6 @@
 crbug.com/591099 external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ]
 crbug.com/591099 external/wpt/xhr/send-content-type-string.htm [ Pass ]
 crbug.com/591099 external/wpt/xhr/send-entity-body-document.htm [ Pass ]
-crbug.com/591099 fast/backgrounds/background-leakage-transforms.html [ Failure ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
 crbug.com/591099 fast/block/basic/quirk-percent-height-table-cell.html [ Failure ]
 crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Crash ]
@@ -387,7 +379,6 @@
 crbug.com/835484 fast/inline/outline-offset.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
 crbug.com/591099 fast/overflow/recompute-overflow-of-layout-root-container.html [ Failure ]
-crbug.com/591099 fast/reflections/opacity-reflection-transform.html [ Failure ]
 crbug.com/591099 fast/replaced/table-replaced-element.html [ Failure ]
 crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Pass ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
@@ -407,7 +398,6 @@
 crbug.com/591099 fast/text/ellipsis-in-relative-inline.html [ Failure ]
 crbug.com/714962 fast/text/emoticons.html [ Failure ]
 crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Pass ]
-crbug.com/591099 fast/text/selection/emphasis.html [ Failure ]
 crbug.com/591099 fast/text/unicode-fallback-font.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/018.html [ Failure ]
 crbug.com/591099 fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
@@ -451,8 +441,6 @@
 crbug.com/714962 inspector-protocol/layout-fonts/languages-emoji-rare-glyphs.js [ Failure ]
 crbug.com/591099 inspector-protocol/timeline/page-frames.js [ Failure ]
 crbug.com/591099 intersection-observer/v2/text-shadow.html [ Failure ]
-crbug.com/591099 media/video-aspect-ratio.html [ Failure ]
-crbug.com/591099 paint/background/scrolling-background-with-negative-z-child.html [ Failure ]
 crbug.com/591099 paint/float/float-under-inline-self-painting-change.html [ Failure ]
 crbug.com/835484 paint/inline/focus-ring-under-absolute-with-relative-continuation.html [ Failure ]
 crbug.com/591099 paint/invalidation/clip/control-clip.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index f29360d..5662c4bf 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -204,8 +204,6 @@
 
 crbug.com/529345 [ Win10 ] paint/masks/fieldset-mask.html [ Slow ]
 
-crbug.com/658211 [ Win7 Debug ] fast/text/line-break-ascii.html [ Slow ]
-
 crbug.com/802029 fast/dom/shadow/focus-controller-recursion-crash.html [ Slow ]
 
 crbug.com/592183 external/wpt/webusb/usbDevice.https.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 1f898d3..2fbaebf 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3857,6 +3857,7 @@
 crbug.com/673539 [ Linux Win ] css3/filters/effect-contrast-hw.html [ Pass Failure ]
 
 
+crbug.com/765738 [ Linux Win Mac ] http/tests/wasm/wasm_remote_postMessage_test.https.html [ Pass Timeout ]
 crbug.com/765738 [ Linux Win Mac ] virtual/enable_wasm/http/tests/wasm/wasm_remote_postMessage_test.https.html [ Pass Timeout ]
 
 # ====== Random order flaky tests from here ======
@@ -4006,25 +4007,16 @@
 crbug.com/798864 [ Android ] external/wpt/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html [ Failure ]
 crbug.com/798864 [ Android ] external/wpt/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html [ Failure ]
 
-# Requires --enable-features=WebAssembly
-crbug.com/746486 external/wpt/wasm/serialization/broadcastchannel-success-and-failure.html [ Timeout ]
-crbug.com/746486 external/wpt/wasm/serialization/broadcastchannel-success.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/identity-not-preserved.html [ Timeout ]
-crbug.com/746486 external/wpt/wasm/serialization/nested-worker-success.any.worker.html [ Timeout Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/no-transferring.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/window-domain-success.sub.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/window-messagechannel-success.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/window-serviceworker-failure.https.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/window-sharedworker-failure.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/window-similar-but-cross-origin-success.sub.html [ Failure ]
-crbug.com/746486 external/wpt/wasm/serialization/window-simple-success.html [ Failure ]
-
 crbug.com/874302 virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html [ Timeout ]
 crbug.com/874302 virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html [ Timeout ]
+crbug.com/874302 external/wpt/wasm/serialization/broadcastchannel-success-and-failure.html [ Timeout ]
 crbug.com/874302 virtual/enable_wasm/external/wpt/wasm/serialization/broadcastchannel-success-and-failure.html [ Timeout ]
+crbug.com/874302 external/wpt/wasm/serialization/broadcastchannel-success.html [ Timeout ]
 crbug.com/874302 virtual/enable_wasm/external/wpt/wasm/serialization/broadcastchannel-success.html [ Timeout ]
 
+crbug.com/877286 external/wpt/wasm/serialization/no-transferring.html [ Failure ]
 crbug.com/877286 virtual/enable_wasm/external/wpt/wasm/serialization/no-transferring.html [ Failure ]
+crbug.com/877296 external/wpt/wasm/serialization/window-serviceworker-failure.https.html [ Failure ]
 crbug.com/877296 virtual/enable_wasm/external/wpt/wasm/serialization/window-serviceworker-failure.https.html [ Failure ]
 
 crbug.com/831509 external/wpt/service-workers/service-worker/skip-waiting-installed.https.html [ Failure Pass ]
@@ -5137,3 +5129,13 @@
 crbug.com/882689 http/tests/security/cookies/third-party-cookie-blocking-worker.html [ Pass Failure ]
 crbug.com/882689 virtual/outofblink-cors/http/tests/security/cookies/third-party-cookie-blocking-worker.html [ Pass Failure ]
 crbug.com/882689 virtual/outofblink-cors-ns/http/tests/security/cookies/third-party-cookie-blocking-worker.html [ Pass Failure ]
+
+# The following tests need LazyFrameLoading.
+crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html [ Failure ]
+crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 50ee177..11f5004 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -757,5 +757,10 @@
     "prefix": "intersection-observer-v2",
     "base": "http/tests/intersection-observer",
     "args": ["--enable-blink-features=IntersectionObserverV2"]
+  },
+  {
+    "prefix" : "lazyload-policy",
+    "base": "external/wpt/feature-policy/experimental-features/lazyload",
+    "args": ["--enable-blink-features=LazyFrameLoading"]
   }
 ]
diff --git a/third_party/WebKit/LayoutTests/compositing/animation/animations-establish-stacking-context-expected.html b/third_party/WebKit/LayoutTests/compositing/animation/animations-establish-stacking-context-expected.html
new file mode 100644
index 0000000..16de217
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/animation/animations-establish-stacking-context-expected.html
@@ -0,0 +1,67 @@
+<style>
+.shouldStack {
+  position: absolute;
+  width: 150px;
+  height: 50px;
+  background-color: red;
+  z-index: 0;
+}
+
+.shouldNotStack {
+  position: absolute;
+  width: 150px;
+  height: 50px;
+  background-color: green;
+}
+
+.child {
+  position: relative;
+  top: 0px;
+  left: 0px;
+  width: 150px;
+  height: 50px;
+  background-color: green;
+  z-index: -1;
+}
+
+.shouldNotStack .child {
+  background-color: red;
+}
+
+#animatedOpacity {
+  top: 0px;
+}
+
+#animatedTransform {
+  top: 100px;
+}
+
+#animatedFilter {
+  top: 200px;
+}
+
+#animatedBackdrop {
+  top: 300px;
+}
+
+#animatedLeft {
+  top: 400px;
+}
+</style>
+
+<div id="animatedOpacity" class="shouldStack">
+  <div class="child">animated opacity</div>
+</div>
+<div id="animatedTransform" class="shouldStack">
+  <div class="child">animated transform</div>
+</div>
+<div id="animatedFilter" class="shouldStack">
+  <div class="child">animated filter</div>
+</div>
+<div id="animatedBackdrop" class="shouldStack">
+  <div class="child">animated backdrop-filter</div>
+</div>
+<div id="animatedLeft" class="shouldNotStack">
+  <div class="child">animated left</div>
+</div>
+
diff --git a/third_party/WebKit/LayoutTests/compositing/animation/animations-establish-stacking-context.html b/third_party/WebKit/LayoutTests/compositing/animation/animations-establish-stacking-context.html
new file mode 100644
index 0000000..a94cde406
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/animation/animations-establish-stacking-context.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<title>Animating opacity, transform, filter, backdrop-filter should establish a stacking context.</title>
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#side-effects-section">
+
+<style>
+.shouldStack {
+  position: absolute;
+  width: 150px;
+  height: 50px;
+  background-color: red;
+}
+
+.shouldNotStack {
+  position: absolute;
+  width: 150px;
+  height: 50px;
+  background-color: green;
+}
+
+.child {
+  position: relative;
+  top: 0px;
+  left: 0px;
+  width: 150px;
+  height: 50px;
+  background-color: green;
+  z-index: -1;
+}
+
+.shouldNotStack .child {
+  background-color: red;
+}
+
+#animatedOpacity {
+  /* Use a large duration so animation is effectively invisible. */
+  animation-duration: 100000s;
+  animation-name: opacity_frames;
+
+  top: 0px;
+}
+
+@keyframes opacity_frames {
+  to {
+    opacity: 0;
+  }
+}
+
+#animatedTransform {
+  animation-duration: 100000s;
+  animation-name: transform_frames;
+
+  top: 100px;
+}
+
+@keyframes transform_frames {
+  to {
+    transform: translateX(10px);
+  }
+}
+
+#animatedFilter {
+  animation-duration: 100000s;
+  animation-name: filter_frames;
+
+  top: 200px;
+}
+
+@keyframes filter_frames {
+  to {
+    filter: grayscale(50%);
+  }
+}
+
+#animatedBackdrop {
+  animation-duration: 100000s;
+  animation-name: backdrop_frames;
+
+  top: 300px;
+}
+
+@keyframes backdrop_frames {
+  to {
+    backdrop-filter: grayscale(50%);
+  }
+}
+
+#animatedLeft {
+  animation-duration: 100000s;
+  animation-name: left_frames;
+
+  top: 400px;
+}
+
+@keyframes left_frames {
+  to {
+    left: 10px;
+  }
+}
+</style>
+
+<div id="animatedOpacity" class="shouldStack">
+  <div class="child">animated opacity</div>
+</div>
+<div id="animatedTransform" class="shouldStack">
+  <div class="child">animated transform</div>
+</div>
+<div id="animatedFilter" class="shouldStack">
+  <div class="child">animated filter</div>
+</div>
+<div id="animatedBackdrop" class="shouldStack">
+  <div class="child">animated backdrop-filter</div>
+</div>
+<div id="animatedLeft" class="shouldNotStack">
+  <div class="child">animated left</div>
+</div>
+
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index c5315f0..8e417921 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -147891,6 +147891,16 @@
      {}
     ]
    ],
+   "feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html.headers": [
+    [
+     {}
+    ]
+   ],
    "feature-policy/experimental-features/resources/async-script.js": [
     [
      {}
@@ -147931,6 +147941,11 @@
      {}
     ]
    ],
+   "feature-policy/experimental-features/resources/lazyload-contents.html": [
+    [
+     {}
+    ]
+   ],
    "feature-policy/experimental-features/resources/parser-blocking-script.js": [
     [
      {}
@@ -219058,6 +219073,18 @@
      {}
     ]
    ],
+   "feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html": [
+    [
+     "/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html",
+     {}
+    ]
+   ],
+   "feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html": [
+    [
+     "/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html",
+     {}
+    ]
+   ],
    "feature-policy/experimental-features/sync-script.tentative.https.sub.html": [
     [
      "/feature-policy/experimental-features/sync-script.tentative.https.sub.html",
@@ -370491,12 +370518,28 @@
    "db2dcbc1929b9e1264855e9b80f77dfbda5d4f38",
    "support"
   ],
+  "feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html": [
+   "4cb8ca6fa168eeaf08fbf9474b0054b41d788af7",
+   "testharness"
+  ],
+  "feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html.headers": [
+   "d0bac47e01a7e903d78ffab7b73838f0852852d6",
+   "support"
+  ],
+  "feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html": [
+   "05053923d9cf39194aa6727fb8305d61ac52a495",
+   "testharness"
+  ],
+  "feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html.headers": [
+   "83b744e2bc4e09b771c7997fc044802f77f65407",
+   "support"
+  ],
   "feature-policy/experimental-features/resources/async-script.js": [
    "3c0ee6d02343891b0234f31c0fb229929ae1b24b",
    "support"
   ],
   "feature-policy/experimental-features/resources/common.js": [
-   "08d3aef9874894f03941a0dc74dd4061ebe021d3",
+   "10c28be7741b718794f264c0b720304b8c5b7cb7",
    "support"
   ],
   "feature-policy/experimental-features/resources/defer-script.js": [
@@ -370523,6 +370566,10 @@
    "73ca820915bbdccdf4fd2d3960c795f1cea8e181",
    "support"
   ],
+  "feature-policy/experimental-features/resources/lazyload-contents.html": [
+   "a6e98c24e6add4976571141ad2409e1cce96d173",
+   "support"
+  ],
   "feature-policy/experimental-features/resources/parser-blocking-script.js": [
    "c61efee8a0a15801d474fd8b384de01e565e37ce",
    "support"
@@ -395524,7 +395571,7 @@
    "support"
   ],
   "lint.whitelist": [
-   "7d579b6b343a23e6c039f309f362354c5aa5ba62",
+   "837a9d01a75baf99c490af64a0b17978b062e5bd",
    "support"
   ],
   "longtask-timing/META.yml": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-horizontal-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-horizontal-ref.html
new file mode 100644
index 0000000..be9155b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-horizontal-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <style>
+            .underline { text-decoration: underline; }
+            .overline { text-decoration: overline; }
+    </style>
+</head>
+<body lang="en">
+    <div class="overline">サンプル</div>
+    <div class="overline">サンプル</div>
+    <div class="underline">"text-underline-position: right" alone should be same as "auto right"</div>
+    <div class="underline">"text-underline-position: left" alone should be same as "auto left"</div>
+</body>
+</html>
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-vertical-ja-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-vertical-ja-ref.html
new file mode 100644
index 0000000..303655ab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-vertical-ja-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <style>
+            body { writing-mode: vertical-rl; }
+            .underline { text-decoration: underline; }
+            .overline { text-decoration: overline; }
+    </style>
+</head>
+<body lang="en">
+    <div>In vertical writing mode with lang=ja, default overline will be same as underline (lang=en). However, when we set text-underline-position to "under left" it should be shifted.</div>
+    <div class="underline">サンプル</div>
+    <div class="underline">サンプル</div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-vertical-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-vertical-ref.html
new file mode 100644
index 0000000..8c0bee6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/reference/text-decoration-underline-position-vertical-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <style>
+            body { writing-mode: vertical-rl; }
+            .underline { text-decoration: underline; }
+            .overline { text-decoration: overline; }
+    </style>
+</head>
+<body lang="en">
+    <div class="underline">サンプル</div>
+    <div class="underline">サンプル</div>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-horizontal.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-horizontal.html
new file mode 100644
index 0000000..e4d495e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-horizontal.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <link rel="help" href="https://www.w3.org/TR/css-text-decor-3/#text-underline-position-property">
+    <link rel="match" href="reference/text-decoration-underline-position-horizontal-ref.html">
+    <style>
+        .underline { text-decoration: underline; }
+        .overline { text-decoration: overline; }
+    </style>
+</head>
+<body lang="en">
+    <div class="overline" style="text-underline-position: under right">サンプル</div>
+    <div class="overline" style="text-underline-position: under left">サンプル</div>
+    <div class="underline" style="text-underline-position: right">"text-underline-position: right" alone should be same as "auto right"</div>
+    <div class="underline" style="text-underline-position: left">"text-underline-position: left" alone should be same as "auto left"</div>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-vertical-ja.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-vertical-ja.html
new file mode 100644
index 0000000..6f41e939
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-vertical-ja.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <link rel="help" href="https://www.w3.org/TR/css-text-decor-3/#text-underline-position-property">
+    <link rel="match" href="reference/text-decoration-underline-position-vertical-ja-ref.html">
+    <style>
+        body { writing-mode: vertical-rl; }
+        .underline { text-decoration: underline; }
+        .overline { text-decoration: overline; }
+    </style>
+</head>
+<body lang="ja">
+    <div>In vertical writing mode with lang=ja, default overline will be same as underline (lang=en). However, when we set text-underline-position to "under left" it should be shifted.</div>
+    <div class="underline" style="text-underline-position: under left">サンプル</div>
+    <div class="overline">サンプル</div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-vertical.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-vertical.html
new file mode 100644
index 0000000..9f60bc1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text-decor/text-decoration-underline-position-vertical.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <link rel="help" href="https://www.w3.org/TR/css-text-decor-3/#text-underline-position-property">
+    <link rel="match" href="reference/text-decoration-underline-position-vertical-ref.html">
+    <style>
+        body { writing-mode: vertical-rl; }
+        .underline { text-decoration: underline; }
+        .overline { text-decoration: overline; }
+    </style>
+</head>
+<body lang="en">
+    <div class="overline" style="text-underline-position: right">サンプル</div>
+    <div class="underline" style="text-underline-position: left">サンプル</div>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html
new file mode 100644
index 0000000..4cb8ca6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/feature-policy/experimental-features/resources/common.js"></script>
+<style>
+html, body {
+  height: 100%;
+  width: 100%;
+}
+
+iframe {
+  width: 400px;
+  height: 400px;
+  margin: 10px;
+}
+
+.spacer {
+  width: 100%;
+  height: 300%;
+}
+</style>
+<div class="spacer"></div>
+<script>
+  let cross_origin_url =
+      "http://{{hosts[alt][www]}}:{{ports[http][0]}}/" +
+      "feature-policy/experimental-features/resources/lazyload-contents.html";
+
+  let load_timeout = 100; // ms
+  let expected_timeout_msg = false;
+
+  window.scrollTo(0, 0);
+
+  // Sanity-check: Make sure lazyload='on' works as intended.
+  promise_test(async(t) => {
+    // Add a frame with lazyload="on".
+    let frame_on = createIframe(document.body, {
+        id: "ON",
+        lazyload: "on",
+        src: `${cross_origin_url}?id=ON`
+      });
+    // Sanity-check: The frame is not visible.
+    assert_greater_than(
+        frame_on.getBoundingClientRect().top,
+        window.innerHeight * 2,
+        "Unexpected position for <iframe> with ID 'ON'.");
+    let msg_or_timeout_attr_on =
+        await waitForMessageOrTimeout(t, "ON", load_timeout);
+    assert_equals(msg_or_timeout_attr_on,
+                  expected_timeout_msg,
+                  "With lazyload='on', the frame should not load.");
+  }, "Sanity-check: Contents do not load immediately (no eager-loading) " +
+     "when the lazyload attribute is 'on' and frame is in viewport.");
+
+
+  // Verify that when 'lazyload' policy is disabled,  lazyload='off' and
+  // lazyload='auto' behave the same.
+  promise_test(async(t) => {
+    // Add a frame with lazyload="off".
+    let frame_on = createIframe(document.body, {
+        id: "OFF",
+        lazyload: "off",
+        src: `${cross_origin_url}?id=OFF`
+      });
+    // Sanity-check: The frame is not visible.
+    assert_greater_than(
+        frame_on.getBoundingClientRect().top,
+        window.innerHeight * 2,
+        "Unexpected position for <iframe> with ID 'OFF'.");
+    let msg_or_timeout_attr_off =
+        await waitForMessageOrTimeout(t, "OFF", load_timeout);
+
+    // Now do the same for lazyload='auto'.
+    let frame_auto = createIframe(document.body, {
+        id: "AUTO",
+        lazyload: "auto",
+        src: `${cross_origin_url}?id=AUTO`
+    });
+    // Sanity-check: The frame is not visible.
+    assert_greater_than(
+        frame_on.getBoundingClientRect().top,
+        window.innerHeight * 2,
+        "Unexpected position for <iframe> with ID 'AUTO'.");
+    let msg_or_timeout_attr_auto =
+        await waitForMessageOrTimeout(t, "AUTO", load_timeout);
+
+    // The result should be the same.
+    assert_equals(
+          msg_or_timeout_attr_off,
+          msg_or_timeout_attr_auto,
+          "lazyload='off' not treated as 'auto'.");
+  }, "When 'lazyload' feature is disabled, a frame cannot avoid lazyloading " +
+     "by setting 'lazyload' attribute to 'off'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html.headers
new file mode 100644
index 0000000..d0bac47
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: lazyload 'none'
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html
new file mode 100644
index 0000000..0505392
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/feature-policy/experimental-features/resources/common.js"></script>
+<style>
+html, body {
+  height: 100%;
+  width: 100%;
+}
+
+iframe {
+  width: 400px;
+  height: 400px;
+  margin: 10px;
+}
+
+.spacer {
+  width: 100%;
+  height: 300%;
+}
+</style>
+<div class="spacer"></div>
+<script>
+  let cross_origin_url =
+      "http://{{hosts[alt][www]}}:{{ports[http][0]}}/" +
+      "feature-policy/experimental-features/resources/lazyload-contents.html";
+
+  let load_timeout = 100; // ms
+  let expected_timeout_msg = false;
+  let expected_load_msg = "This page is lazyloaded.";
+
+  window.scrollTo(0, 0);
+
+  // Sanity-check: Make sure lazyload='on' works as intended.
+  promise_test(async(t) => {
+    // Add a frame with lazyload="on".
+    let frame_on = createIframe(document.body, {
+        id: "ON",
+        lazyload: "on",
+        src: `${cross_origin_url}?id=ON`
+      });
+    // Sanity-check: The frame is not visible.
+    assert_greater_than(
+        frame_on.getBoundingClientRect().top,
+        window.innerHeight * 2,
+        "Unexpected position for <iframe> with ID 'ON'.");
+    let msg_or_timeout_attr_on =
+        await waitForMessageOrTimeout(t, "ON", load_timeout);
+    assert_equals(msg_or_timeout_attr_on,
+                  expected_timeout_msg,
+                  "With lazyload='on', the frame should not load.");
+  }, "Sanity-check: Contents do not load immediately (no eager-loading) " +
+     "when the lazyload attribute is 'on' and frame is in viewport.");
+
+  // When feature is enabled, a frame can turn off lazy loading by setting the
+  // attribute to 'off'.
+  promise_test(async(t) => {
+    // Add a frame with lazyload="off".
+    let frame_off = createIframe(document.body, {
+        id: "OFF",
+        lazyload: "off",
+        src: `${cross_origin_url}?id=OFF`
+      });
+    // Sanity-check: The frame is not visible.
+    assert_greater_than(
+        frame_off.getBoundingClientRect().top,
+        window.innerHeight * 2,
+        "Unexpected position for <iframe> with ID 'OFF'.");
+    let msg_or_timeout_attr_off =
+        await waitForMessageOrTimeout(t, "OFF", load_timeout);
+
+    assert_equals(msg_or_timeout_attr_off,
+                  expected_load_msg,
+                  "With lazyload='off', the frame should load.");
+  }, "When 'lazyload' feature is enabled, a frame can avoid lazyloading by " +
+     "setting 'lazyload' attribute to 'off'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html.headers
new file mode 100644
index 0000000..83b744e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: lazyload *
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/common.js b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/common.js
index 08d3aef..10c28be 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/common.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/common.js
@@ -32,3 +32,29 @@
 }
 
 window.addEventListener("message", onMessage);
+
+// Waits for |load_timeout| before resolving the promise. It will resolve the
+// promise sooner if a message event with |e.data.id| of |id| is received.
+// In such a case the response is the contents of the message |e.data.contents|.
+// Otherwise, returns false (when timeout occurs).
+function waitForMessageOrTimeout(t, id, load_timeout) {
+  return new Promise((resolve) => {
+      window.addEventListener(
+        "message",
+        (e) => {
+          if (!e.data || e.data.id !== id)
+            return;
+          resolve(e.data.contents);
+        }
+      );
+      t.step_timeout(() => { resolve(false); }, load_timeout);
+  });
+}
+
+function createIframe(container, attributes) {
+  var new_iframe = document.createElement("iframe");
+  for (attr_name in attributes)
+    new_iframe.setAttribute(attr_name, attributes[attr_name]);
+  container.appendChild(new_iframe);
+  return new_iframe;
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/lazyload-contents.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/lazyload-contents.html
new file mode 100644
index 0000000..a6e98c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/experimental-features/resources/lazyload-contents.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<body>
+  <p>This page is lazyloaded.</p>
+  <script>
+    let query_index = window.location.href.indexOf("?id=");
+    let id = window.location.href.substr(query_index + 4);
+    window.addEventListener("load", () => {
+      let p = document.querySelector("p");
+      let contents = p ? p.innerHTML : "null";
+      window.parent.postMessage({"id": id, "contents": contents}, "*");
+    });
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist b/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
index 7d579b6..837a9d01 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
+++ b/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
@@ -650,6 +650,8 @@
 CSS-COLLIDING-REF-NAME: css/css-grid/grid-items/percentage-size-subitems-001-ref.html
 CSS-COLLIDING-REF-NAME: css/css-contain/reference/contain-size-button-001-ref.html
 CSS-COLLIDING-REF-NAME: css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-button-001-ref.html
+CSS-COLLIDING-REF-NAME: css/css-contain/reference/contain-size-grid-001-ref.html
+CSS-COLLIDING-REF-NAME: css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-grid-001-ref.html
 CSS-COLLIDING-SUPPORT-NAME: css/css-backgrounds/support/red.png
 CSS-COLLIDING-SUPPORT-NAME: css/compositing/mix-blend-mode/support/red.png
 CSS-COLLIDING-SUPPORT-NAME: css/compositing/background-blending/support/red.png
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-all-ascii.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-all-ascii.html
index 7959247..126001c 100644
--- a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-all-ascii.html
+++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-all-ascii.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <style>
-#break-test {
+#container {
   word-break:break-all;
   font:50px/1 Ahem;
   width:3em;
@@ -11,52 +11,13 @@
 }
 </style>
 <div id="result"></div>
-<div id="break-test"></div>
+<div id="container"></div>
+<script src="../../text/resources/line-break-test.js"></script>
 <script>
-var beginChar = 33;
-var endChar = 127;
-var breakTest = document.getElementById("break-test");
-var breakTestFontsize = parseFloat(getComputedStyle(breakTest).fontSize);
-var nbsp = String.fromCharCode(0xA0);
-nbsp = nbsp + nbsp;
+let matrix = new LineBreakTest(33, 127);
+result.textContent = matrix.toResultString();
+container.remove();
 
-class BreakTest {
-  constructor(ch0, ch1) {
-    this.element = document.createElement('div');
-    this.element.textContent = nbsp + String.fromCharCode(ch0) + String.fromCharCode(ch1);
-    breakTest.appendChild(this.element);
-  }
-
-  canBreak() {
-    return this.element.offsetHeight / breakTestFontsize > 1.9;
-  }
-
-  static GetLineBreakMatrix() {
-    var matrix = [];
-    for (var last = beginChar; last < endChar; last++) {
-      var canBreakBefore = [];
-      for (var current = beginChar; current < endChar; current++)
-        canBreakBefore.push(new BreakTest(last, current));
-      matrix.push(canBreakBefore);
-    }
-    return matrix;
-  }
-}
-
-var matrix = BreakTest.GetLineBreakMatrix();
-
-var header = [];
-for (var i = 0; i < matrix.length; i++)
-  header.push(String.fromCharCode(beginChar + i));
-var rows = ["  " + header.join("")];
-for (var i = 0; i < matrix.length; i++) {
-  rows.push(String.fromCharCode(beginChar + i) + " " + matrix[i].map(function (breakTest) {
-    return breakTest.canBreak() ? "/" : "X";
-  }).join(""));
-}
-result.textContent = rows.join("\n");
-
-breakTest.remove();
 if (window.testRunner)
-    testRunner.dumpAsText();
+  testRunner.dumpAsText();
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/text/line-break-ascii-expected.txt b/third_party/WebKit/LayoutTests/fast/text/line-break-ascii-expected.txt
index 8efbb9a..43efdc2 100644
--- a/third_party/WebKit/LayoutTests/fast/text/line-break-ascii-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/text/line-break-ascii-expected.txt
@@ -93,4 +93,3 @@
 | XXXXXXX/XXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXX
 } XXXXXXX/XXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXX
 ~ XXXXXXX/XXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXX
-
diff --git a/third_party/WebKit/LayoutTests/fast/text/line-break-ascii.html b/third_party/WebKit/LayoutTests/fast/text/line-break-ascii.html
index e649935..78ab567a 100644
--- a/third_party/WebKit/LayoutTests/fast/text/line-break-ascii.html
+++ b/third_party/WebKit/LayoutTests/fast/text/line-break-ascii.html
@@ -1,54 +1,22 @@
 <!DOCTYPE html>
 <style>
-#break-test {
-    font:50px/1 Ahem;
-    width:3em;
+#container {
+  font:50px/1 Ahem;
+  width:3em;
 }
 #result {
-    font:15px/1 monospace;
-    white-space:pre;
+  font:15px/1 monospace;
+  white-space:pre;
 }
 </style>
 <div id="result"></div>
-<div id="break-test"></div>
+<div id="container"></div>
+<script src="resources/line-break-test.js"></script>
 <script>
-var beginChar = 33;
-var endChar = 127;
-var breakTest = document.getElementById("break-test");
-var breakTestFontsize = parseFloat(getComputedStyle(breakTest).fontSize);
-var nbsp = String.fromCharCode(0xA0);
-nbsp = nbsp + nbsp;
+let matrix = new LineBreakTest(33, 127);
+result.textContent = matrix.toResultString();
+container.remove();
 
-var matrix = getLineBreakMatrix();
-
-var header = [];
-for (var i = 0; i < matrix.length; i++)
-    header.push(String.fromCharCode(beginChar + i));
-var rows = ["  " + header.join("")];
-for (var i = 0; i < matrix.length; i++) {
-    rows.push(String.fromCharCode(beginChar + i) + " " + matrix[i].map(function (canBreak) {
-        return canBreak ? "/" : "X";
-    }).join(""));
-}
-result.textContent = rows.join("\n");
-
-function getLineBreakMatrix() {
-    var matrix = [];
-    for (var last = beginChar; last < endChar; last++) {
-        var canBreakBefore = [];
-        for (var current = beginChar; current < endChar; current++)
-            canBreakBefore.push(canBreakBetween(last, current));
-        matrix.push(canBreakBefore);
-    }
-    return matrix;
-}
-
-function canBreakBetween(last, current) {
-    breakTest.textContent = nbsp + String.fromCharCode(last) + String.fromCharCode(current);
-    return breakTest.offsetHeight / breakTestFontsize > 1.9;
-}
-
-breakTest.textContent = "";
 if (window.testRunner)
-    testRunner.dumpAsText();
+  testRunner.dumpAsText();
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/text/resources/line-break-test.js b/third_party/WebKit/LayoutTests/fast/text/resources/line-break-test.js
new file mode 100644
index 0000000..5c00def6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/resources/line-break-test.js
@@ -0,0 +1,45 @@
+let container = document.getElementById("container");
+let breakTestFontsize = parseFloat(getComputedStyle(container).fontSize);
+let nbsp = String.fromCharCode(0xA0);
+nbsp = nbsp + nbsp;
+
+class LineBreakTestElement {
+  constructor(last, current) {
+    let element = document.createElement('div');
+    element.textContent = nbsp + String.fromCharCode(last) + String.fromCharCode(current);
+    container.appendChild(element);
+    this.element = element;
+  }
+
+  get canBreak() {
+    return this.element.offsetHeight / breakTestFontsize > 1.9;
+  }
+}
+
+class LineBreakTest {
+  constructor(begin, end) {
+    let rows = [];
+    for (let last = begin; last < end; last++) {
+      let row = [];
+      for (let current = begin; current < end; current++)
+        row.push(new LineBreakTestElement(last, current));
+      rows.push(row);
+    }
+    this.begin = begin;
+    this.rows = rows;
+  }
+
+  toResultString() {
+    let header = [];
+    for (let i = 0; i < this.rows.length; i++)
+      header.push(String.fromCharCode(this.begin + i));
+    let rows = ["  " + header.join("")];
+    for (let i = 0; i < this.rows.length; i++) {
+      let row = String.fromCharCode(this.begin + i) + " " +
+          this.rows[i].map((test) => test.canBreak ? "/" : "X")
+          .join("");
+      rows.push(row);
+    }
+    return rows.join("\n");
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/animations/rotate-transform-equivalent-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/animations/rotate-transform-equivalent-expected.png
new file mode 100644
index 0000000..ad43755
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/animations/rotate-transform-equivalent-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png
new file mode 100644
index 0000000..7beac27
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.txt
new file mode 100644
index 0000000..44d8690
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.txt
@@ -0,0 +1,55 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 854
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x854 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutNGBlockFlow {HTML} at (0,0) size 785x854
+    LayoutNGBlockFlow {BODY} at (8,8) size 769x838
+      LayoutNGBlockFlow {DIV} at (0,0) size 769x149
+        LayoutNGBlockFlow {DIV} at (10,10) size 268x129
+          LayoutNGBlockFlow {DIV} at (12,12) size 110x100 [bgcolor=#000000] [border: (20px solid #FFFFFF)]
+          LayoutText {#text} at (132,107) size 4x19
+            text run at (132,107) width 4: " "
+          LayoutNGBlockFlow {DIV} at (146,12) size 110x100 [bgcolor=#000000] [border: (20px double #FFFFFF)]
+          LayoutText {#text} at (0,0) size 0x0
+        LayoutText {#text} at (288,117) size 4x19
+          text run at (288,117) width 4: " "
+        LayoutNGBlockFlow {DIV} at (302,10) size 268x129 [bgcolor=#808080]
+          LayoutNGBlockFlow {DIV} at (12,12) size 110x100 [bgcolor=#FFFFFF] [border: (20px solid #0000FF80)]
+          LayoutText {#text} at (132,107) size 4x19
+            text run at (132,107) width 4: " "
+          LayoutNGBlockFlow {DIV} at (146,12) size 110x100 [bgcolor=#FFFFFF] [border: (20px double #0000FF80)]
+          LayoutText {#text} at (0,0) size 0x0
+        LayoutText {#text} at (0,0) size 0x0
+layer at (8,157) size 769x149
+  LayoutNGBlockFlow {DIV} at (0,149) size 769x149
+    LayoutNGBlockFlow {DIV} at (10,10) size 268x129
+      LayoutNGBlockFlow {DIV} at (12,12) size 110x100 [bgcolor=#000000] [border: (20px solid #FFFFFF)]
+      LayoutText {#text} at (132,107) size 4x19
+        text run at (132,107) width 4: " "
+      LayoutNGBlockFlow {DIV} at (146,12) size 110x100 [bgcolor=#000000] [border: (20px double #FFFFFF)]
+      LayoutText {#text} at (0,0) size 0x0
+    LayoutText {#text} at (288,117) size 4x19
+      text run at (288,117) width 4: " "
+    LayoutNGBlockFlow {DIV} at (302,10) size 268x129 [bgcolor=#808080]
+      LayoutNGBlockFlow {DIV} at (12,12) size 110x100 [bgcolor=#FFFFFF] [border: (20px solid #0000FF80)]
+      LayoutText {#text} at (132,107) size 4x19
+        text run at (132,107) width 4: " "
+      LayoutNGBlockFlow {DIV} at (146,12) size 110x100 [bgcolor=#FFFFFF] [border: (20px double #0000FF80)]
+      LayoutText {#text} at (0,0) size 0x0
+    LayoutText {#text} at (0,0) size 0x0
+layer at (8,306) size 159x540 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutNGBlockFlow {DIV} at (0,298) size 159x540
+    LayoutNGBlockFlow {DIV} at (10,10) size 139x248
+      LayoutNGBlockFlow {DIV} at (17,12) size 110x100 [bgcolor=#000000] [border: (20px solid #FFFFFF)]
+      LayoutText {#text} at (3,122) size 19x4
+        text run at (3,122) width 4: " "
+      LayoutNGBlockFlow {DIV} at (17,136) size 110x100 [bgcolor=#000000] [border: (20px double #FFFFFF)]
+      LayoutText {#text} at (0,0) size 0x0
+    LayoutText {#text} at (13,268) size 19x4
+      text run at (13,268) width 4: " "
+    LayoutNGBlockFlow {DIV} at (10,282) size 139x248 [bgcolor=#808080]
+      LayoutNGBlockFlow {DIV} at (17,12) size 110x100 [bgcolor=#FFFFFF] [border: (20px solid #0000FF80)]
+      LayoutText {#text} at (3,122) size 19x4
+        text run at (3,122) width 4: " "
+      LayoutNGBlockFlow {DIV} at (17,136) size 110x100 [bgcolor=#FFFFFF] [border: (20px double #0000FF80)]
+      LayoutText {#text} at (0,0) size 0x0
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/reflections/opacity-reflection-transform-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/reflections/opacity-reflection-transform-expected.png
index 637be0e..c473dd6 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/reflections/opacity-reflection-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/reflections/opacity-reflection-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/selection/emphasis-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/selection/emphasis-expected.png
new file mode 100644
index 0000000..970db4c6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/selection/emphasis-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/video-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/video-aspect-ratio-expected.png
index b007d07..2d641c3 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/video-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/video-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/add-background-property-on-root-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/add-background-property-on-root-expected.txt
index 010e22c..45dbe7a 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/add-background-property-on-root-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/add-background-property-on-root-expected.txt
@@ -25,7 +25,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [8, 8, 100, 100],
-          "reason": "background"
+          "reason": "disappeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/remove-background-property-on-root-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/remove-background-property-on-root-expected.txt
index 14ec7ce..7cd30df0 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/remove-background-property-on-root-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/remove-background-property-on-root-expected.txt
@@ -25,7 +25,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [8, 8, 100, 100],
-          "reason": "background"
+          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/android/fullscreen/video-overlay-scroll-expected.txt b/third_party/WebKit/LayoutTests/virtual/android/fullscreen/video-overlay-scroll-expected.txt
new file mode 100644
index 0000000..af4b383
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/android/fullscreen/video-overlay-scroll-expected.txt
@@ -0,0 +1,27 @@
+EVENT(fullscreenchange)
+END OF TEST
+{
+  "layers": [
+    {
+      "name": "LayoutVideo (positioned) VIDEO id='video'",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutFlexibleBox (relative positioned) DIV class='phase-pre-ready state-no-source use-default-poster sizing-medium'",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#333333"
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutFlexibleBox DIV",
+      "bounds": [800, 600]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/virtual/android/fullscreen/video-overlay-scroll.html b/third_party/WebKit/LayoutTests/virtual/android/fullscreen/video-overlay-scroll.html
new file mode 100644
index 0000000..896bfeb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/android/fullscreen/video-overlay-scroll.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<body>
+  <script src="../../../fullscreen/full-screen-test.js"></script>
+  <div style="width: 100px; height: 1000px"></div>
+  <video id="video"></video>
+  <pre id="layertree"></pre>
+  <script>
+    if (window.testRunner)
+      testRunner.dumpAsText();
+
+    var clientRect;
+    var video = document.getElementById('video');
+
+    window.scrollTo(0, 1000);
+    waitForEventAndEnd(document, 'fullscreenchange', function(){
+      document.getElementById("layertree").innerText = internals.elementLayerTreeAsText(document.fullscreenElement);
+    });
+
+    runWithKeyDown(function(){
+      video.requestFullscreen();
+    });
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/virtual/lazyload-policy/external/wpt/feature-policy/experimental-features/lazyload/README.txt b/third_party/WebKit/LayoutTests/virtual/lazyload-policy/external/wpt/feature-policy/experimental-features/lazyload/README.txt
new file mode 100644
index 0000000..639e356
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/lazyload-policy/external/wpt/feature-policy/experimental-features/lazyload/README.txt
@@ -0,0 +1,2 @@
+# This suite runs the tests in virtual/lazyload-policy/external/wpt/feature-policy/experimental-features/lazyload/
+# with --enable-blink-features=LazyFrameLoading.
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate.html
index 784cc6d..0590b40 100644
--- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate.html
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate.html
@@ -14,7 +14,7 @@
   animate(currentTime, effect) {
     if (!this.animated)
         console.log("test animator animate called.");
-
+    effect.localTime = 0;
     this.animated = true;
   }
 });
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn
index f5afc85..bfdd42b3 100644
--- a/third_party/android_deps/BUILD.gn
+++ b/third_party/android_deps/BUILD.gn
@@ -109,6 +109,81 @@
     ":com_android_support_support_vector_drawable_java",
   ]
 }
+java_group("google_play_services_basement_java") {
+  deps = [
+    ":com_google_android_gms_play_services_basement_java",
+  ]
+}
+java_group("google_play_services_tasks_java") {
+  deps = [
+    ":com_google_android_gms_play_services_tasks_java",
+  ]
+}
+java_group("google_play_services_base_java") {
+  deps = [
+    ":com_google_android_gms_play_services_base_java",
+  ]
+}
+java_group("google_play_services_auth_base_java") {
+  deps = [
+    ":com_google_android_gms_play_services_auth_base_java",
+  ]
+}
+java_group("google_play_services_auth_api_phone_java") {
+  deps = [
+    ":com_google_android_gms_play_services_auth_api_phone_java",
+  ]
+}
+java_group("google_play_services_auth_java") {
+  deps = [
+    ":com_google_android_gms_play_services_auth_java",
+  ]
+}
+java_group("google_play_services_cast_java") {
+  deps = [
+    ":com_google_android_gms_play_services_cast_java",
+  ]
+}
+java_group("google_play_services_cast_framework_java") {
+  deps = [
+    ":com_google_android_gms_play_services_cast_framework_java",
+  ]
+}
+java_group("google_play_services_iid_java") {
+  deps = [
+    ":com_google_android_gms_play_services_iid_java",
+  ]
+}
+java_group("google_play_services_instantapps_java") {
+  deps = [
+    ":com_google_android_gms_play_services_instantapps_java",
+  ]
+}
+java_group("google_play_services_gcm_java") {
+  deps = [
+    ":com_google_android_gms_play_services_gcm_java",
+  ]
+}
+java_group("google_play_services_location_java") {
+  deps = [
+    ":com_google_android_gms_play_services_location_java",
+  ]
+}
+java_group("google_play_services_vision_java") {
+  deps = [
+    ":com_google_android_gms_play_services_vision_java",
+  ]
+}
+java_group("google_play_services_vision_common_java") {
+  deps = [
+    ":com_google_android_gms_play_services_vision_common_java",
+  ]
+}
+java_group("google_play_services_fido_java") {
+  deps = [
+    ":com_google_android_gms_play_services_fido_java",
+  ]
+}
 
 # The dependencies below don't seem to be used but break downstream builds
 # when not defined.
@@ -490,6 +565,12 @@
   ]
 }
 
+java_prebuilt("javax_inject_javax_inject_java") {
+  jar_path = "libs/javax_inject_javax_inject/javax.inject-1.jar"
+  output_name = "javax_inject_javax_inject"
+  supports_android = true
+}
+
 java_prebuilt("android_arch_core_common_java") {
   jar_path = "libs/android_arch_core_common/common-1.0.0.jar"
   output_name = "android_arch_core_common"
@@ -655,6 +736,12 @@
   ]
 }
 
+java_prebuilt("com_google_code_findbugs_jsr305_java") {
+  jar_path = "libs/com_google_code_findbugs_jsr305/jsr305-1.3.9.jar"
+  output_name = "com_google_code_findbugs_jsr305"
+  visibility = [ ":*" ]
+}
+
 java_prebuilt("com_google_dagger_dagger_producers_java") {
   jar_path = "libs/com_google_dagger_dagger_producers/dagger-producers-2.17.jar"
   output_name = "com_google_dagger_dagger_producers"
@@ -663,6 +750,7 @@
     ":com_google_dagger_dagger_java",
     ":com_google_guava_guava_java",
     ":javax_inject_javax_inject_java",
+    ":org_checkerframework_checker_compat_qual_java",
   ]
 }
 
@@ -678,6 +766,12 @@
   ]
 }
 
+java_prebuilt("com_google_errorprone_error_prone_annotations_java") {
+  jar_path = "libs/com_google_errorprone_error_prone_annotations/error_prone_annotations-2.1.3.jar"
+  output_name = "com_google_errorprone_error_prone_annotations"
+  visibility = [ ":*" ]
+}
+
 java_prebuilt("com_google_errorprone_javac_shaded_java") {
   jar_path =
       "libs/com_google_errorprone_javac_shaded/javac-shaded-9-dev-r4023-3.jar"
@@ -696,9 +790,23 @@
 }
 
 java_prebuilt("com_google_guava_guava_java") {
-  jar_path = "libs/com_google_guava_guava/guava-25.0.jar"
+  jar_path = "libs/com_google_guava_guava/guava-25.0-jre.jar"
   output_name = "com_google_guava_guava"
   visibility = [ ":*" ]
+  deps = [
+    ":com_google_code_findbugs_jsr305_java",
+    ":com_google_errorprone_error_prone_annotations_java",
+    ":com_google_j2objc_j2objc_annotations_java",
+    ":org_checkerframework_checker_compat_qual_java",
+    ":org_codehaus_mojo_animal_sniffer_annotations_java",
+  ]
+}
+
+java_prebuilt("com_google_j2objc_j2objc_annotations_java") {
+  jar_path =
+      "libs/com_google_j2objc_j2objc_annotations/j2objc-annotations-1.1.jar"
+  output_name = "com_google_j2objc_j2objc_annotations"
+  visibility = [ ":*" ]
 }
 
 java_prebuilt("com_squareup_javapoet_java") {
@@ -713,9 +821,15 @@
   visibility = [ ":*" ]
 }
 
-java_prebuilt("javax_inject_javax_inject_java") {
-  jar_path = "libs/javax_inject_javax_inject/javax.inject-1.jar"
-  output_name = "javax_inject_javax_inject"
-  supports_android = true
+java_prebuilt("org_checkerframework_checker_compat_qual_java") {
+  jar_path = "libs/org_checkerframework_checker_compat_qual/checker-compat-qual-2.3.0.jar"
+  output_name = "org_checkerframework_checker_compat_qual"
+  visibility = [ ":*" ]
+}
+
+java_prebuilt("org_codehaus_mojo_animal_sniffer_annotations_java") {
+  jar_path = "libs/org_codehaus_mojo_animal_sniffer_annotations/animal-sniffer-annotations-1.14.jar"
+  output_name = "org_codehaus_mojo_animal_sniffer_annotations"
+  visibility = [ ":*" ]
 }
 # === Generated Code End ===
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json
index 496c1b1a..99c7d330 100644
--- a/third_party/android_deps/additional_readme_paths.json
+++ b/third_party/android_deps/additional_readme_paths.json
@@ -46,14 +46,19 @@
     "libs/com_google_android_gms_play_services_vision",
     "libs/com_google_android_gms_play_services_vision_common",
     "libs/com_google_android_play_core",
+    "libs/com_google_code_findbugs_jsr305",
     "libs/com_google_dagger_dagger",
     "libs/com_google_dagger_dagger_compiler",
     "libs/com_google_dagger_dagger_producers",
     "libs/com_google_dagger_dagger_spi",
+    "libs/com_google_errorprone_error_prone_annotations",
     "libs/com_google_errorprone_javac_shaded",
     "libs/com_google_googlejavaformat_google_java_format",
     "libs/com_google_guava_guava",
+    "libs/com_google_j2objc_j2objc_annotations",
     "libs/com_squareup_javapoet",
     "libs/javax_annotation_jsr250_api",
-    "libs/javax_inject_javax_inject"
+    "libs/javax_inject_javax_inject",
+    "libs/org_checkerframework_checker_compat_qual",
+    "libs/org_codehaus_mojo_animal_sniffer_annotations"
 ]
diff --git a/third_party/android_deps/libs/android_arch_core_common/cipd.yaml b/third_party/android_deps/libs/android_arch_core_common/cipd.yaml
index ac5c8bb8..265ca55 100644
--- a/third_party/android_deps/libs/android_arch_core_common/cipd.yaml
+++ b/third_party/android_deps/libs/android_arch_core_common/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0
 package: chromium/third_party/android_deps/libs/android_arch_core_common
-description: Android Arch-Common
+description: "Android Arch-Common"
 data:
 - file: common-1.0.0.jar
diff --git a/third_party/android_deps/libs/android_arch_lifecycle_common/cipd.yaml b/third_party/android_deps/libs/android_arch_lifecycle_common/cipd.yaml
index 0a25b201..3eb9d7ea 100644
--- a/third_party/android_deps/libs/android_arch_lifecycle_common/cipd.yaml
+++ b/third_party/android_deps/libs/android_arch_lifecycle_common/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0
 package: chromium/third_party/android_deps/libs/android_arch_lifecycle_common
-description: Android Lifecycle-Common
+description: "Android Lifecycle-Common"
 data:
 - file: common-1.0.0.jar
diff --git a/third_party/android_deps/libs/android_arch_lifecycle_runtime/cipd.yaml b/third_party/android_deps/libs/android_arch_lifecycle_runtime/cipd.yaml
index ecd9a6a5..4aa3b10 100644
--- a/third_party/android_deps/libs/android_arch_lifecycle_runtime/cipd.yaml
+++ b/third_party/android_deps/libs/android_arch_lifecycle_runtime/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0
 package: chromium/third_party/android_deps/libs/android_arch_lifecycle_runtime
-description: Android Lifecycle Runtime
+description: "Android Lifecycle Runtime"
 data:
 - file: runtime-1.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_animated_vector_drawable/cipd.yaml b/third_party/android_deps/libs/com_android_support_animated_vector_drawable/cipd.yaml
index 4e9678d..652e316 100644
--- a/third_party/android_deps/libs/com_android_support_animated_vector_drawable/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_animated_vector_drawable/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_animated_vector_drawable
-description: Android Support AnimatedVectorDrawable
+description: "Android Support AnimatedVectorDrawable"
 data:
 - file: animated-vector-drawable-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_appcompat_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_appcompat_v7/cipd.yaml
index 46f75c4..f85a169 100644
--- a/third_party/android_deps/libs/com_android_support_appcompat_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_appcompat_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_appcompat_v7
-description: Android AppCompat Library v7
+description: "Android AppCompat Library v7"
 data:
 - file: appcompat-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_cardview_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_cardview_v7/cipd.yaml
index 98c9bdb..a2c7cce 100644
--- a/third_party/android_deps/libs/com_android_support_cardview_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_cardview_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_cardview_v7
-description: Android Support CardView v7
+description: "Android Support CardView v7"
 data:
 - file: cardview-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_design/cipd.yaml b/third_party/android_deps/libs/com_android_support_design/cipd.yaml
index 255e245d..0f80ad5 100644
--- a/third_party/android_deps/libs/com_android_support_design/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_design/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_design
-description: Android Design Support Library
+description: "Android Design Support Library"
 data:
 - file: design-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_gridlayout_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_gridlayout_v7/cipd.yaml
index 9da5681d..987ac58c 100644
--- a/third_party/android_deps/libs/com_android_support_gridlayout_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_gridlayout_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_gridlayout_v7
-description: Android Support Grid Layout
+description: "Android Support Grid Layout"
 data:
 - file: gridlayout-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_leanback_v17/cipd.yaml b/third_party/android_deps/libs/com_android_support_leanback_v17/cipd.yaml
index 1b5fe75..878a8bd0 100644
--- a/third_party/android_deps/libs/com_android_support_leanback_v17/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_leanback_v17/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_leanback_v17
-description: Android Support Leanback v17
+description: "Android Support Leanback v17"
 data:
 - file: leanback-v17-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_mediarouter_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_mediarouter_v7/cipd.yaml
index 676e1c3..d938c29 100644
--- a/third_party/android_deps/libs/com_android_support_mediarouter_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_mediarouter_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_mediarouter_v7
-description: Android MediaRouter Support Library
+description: "Android MediaRouter Support Library"
 data:
 - file: mediarouter-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_multidex/cipd.yaml b/third_party/android_deps/libs/com_android_support_multidex/cipd.yaml
index fbcde3fab..e6a4599 100644
--- a/third_party/android_deps/libs/com_android_support_multidex/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_multidex/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_multidex
-description: Android Multi-Dex Library
+description: "Android Multi-Dex Library"
 data:
 - file: multidex-1.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_palette_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_palette_v7/cipd.yaml
index 4ea30594..97ca1741 100644
--- a/third_party/android_deps/libs/com_android_support_palette_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_palette_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_palette_v7
-description: Android Support Palette v7
+description: "Android Support Palette v7"
 data:
 - file: palette-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_preference_leanback_v17/cipd.yaml b/third_party/android_deps/libs/com_android_support_preference_leanback_v17/cipd.yaml
index 745c284a..d40a052 100644
--- a/third_party/android_deps/libs/com_android_support_preference_leanback_v17/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_preference_leanback_v17/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_preference_leanback_v17
-description: Android Support Leanback Preference v17
+description: "Android Support Leanback Preference v17"
 data:
 - file: preference-leanback-v17-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_preference_v14/cipd.yaml b/third_party/android_deps/libs/com_android_support_preference_v14/cipd.yaml
index a58e678..f7fe88a 100644
--- a/third_party/android_deps/libs/com_android_support_preference_v14/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_preference_v14/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_preference_v14
-description: Android Support Preference v14
+description: "Android Support Preference v14"
 data:
 - file: preference-v14-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_preference_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_preference_v7/cipd.yaml
index 263ae7f6..31912a9 100644
--- a/third_party/android_deps/libs/com_android_support_preference_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_preference_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_preference_v7
-description: Android Support Preference v7
+description: "Android Support Preference v7"
 data:
 - file: preference-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_recyclerview_v7/cipd.yaml b/third_party/android_deps/libs/com_android_support_recyclerview_v7/cipd.yaml
index d56caee..2c4afa1 100644
--- a/third_party/android_deps/libs/com_android_support_recyclerview_v7/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_recyclerview_v7/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_recyclerview_v7
-description: Android Support RecyclerView v7
+description: "Android Support RecyclerView v7"
 data:
 - file: recyclerview-v7-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml
index ccf0bf4d..bf084b4 100644
--- a/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_annotations
-description: Android Support Library Annotations
+description: "Android Support Library Annotations"
 data:
 - file: support-annotations-27.0.0.jar
diff --git a/third_party/android_deps/libs/com_android_support_support_compat/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_compat/cipd.yaml
index 59f6160..5dba900 100644
--- a/third_party/android_deps/libs/com_android_support_support_compat/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_compat/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_compat
-description: Android Support Library compat
+description: "Android Support Library compat"
 data:
 - file: support-compat-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_core_ui/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_core_ui/cipd.yaml
index f536650..0323d64 100644
--- a/third_party/android_deps/libs/com_android_support_support_core_ui/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_core_ui/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_core_ui
-description: Android Support Library core UI
+description: "Android Support Library core UI"
 data:
 - file: support-core-ui-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_core_utils/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_core_utils/cipd.yaml
index 70f0f1cd..8349b89 100644
--- a/third_party/android_deps/libs/com_android_support_support_core_utils/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_core_utils/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_core_utils
-description: Android Support Library core utils
+description: "Android Support Library core utils"
 data:
 - file: support-core-utils-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_fragment/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_fragment/cipd.yaml
index 1b682ea9..17d16d5 100644
--- a/third_party/android_deps/libs/com_android_support_support_fragment/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_fragment/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_fragment
-description: Android Support Library fragment
+description: "Android Support Library fragment"
 data:
 - file: support-fragment-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_media_compat/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_media_compat/cipd.yaml
index 30f4e342..00ded13 100644
--- a/third_party/android_deps/libs/com_android_support_support_media_compat/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_media_compat/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_media_compat
-description: Android Support Library media compat
+description: "Android Support Library media compat"
 data:
 - file: support-media-compat-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_v13/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_v13/cipd.yaml
index 18ab29f..a7e1c3f 100644
--- a/third_party/android_deps/libs/com_android_support_support_v13/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_v13/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_v13
-description: Android Support Library v13
+description: "Android Support Library v13"
 data:
 - file: support-v13-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_v4/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_v4/cipd.yaml
index e856a58ff..7e52146 100644
--- a/third_party/android_deps/libs/com_android_support_support_v4/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_v4/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_v4
-description: Android Support Library v4
+description: "Android Support Library v4"
 data:
 - file: support-v4-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_support_vector_drawable/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_vector_drawable/cipd.yaml
index 3a568ee..4a8f163 100644
--- a/third_party/android_deps/libs/com_android_support_support_vector_drawable/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_support_vector_drawable/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_support_vector_drawable
-description: Android Support VectorDrawable
+description: "Android Support VectorDrawable"
 data:
 - file: support-vector-drawable-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_android_support_transition/cipd.yaml b/third_party/android_deps/libs/com_android_support_transition/cipd.yaml
index 09fd0e8a..8e488481 100644
--- a/third_party/android_deps/libs/com_android_support_transition/cipd.yaml
+++ b/third_party/android_deps/libs/com_android_support_transition/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:27.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_android_support_transition
-description: Android Transition Support Library
+description: "Android Transition Support Library"
 data:
 - file: transition-27.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_auth/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_auth/cipd.yaml
index 76e505b2..07d9e69 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_auth/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_auth/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth
-description: play-services-auth
+description: "play-services-auth"
 data:
 - file: play-services-auth-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone/cipd.yaml
index 85141cc..9b72ac9 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone
-description: play-services-auth-api-phone
+description: "play-services-auth-api-phone"
 data:
 - file: play-services-auth-api-phone-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base/cipd.yaml
index daa8273e..c7f2c94 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base
-description: play-services-auth-base
+description: "play-services-auth-base"
 data:
 - file: play-services-auth-base-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_base/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_base/cipd.yaml
index 42d0ceb7..8f9540fa 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_base/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_base/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_base
-description: play-services-base
+description: "play-services-base"
 data:
 - file: play-services-base-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_basement/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_basement/cipd.yaml
index 643dd771..dc240a65 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_basement/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_basement/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_basement
-description: play-services-basement
+description: "play-services-basement"
 data:
 - file: play-services-basement-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml
index 6cfab4f..8e32d54 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:16.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cast
-description: play-services-cast
+description: "play-services-cast"
 data:
 - file: play-services-cast-16.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml
index d987898..f2e7d5e 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:16.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework
-description: play-services-cast-framework
+description: "play-services-cast-framework"
 data:
 - file: play-services-cast-framework-16.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml
index 8485d71..fa5c2f8e 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut
-description: play-services-clearcut
+description: "play-services-clearcut"
 data:
 - file: play-services-clearcut-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_fido/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_fido/cipd.yaml
index 9038051a..81dfde67 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_fido/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_fido/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_fido
-description: play-services-fido
+description: "play-services-fido"
 data:
 - file: play-services-fido-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml
index bdf568a..1d36647 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_flags
-description: play-services-flags
+description: "play-services-flags"
 data:
 - file: play-services-flags-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml
index 5421833..6cae4ef 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_gcm
-description: play-services-gcm
+description: "play-services-gcm"
 data:
 - file: play-services-gcm-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml
index 410ebd2..833cba36 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_iid
-description: play-services-iid
+description: "play-services-iid"
 data:
 - file: play-services-iid-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml
index f386443..9a0ef3d 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:16.0.0-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps
-description: play-services-instantapps
+description: "play-services-instantapps"
 data:
 - file: play-services-instantapps-16.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml
index 3517ff4..0d1b5e0 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_location
-description: play-services-location
+description: "play-services-location"
 data:
 - file: play-services-location-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml
index eb9ebf2..60d702d0 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype
-description: play-services-phenotype
+description: "play-services-phenotype"
 data:
 - file: play-services-phenotype-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport/cipd.yaml
index 0b42b376..13f7be0 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport
-description: play-services-places-placereport
+description: "play-services-places-placereport"
 data:
 - file: play-services-places-placereport-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml
index 96fc9b5..cff73b65 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_stats
-description: play-services-stats
+description: "play-services-stats"
 data:
 - file: play-services-stats-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_tasks/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_tasks/cipd.yaml
index 7bba4b8b..2e05fa8a 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_tasks/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_tasks/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_tasks
-description: play-services-tasks
+description: "play-services-tasks"
 data:
 - file: play-services-tasks-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml
index 88f715f..24aadbc 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_vision
-description: play-services-vision
+description: "play-services-vision"
 data:
 - file: play-services-vision-15.0.1.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml
index 2d7fbf87..51856b42 100644
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:15.0.1-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common
-description: play-services-vision-common
+description: "play-services-vision-common"
 data:
 - file: play-services-vision-common-15.0.1.aar
diff --git a/third_party/android_deps/Android_SDK_License-December_9_2016.txt b/third_party/android_deps/libs/com_google_android_play_core/LICENSE
similarity index 100%
copy from third_party/android_deps/Android_SDK_License-December_9_2016.txt
copy to third_party/android_deps/libs/com_google_android_play_core/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_play_core/README.chromium b/third_party/android_deps/libs/com_google_android_play_core/README.chromium
index db38ef1..1ff27de 100644
--- a/third_party/android_deps/libs/com_google_android_play_core/README.chromium
+++ b/third_party/android_deps/libs/com_google_android_play_core/README.chromium
@@ -1,9 +1,9 @@
-Name: Google Android Play Core
+Name: 
 Short Name: core
-URL: https://developer.android.com/guide/app-bundle/playcore
+URL: https://developers.google.com/android/guides/setup
 Version: 1.3.0
 License: Android Software Development Kit License
-License File: /third_party/android_deps/Android_SDK_License-December_9_2016.txt
+License File: LICENSE
 Security Critical: yes
 
 Description:
diff --git a/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml b/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml
index bea7177ac..2800ffe4 100644
--- a/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1.3.0-cr0
 package: chromium/third_party/android_deps/libs/com_google_android_play_core
-description: Google Android Play Core
+description: ""
 data:
 - file: core-1.3.0.aar
diff --git a/third_party/android_deps/libs/com_google_code_findbugs_jsr305/LICENSE b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/android_deps/libs/com_google_code_findbugs_jsr305/OWNERS b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_code_findbugs_jsr305/README.chromium b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/README.chromium
new file mode 100644
index 0000000..31c6d59d
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/README.chromium
@@ -0,0 +1,13 @@
+Name: FindBugs-jsr305
+Short Name: jsr305
+URL: http://findbugs.sourceforge.net/
+Version: 1.3.9
+License: Apache Version 2.0
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+JSR305 Annotations for Findbugs
+
+Local Modifications:
+No modifications.
diff --git a/third_party/android_deps/libs/com_google_code_findbugs_jsr305/cipd.yaml b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/cipd.yaml
new file mode 100644
index 0000000..c8bf5b5
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_code_findbugs_jsr305/cipd.yaml
@@ -0,0 +1,10 @@
+# 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.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd.yaml -tag version:1.3.9-cr0
+package: chromium/third_party/android_deps/libs/com_google_code_findbugs_jsr305
+description: "FindBugs-jsr305"
+data:
+- file: jsr305-1.3.9.jar
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger/OWNERS b/third_party/android_deps/libs/com_google_dagger_dagger/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_dagger_dagger/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger/cipd.yaml b/third_party/android_deps/libs/com_google_dagger_dagger/cipd.yaml
index 2aae831..55f9baa6 100644
--- a/third_party/android_deps/libs/com_google_dagger_dagger/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_dagger_dagger/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2.13-cr0
+# cipd create --pkg-def cipd.yaml -tag version:2.17-cr0
 package: chromium/third_party/android_deps/libs/com_google_dagger_dagger
-description: Dagger
+description: "Dagger"
 data:
 - file: dagger-2.17.jar
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_compiler/OWNERS b/third_party/android_deps/libs/com_google_dagger_dagger_compiler/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_compiler/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_compiler/cipd.yaml b/third_party/android_deps/libs/com_google_dagger_dagger_compiler/cipd.yaml
index 424ce95b..bb892ae 100644
--- a/third_party/android_deps/libs/com_google_dagger_dagger_compiler/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_compiler/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2.13-cr0
+# cipd create --pkg-def cipd.yaml -tag version:2.17-cr0
 package: chromium/third_party/android_deps/libs/com_google_dagger_dagger_compiler
-description: Dagger Compiler
+description: "Dagger Compiler"
 data:
 - file: dagger-compiler-2.17.jar
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_producers/OWNERS b/third_party/android_deps/libs/com_google_dagger_dagger_producers/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_producers/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_producers/cipd.yaml b/third_party/android_deps/libs/com_google_dagger_dagger_producers/cipd.yaml
index f839855..15b2d0e 100644
--- a/third_party/android_deps/libs/com_google_dagger_dagger_producers/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_producers/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2.13-cr0
+# cipd create --pkg-def cipd.yaml -tag version:2.17-cr0
 package: chromium/third_party/android_deps/libs/com_google_dagger_dagger_producers
-description: Dagger Producers
+description: "Dagger Producers"
 data:
 - file: dagger-producers-2.17.jar
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_spi/OWNERS b/third_party/android_deps/libs/com_google_dagger_dagger_spi/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_spi/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_spi/README.chromium b/third_party/android_deps/libs/com_google_dagger_dagger_spi/README.chromium
index a3776d9..4aaef27 100644
--- a/third_party/android_deps/libs/com_google_dagger_dagger_spi/README.chromium
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_spi/README.chromium
@@ -1,4 +1,4 @@
-Name: Dagger Spi
+Name: Dagger SPI
 Short Name: dagger-spi
 URL: https://github.com/google/dagger
 Version: 2.17
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger_spi/cipd.yaml b/third_party/android_deps/libs/com_google_dagger_dagger_spi/cipd.yaml
index 46c68ad..8ec7c8e9 100644
--- a/third_party/android_deps/libs/com_google_dagger_dagger_spi/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_dagger_dagger_spi/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2.13-cr0
+# cipd create --pkg-def cipd.yaml -tag version:2.17-cr0
 package: chromium/third_party/android_deps/libs/com_google_dagger_dagger_spi
-description: A fast dependency injector for Android and Java
+description: "Dagger SPI"
 data:
 - file: dagger-spi-2.17.jar
diff --git a/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/LICENSE b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/OWNERS b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/README.chromium b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/README.chromium
new file mode 100644
index 0000000..911ffc0
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/README.chromium
@@ -0,0 +1,13 @@
+Name: error-prone annotations
+Short Name: error_prone_annotations
+URL: 
+Version: 2.1.3
+License: Apache 2.0
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+
+
+Local Modifications:
+No modifications.
diff --git a/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/cipd.yaml b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/cipd.yaml
new file mode 100644
index 0000000..12ee717
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/cipd.yaml
@@ -0,0 +1,10 @@
+# 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.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd.yaml -tag version:2.1.3-cr0
+package: chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations
+description: "error-prone annotations"
+data:
+- file: error_prone_annotations-2.1.3.jar
diff --git a/third_party/android_deps/libs/com_google_errorprone_javac_shaded/LICENSE b/third_party/android_deps/libs/com_google_errorprone_javac_shaded/LICENSE
index c322c37..0f5e3d3 100644
--- a/third_party/android_deps/libs/com_google_errorprone_javac_shaded/LICENSE
+++ b/third_party/android_deps/libs/com_google_errorprone_javac_shaded/LICENSE
@@ -353,10 +353,8 @@
 </div><div id="sidebar"><div id="openjdk-sidebar-logo"><a href="/"><img alt="OpenJDK logo" src="../images/openjdk-small.png" /></a></div><div class="links"><div class="links"><a href="/workshop"><b>Workshop</b></a></div></div><div class="links"><div class="link"><a href="/faq/">OpenJDK FAQ</a></div><div class="link"><a href="/install/">Installing</a></div><div class="link"><a href="/contribute/">Contributing</a></div><div class="link"><a href="/sponsor/">Sponsoring</a></div><div class="link"><a href="/guide/">Developers' Guide</a></div></div><div class="links"><div class="links"><a href="http://mail.openjdk.java.net">Mailing lists</a></div><div class="link"><a href="/irc">IRC</a>
                       &#183; <a href="http://wiki.openjdk.java.net">Wiki</a></div></div><div class="links"><div class="links"><a href="/bylaws">Bylaws</a> &#183; <a href="/census">Census</a></div><div class="link"><a href="/legal/">Legal</a></div></div><div class="links"><div class="links"><a href="/jeps/0"><b>JEP Process</b></a></div></div><div class="links"><div class="link search"><form method="get" action="http://www.google.com/search"><input id="searchBox" style="color: gray" type="text" name="q" size="10" maxlength="255" value="search" /><input type="hidden" name="sitesearch" value="openjdk.java.net" /></form></div></div><div class="links"><div class="about">Source code</div><div class="link"><a href="http://hg.openjdk.java.net">Mercurial</a></div><div class="link">Bundles (<a href="http://download.java.net/openjdk/jdk6">6</a>)</div></div><div class="links"><div class="about">Groups</div><div class="link"><a href="/groups/">(overview)</a></div><div class="link"><a href="/groups/2d">2D Graphics</a></div><div class="link"><a href="/groups/adoption">Adoption</a></div><div class="link"><a href="/groups/awt">AWT</a></div><div class="link"><a href="/groups/build">Build</a></div><div class="link"><a href="/groups/csr">Compatibility &amp; Specification Review</a></div><div class="link"><a href="/groups/compiler">Compiler</a></div><div class="link"><a href="/groups/conformance">Conformance</a></div><div class="link"><a href="/groups/core-libs">Core Libraries</a></div><div class="link"><a href="/groups/gb">Governing Board</a></div><div class="link"><a href="/groups/hotspot">HotSpot</a></div><div class="link"><a href="/groups/i18n">Internationalization</a></div><div class="link"><a href="/groups/jmx">JMX</a></div><div class="link"><a href="/groups/members">Members</a></div><div class="link"><a href="/groups/net">Networking</a></div><div class="link"><a href="/groups/nb-projects">NetBeans Projects</a></div><div class="link"><a href="/groups/porters">Porters</a></div><div class="link"><a href="/groups/quality">Quality</a></div><div class="link"><a href="/groups/security">Security</a></div><div class="link"><a href="/groups/serviceability">Serviceability</a></div><div class="link"><a href="/groups/sound">Sound</a></div><div class="link"><a href="/groups/swing">Swing</a></div><div class="link"><a href="/groups/vulnerability">Vulnerability</a></div><div class="link"><a href="/groups/web">Web</a></div></div><div class="links"><div class="about">Projects</div><div class="link"><a href="/projects/">(overview)</a></div><div class="link"><a href="/projects/amber">Amber</a></div><div class="link"><a href="/projects/anno-pipeline">Annotations Pipeline 2.0</a></div><div class="link"><a href="/projects/audio-engine">Audio Engine</a></div><div class="link"><a href="/projects/build-infra">Build Infrastructure</a></div><div class="link"><a href="/projects/caciocavallo">Caciocavallo</a></div><div class="link"><a href="/projects/closures">Closures</a></div><div class="link"><a href="/projects/code-tools">Code Tools</a></div><div class="link"><a href="/projects/coin">Coin</a></div><div class="link"><a href="/projects/cvmi">Common VM Interface</a></div><div class="link"><a href="/projects/compiler-grammar">Compiler Grammar</a></div><div class="link"><a href="/projects/detroit">Detroit</a></div><div class="link"><a href="/projects/dio">Device I/O</a></div><div class="link"><a href="/projects/duke">Duke</a></div><div class="link"><a href="/projects/font-scaler">Font Scaler</a></div><div class="link"><a href="/projects/fbtoolkit">Framebuffer Toolkit</a></div><div class="link"><a href="/projects/graal">Graal</a></div><div class="link"><a href="/projects/graphics-rasterizer">Graphics Rasterizer</a></div><div class="link"><a href="/projects/harfbuzz">HarfBuzz Integration</a></div><div class="link"><a href="/projects/icedtea">IcedTea</a></div><div class="link"><a href="/projects/jdk6">JDK 6</a></div><div class="link"><a href="/projects/jdk7">JDK 7</a></div><div class="link"><a href="/projects/jdk7u">JDK 7 Updates</a></div><div class="link"><a href="/projects/jdk8">JDK 8</a></div><div class="link"><a href="/projects/jdk8u">JDK 8 Updates</a></div><div class="link"><a href="/projects/jdk9">JDK 9</a></div><div class="link"><a href="/projects/jdk">JDK</a>
       (<a href="/projects/jdk/10">10</a>,
-       <a href="/projects/jdk/11">11</a>)</div><div class="link"><a href="/projects/jdk-updates">JDK Updates</a></div><div class="link"><a href="/projects/javadoc-next">JavaDoc.Next</a></div><div class="link"><a href="/projects/jigsaw">Jigsaw</a></div><div class="link"><a href="/projects/kona">Kona</a></div><div class="link"><a href="/projects/kulla">Kulla</a></div><div class="link"><a href="/projects/lambda">Lambda</a></div><div class="link"><a href="/projects/locale-enhancement">Locale Enhancement</a></div><div class="link"><a href="/projects/loom">Loom</a></div><div class="link"><a href="/projects/jmm">Memory Model Update</a></div><div class="link"><a href="/projects/metropolis">Metropolis</a></div><div class="link"><a href="/projects/jmc">Mission Control</a></div><div class="link"><a href="/projects/mobile">Mobile</a></div><div class="link"><a href="/projects/modules">Modules</a></div><div class="link"><a href="/projects/mlvm">Multi-Language VM</a></div><div class="link"><a href="/projects/nashorn">Nashorn</a></div><div class="link"><a href="/projects/nio">New I/O</a></div><div class="link"><a href="/projects/openjfx">OpenJFX</a></div><div class="link"><a href="/projects/panama">Panama</a></div><div class="link"><a href="/projects/penrose">Penrose</a></div><div class="link"><a href="/projects/aarch32-port">Port: AArch32</a></div><div class="link"><a href="/projects/aarch64-port">Port: AArch64</a></div><div class="link"><a href="/projects/bsd-port">Port: BSD</a></div><div class="link"><a href="/projects/haiku-port">Port: Haiku</a></div><div class="link"><a href="/projects/macosx-port">Port: Mac OS X</a></div><div class="link"><a href="/projects/mips-port">Port: MIPS</a></div><div class="link"><a href="/projects/ppc-aix-port">Port: PowerPC/AIX</a></div><div class="link"><a href="/projects/s390x-port">Port: s390x</a></div><div class="link"><a href="/projects/portola">Portola</a></div><div class="link"><a href="/projects/sctp">SCTP</a></div><div class="link"><a href="/projects/shenandoah">Shenandoah</a></div><div class="link"><a href="/projects/sumatra">Sumatra</a></div><div class="link"><a href="/projects/threeten">ThreeTen</a></div><div class="link"><a href="/projects/tiered-attrib">Tiered Attribution</a></div><div class="link"><a href="/projects/type-annotations">Type Annotations</a></div><div class="link"><a href="/projects/xrender">XRender Pipeline</a></div><div class="link"><a href="/projects/valhalla">Valhalla</a></div><div class="link"><a href="/projects/verona">Verona</a></div><div class="link"><a href="/projects/visualvm">VisualVM</a></div><div class="link"><a href="/projects/zero">Zero</a></div><div class="link"><a href="/projects/zgc">ZGC</a></div></div><div class="links"><div class="about">Tools</div><div class="link"><a href="http://java.sun.com/javase/downloads/index.jsp">Java SE</a></div><div class="link"><a href="http://www.selenic.com/mercurial/">Mercurial</a></div><div class="link"><a href="http://netbeans.org">NetBeans</a></div><div class="link"><a href="/jtreg/index.html">jtreg harness</a></div></div><div class="links"><div class="about">Community</div><div class="link"><a href="http://planetjdk.org">Planet JDK blogs</a></div><div class="link"><a href="http://blogs.oracle.com/theaquarium">The Aquarium</a></div><div class="link"><a href="http://java.sun.com">java.sun.com</a></div><div class="link"><a href="http://jcp.org">Java Community Process</a></div></div><div class="links"><div class="about">Related</div><div class="link">JDK Snapshots (<a href="http://jdk.java.net/8/">8u</a>,
-       <a href="http://jdk.java.net/9/">9</a>,
-       <a href="http://jdk.java.net/10/">10</a>,
-       <a href="http://jdk.java.net/11/">11</a>) </div><div class="link"><a href="http://javaee.github.io/glassfish/">GlassFish</a></div></div><div class="buttons"><a href="http://oracle.com"><img alt="Oracle logo" src="../images/oracle.png" /></a></div></div><div id="footer">
+       <a href="/projects/jdk/11">11</a>,
+       <a href="/projects/jdk/12">12</a>)</div><div class="link"><a href="/projects/jdk-updates">JDK Updates</a></div><div class="link"><a href="/projects/javadoc-next">JavaDoc.Next</a></div><div class="link"><a href="/projects/jigsaw">Jigsaw</a></div><div class="link"><a href="/projects/kona">Kona</a></div><div class="link"><a href="/projects/kulla">Kulla</a></div><div class="link"><a href="/projects/lambda">Lambda</a></div><div class="link"><a href="/projects/locale-enhancement">Locale Enhancement</a></div><div class="link"><a href="/projects/loom">Loom</a></div><div class="link"><a href="/projects/jmm">Memory Model Update</a></div><div class="link"><a href="/projects/metropolis">Metropolis</a></div><div class="link"><a href="/projects/jmc">Mission Control</a></div><div class="link"><a href="/projects/mobile">Mobile</a></div><div class="link"><a href="/projects/modules">Modules</a></div><div class="link"><a href="/projects/mlvm">Multi-Language VM</a></div><div class="link"><a href="/projects/nashorn">Nashorn</a></div><div class="link"><a href="/projects/nio">New I/O</a></div><div class="link"><a href="/projects/openjfx">OpenJFX</a></div><div class="link"><a href="/projects/panama">Panama</a></div><div class="link"><a href="/projects/penrose">Penrose</a></div><div class="link"><a href="/projects/aarch32-port">Port: AArch32</a></div><div class="link"><a href="/projects/aarch64-port">Port: AArch64</a></div><div class="link"><a href="/projects/bsd-port">Port: BSD</a></div><div class="link"><a href="/projects/haiku-port">Port: Haiku</a></div><div class="link"><a href="/projects/macosx-port">Port: Mac OS X</a></div><div class="link"><a href="/projects/mips-port">Port: MIPS</a></div><div class="link"><a href="/projects/ppc-aix-port">Port: PowerPC/AIX</a></div><div class="link"><a href="/projects/s390x-port">Port: s390x</a></div><div class="link"><a href="/projects/portola">Portola</a></div><div class="link"><a href="/projects/sctp">SCTP</a></div><div class="link"><a href="/projects/shenandoah">Shenandoah</a></div><div class="link"><a href="/projects/sumatra">Sumatra</a></div><div class="link"><a href="/projects/threeten">ThreeTen</a></div><div class="link"><a href="/projects/tiered-attrib">Tiered Attribution</a></div><div class="link"><a href="/projects/type-annotations">Type Annotations</a></div><div class="link"><a href="/projects/xrender">XRender Pipeline</a></div><div class="link"><a href="/projects/valhalla">Valhalla</a></div><div class="link"><a href="/projects/verona">Verona</a></div><div class="link"><a href="/projects/visualvm">VisualVM</a></div><div class="link"><a href="/projects/zero">Zero</a></div><div class="link"><a href="/projects/zgc">ZGC</a></div></div><div class="links"><div class="about">Tools</div><div class="link"><a href="http://java.sun.com/javase/downloads/index.jsp">Java SE</a></div><div class="link"><a href="http://mercurial-scm.org/mercurial/">Mercurial</a></div><div class="link"><a href="/jtreg/index.html">jtreg harness</a></div></div><div class="links"><div class="about">Related</div><div class="link"><a href="http://planetjdk.org">Planet JDK</a></div><div class="link"><a href="http://java.sun.com">java.sun.com</a></div><div class="link"><a href="http://jcp.org">Java Community Process</a></div><div class="link"><a href="http://jdk.java.net">JDK GA/EA Builds</a></div></div><div class="buttons"><a href="http://oracle.com"><img alt="Oracle logo" src="../images/oracle.png" /></a></div></div><div id="footer">
 
         &#169; 2018 Oracle Corporation and/or its affiliates
         <br /><a href="/legal/tou/">Terms of Use</a>
diff --git a/third_party/android_deps/libs/com_google_errorprone_javac_shaded/OWNERS b/third_party/android_deps/libs/com_google_errorprone_javac_shaded/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_errorprone_javac_shaded/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_errorprone_javac_shaded/cipd.yaml b/third_party/android_deps/libs/com_google_errorprone_javac_shaded/cipd.yaml
index 3bb671405..520cf3f2 100644
--- a/third_party/android_deps/libs/com_google_errorprone_javac_shaded/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_errorprone_javac_shaded/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:9-dev-r4023-3-cr0
 package: chromium/third_party/android_deps/libs/com_google_errorprone_javac_shaded
-description: Error Prone shaded javac
+description: "Error Prone shaded javac"
 data:
 - file: javac-shaded-9-dev-r4023-3.jar
diff --git a/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/OWNERS b/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/README.chromium b/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/README.chromium
index e57749b..c6e3385 100644
--- a/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/README.chromium
+++ b/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/README.chromium
@@ -1,7 +1,7 @@
 Name: Google Java Format
 Short Name: google-java-format
 URL: https://github.com/google/google-java-format
-Version: 1.4
+Version: 1.5
 License: Apache 2.0
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/cipd.yaml b/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/cipd.yaml
index 78fba15..5b533c5 100644
--- a/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:1.4-cr0
+# cipd create --pkg-def cipd.yaml -tag version:1.5-cr0
 package: chromium/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format
-description: Google Java Format
+description: "Google Java Format"
 data:
 - file: google-java-format-1.5.jar
diff --git a/third_party/android_deps/libs/com_google_guava_guava/OWNERS b/third_party/android_deps/libs/com_google_guava_guava/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_guava_guava/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_guava_guava/README.chromium b/third_party/android_deps/libs/com_google_guava_guava/README.chromium
index 679b657..735052e 100644
--- a/third_party/android_deps/libs/com_google_guava_guava/README.chromium
+++ b/third_party/android_deps/libs/com_google_guava_guava/README.chromium
@@ -1,13 +1,13 @@
 Name: Guava: Google Core Libraries for Java
 Short Name: guava
 URL: https://github.com/google/guava
-Version: 25.0
+Version: 25.0-jre
 License: Apache 2.0
 License File: NOT_SHIPPED
 Security Critical: no
 
 Description:
-Guava is a suite of core and expanded libraries that include utility classes, google's collections, io classes, and much much more. Guava has only one code dependency - javax.annotation, per the JSR-305 spec.
+Guava is a suite of core and expanded libraries that include utility classes, google's collections, io classes, and much much more.
 
 Local Modifications:
 No modifications.
diff --git a/third_party/android_deps/libs/com_google_guava_guava/cipd.yaml b/third_party/android_deps/libs/com_google_guava_guava/cipd.yaml
index d486e1dc..deccb9d 100644
--- a/third_party/android_deps/libs/com_google_guava_guava/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_guava_guava/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:21.0-cr0
+# cipd create --pkg-def cipd.yaml -tag version:25.0-jre-cr0
 package: chromium/third_party/android_deps/libs/com_google_guava_guava
-description: Guava, Google Core Libraries for Java
+description: "Guava: Google Core Libraries for Java"
 data:
-- file: guava-25.0.jar
+- file: guava-25.0-jre.jar
diff --git a/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/LICENSE b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/OWNERS b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/README.chromium b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/README.chromium
new file mode 100644
index 0000000..426fc24
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/README.chromium
@@ -0,0 +1,13 @@
+Name: J2ObjC Annotations
+Short Name: j2objc-annotations
+URL: https://github.com/google/j2objc/
+Version: 1.1
+License: Apache Version 2.0
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+A set of annotations that provide additional information to the J2ObjC translator to modify the result of translation.
+
+Local Modifications:
+No modifications.
diff --git a/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/cipd.yaml b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/cipd.yaml
new file mode 100644
index 0000000..fea1c80
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/cipd.yaml
@@ -0,0 +1,10 @@
+# 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.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd.yaml -tag version:1.1-cr0
+package: chromium/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations
+description: "J2ObjC Annotations"
+data:
+- file: j2objc-annotations-1.1.jar
diff --git a/third_party/android_deps/libs/com_squareup_javapoet/OWNERS b/third_party/android_deps/libs/com_squareup_javapoet/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_squareup_javapoet/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml b/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml
index aae1d38..7249fde8 100644
--- a/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml
+++ b/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:1.8.0-cr0
+# cipd create --pkg-def cipd.yaml -tag version:1.11.0-cr0
 package: chromium/third_party/android_deps/libs/com_squareup_javapoet
-description: JavaPoet
+description: "JavaPoet"
 data:
 - file: javapoet-1.11.0.jar
diff --git a/third_party/android_deps/libs/javax_annotation_jsr250_api/OWNERS b/third_party/android_deps/libs/javax_annotation_jsr250_api/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/javax_annotation_jsr250_api/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/javax_annotation_jsr250_api/cipd.yaml b/third_party/android_deps/libs/javax_annotation_jsr250_api/cipd.yaml
index 2fc6ac6b..d01fd79 100644
--- a/third_party/android_deps/libs/javax_annotation_jsr250_api/cipd.yaml
+++ b/third_party/android_deps/libs/javax_annotation_jsr250_api/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1.0-cr0
 package: chromium/third_party/android_deps/libs/javax_annotation_jsr250_api
-description: JSR-250 Common Annotations for the JavaTM Platform
+description: "JSR-250 Common Annotations for the JavaTM Platform"
 data:
 - file: jsr250-api-1.0.jar
diff --git a/third_party/android_deps/libs/javax_inject_javax_inject/OWNERS b/third_party/android_deps/libs/javax_inject_javax_inject/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/javax_inject_javax_inject/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/javax_inject_javax_inject/cipd.yaml b/third_party/android_deps/libs/javax_inject_javax_inject/cipd.yaml
index 8b0b186..c25927a 100644
--- a/third_party/android_deps/libs/javax_inject_javax_inject/cipd.yaml
+++ b/third_party/android_deps/libs/javax_inject_javax_inject/cipd.yaml
@@ -5,6 +5,6 @@
 # To create CIPD package run the following command.
 # cipd create --pkg-def cipd.yaml -tag version:1-cr0
 package: chromium/third_party/android_deps/libs/javax_inject_javax_inject
-description: javax.inject
+description: "javax.inject"
 data:
 - file: javax.inject-1.jar
diff --git a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/LICENSE b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/LICENSE
new file mode 100644
index 0000000..40cdc59
--- /dev/null
+++ b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/LICENSE
@@ -0,0 +1,409 @@
+Most of the Checker Framework is licensed under the GNU General Public
+License, version 2 (GPL2), with the classpath exception.  The text of this
+license appears below.  This is the same license used for OpenJDK.
+
+A few parts of the Checker Framework have more permissive licenses.
+
+ * The annotations are licensed under the MIT License.  (The text of this
+   license appears below.)  More specifically, all the parts of the Checker
+   Framework that you might want to include with your own program use the
+   MIT License.  This is the checker-qual.jar file and all the files that
+   appear in it:  every file in a qual/ directory, plus utility files such
+   as NullnessUtil.java, RegexUtil.java, SignednessUtil.java, etc.
+   In addition, the cleanroom implementations of third-party annotations,
+   which the Checker Framework recognizes as aliases for its own
+   annotations, are licensed under the MIT License.
+
+Some external libraries that are included with the Checker Framework have
+different licenses.
+
+ * javaparser is dual licensed under the LGPL or the Apache license -- you
+   may use it under whichever one you want.  (The javaparser source code
+   contains a file with the text of the GPL, but it is not clear why, since
+   javaparser does not use the GPL.)  See file stubparser/LICENSE
+   and the source code of all its files.
+
+ * JUnit is licensed under the Common Public License v1.0 (see
+   http://www.junit.org/license), with parts (Hamcrest) licensed under the
+   BSD License (see http://hamcrest.org/JavaHamcrest/).
+
+ * Libraries in plume-lib (https://github.com/plume-lib/) are licensed
+   under the MIT License.
+
+The Checker Framework includes annotations for the JDK in directory
+checker/jdk/, and for some other libraries.  Each annotated library uses
+the same license as the unannotated version of the library.
+
+===========================================================================
+
+The GNU General Public License (GPL)
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share
+and change it.  By contrast, the GNU General Public License is intended to
+guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.  This General Public License applies to
+most of the Free Software Foundation's software and to any other program whose
+authors commit to using it.  (Some other Free Software Foundation software is
+covered by the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.  Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this service if you wish),
+that you receive source code or can get it if you want it, that you can change
+the software or use pieces of it in new free programs; and that you know you
+can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny
+you these rights or to ask you to surrender the rights.  These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have.  You must
+make sure that they, too, receive or can get the source code.  And you must
+show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software.  If the
+software is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original, so that any problems introduced
+by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.  We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent must be licensed for
+everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms of
+this General Public License.  The "Program", below, refers to any such program
+or work, and a "work based on the Program" means either the Program or any
+derivative work under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with modifications and/or
+translated into another language.  (Hereinafter, translation is included
+without limitation in the term "modification".) Each licensee is addressed as
+"you".
+
+Activities other than copying, distribution and modification are not covered by
+this License; they are outside its scope.  The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made by
+running the Program).  Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as
+you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may
+at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus
+forming a work based on the Program, and copy and distribute such modifications
+or work under the terms of Section 1 above, provided that you also meet all of
+these conditions:
+
+    a) You must cause the modified files to carry prominent notices stating
+    that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in whole or
+    in part contains or is derived from the Program or any part thereof, to be
+    licensed as a whole at no charge to all third parties under the terms of
+    this License.
+
+    c) If the modified program normally reads commands interactively when run,
+    you must cause it, when started running for such interactive use in the
+    most ordinary way, to print or display an announcement including an
+    appropriate copyright notice and a notice that there is no warranty (or
+    else, saying that you provide a warranty) and that users may redistribute
+    the program under these conditions, and telling the user how to view a copy
+    of this License.  (Exception: if the Program itself is interactive but does
+    not normally print such an announcement, your work based on the Program is
+    not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If identifiable
+sections of that work are not derived from the Program, and can be reasonably
+considered independent and separate works in themselves, then this License, and
+its terms, do not apply to those sections when you distribute them as separate
+works.  But when you distribute the same sections as part of a whole which is a
+work based on the Program, the distribution of the whole must be on the terms
+of this License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on the Program with the
+Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1 and
+2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable source
+    code, which must be distributed under the terms of Sections 1 and 2 above
+    on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three years, to
+    give any third party, for a charge no more than your cost of physically
+    performing source distribution, a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of Sections 1
+    and 2 above on a medium customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer to
+    distribute corresponding source code.  (This alternative is allowed only
+    for noncommercial distribution and only if you received the program in
+    object code or executable form with such an offer, in accord with
+    Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it.  For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and installation
+of the executable.  However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the source
+code from the same place counts as distribution of the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License.  Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate
+your rights under this License.  However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the Program
+or its derivative works.  These actions are prohibited by law if you do not
+accept this License.  Therefore, by modifying or distributing the Program (or
+any work based on the Program), you indicate your acceptance of this License to
+do so, and all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program),
+the recipient automatically receives a license from the original licensor to
+copy, distribute or modify the Program subject to these terms and conditions.
+You may not impose any further restrictions on the recipients' exercise of the
+rights granted herein.  You are not responsible for enforcing compliance by
+third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License.  If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices.  Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded.  In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the
+General Public License from time to time.  Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems
+or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software Foundation.
+If the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission.  For software which is copyrighted by the Free Software Foundation,
+write to the Free Software Foundation; we sometimes make exceptions for this.
+Our decision will be guided by the two goals of preserving the free status of
+all derivatives of our free software and of promoting the sharing and reuse of
+software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
+ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
+PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
+OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program.  It is safest to attach
+them to the start of each source file to most effectively convey the exclusion
+of warranty; and each file should have at least the "copyright" line and a
+pointer to where the full notice is found.
+
+    One line to give the program's name and a brief idea of what it does.
+
+    Copyright (C) <year> <name of author>
+
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the Free
+    Software Foundation; either version 2 of the License, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+    more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc., 59
+    Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it
+starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
+    with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free
+    software, and you are welcome to redistribute it under certain conditions;
+    type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may be
+called something other than 'show w' and 'show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.  Here
+is a sample; alter the names:
+
+    Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+    'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+    signature of Ty Coon, 1 April 1989
+
+    Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General Public
+License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL
+
+Certain source files distributed by Oracle America and/or its affiliates are
+subject to the following clarification and special exception to the GPL, but
+only where Oracle has expressly included in the particular source file's header
+the words "Oracle designates this particular file as subject to the "Classpath"
+exception as provided by Oracle in the LICENSE file that accompanied this code."
+
+    Linking this library statically or dynamically with other modules is making
+    a combined work based on this library.  Thus, the terms and conditions of
+    the GNU General Public License cover the whole combination.
+
+    As a special exception, the copyright holders of this library give you
+    permission to link this library with independent modules to produce an
+    executable, regardless of the license terms of these independent modules,
+    and to copy and distribute the resulting executable under terms of your
+    choice, provided that you also meet, for each linked independent module,
+    the terms and conditions of the license of that module.  An independent
+    module is a module which is not derived from or based on this library.  If
+    you modify this library, you may extend this exception to your version of
+    the library, but you are not obligated to do so.  If you do not wish to do
+    so, delete this exception statement from your version.
+
+===========================================================================
+
+MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+===========================================================================
diff --git a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/OWNERS b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/README.chromium b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/README.chromium
new file mode 100644
index 0000000..07680fa8
--- /dev/null
+++ b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/README.chromium
@@ -0,0 +1,13 @@
+Name: Checker Qual
+Short Name: checker-compat-qual
+URL: https://checkerframework.org
+Version: 2.3.0
+License: GPL v2 with the classpath exception
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+Checker Qual is the set of annotations (qualifiers) and supporting classes used by the Checker Framework to type check Java source code. Please see artifact: org.checkerframework:checker
+
+Local Modifications:
+No modifications.
diff --git a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml
new file mode 100644
index 0000000..42d1521
--- /dev/null
+++ b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml
@@ -0,0 +1,10 @@
+# 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.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd.yaml -tag version:2.3.0-cr0
+package: chromium/third_party/android_deps/libs/org_checkerframework_checker_compat_qual
+description: "Checker Qual"
+data:
+- file: checker-compat-qual-2.3.0.jar
diff --git a/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/LICENSE b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/LICENSE
new file mode 100644
index 0000000..370fb55
--- /dev/null
+++ b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2009 codehaus.org.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/OWNERS b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/README.chromium b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/README.chromium
new file mode 100644
index 0000000..63ff8e3
--- /dev/null
+++ b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/README.chromium
@@ -0,0 +1,13 @@
+Name: Animal Sniffer Annotations
+Short Name: animal-sniffer-annotations
+URL: http://www.mojohaus.org/animal-sniffer/animal-sniffer-annotations/
+Version: 1.14
+License: MIT
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+
+
+Local Modifications:
+No modifications.
diff --git a/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/cipd.yaml b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/cipd.yaml
new file mode 100644
index 0000000..7d7cf97
--- /dev/null
+++ b/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/cipd.yaml
@@ -0,0 +1,10 @@
+# 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.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd.yaml -tag version:1.14-cr0
+package: chromium/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations
+description: "Animal Sniffer Annotations"
+data:
+- file: animal-sniffer-annotations-1.14.jar
diff --git a/third_party/android_deps/Android_SDK_License-December_9_2016.txt b/third_party/android_deps/licenses/Android_SDK_License-December_9_2016.txt
similarity index 100%
rename from third_party/android_deps/Android_SDK_License-December_9_2016.txt
rename to third_party/android_deps/licenses/Android_SDK_License-December_9_2016.txt
diff --git a/third_party/android_deps/licenses/Codehaus_License-2009.txt b/third_party/android_deps/licenses/Codehaus_License-2009.txt
new file mode 100644
index 0000000..370fb55
--- /dev/null
+++ b/third_party/android_deps/licenses/Codehaus_License-2009.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2009 codehaus.org.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn
index 5f62cbb..84a770b 100644
--- a/third_party/blink/common/BUILD.gn
+++ b/third_party/blink/common/BUILD.gn
@@ -85,6 +85,11 @@
 
     deps += [ "//third_party/icu" ]
   }
+
+  if (is_win) {
+    sources += [ "dwrite_rasterizer_support/dwrite_rasterizer_support.cc" ]
+    deps += [ "//ui/gfx/" ]
+  }
 }
 
 test("blink_common_unittests") {
diff --git a/third_party/blink/common/DEPS b/third_party/blink/common/DEPS
index ddc8edb..1063c9cc 100644
--- a/third_party/blink/common/DEPS
+++ b/third_party/blink/common/DEPS
@@ -19,6 +19,7 @@
     "+third_party/blink/public/mojom",
     "+third_party/icu/source/common/unicode/unistr.h",
     "+ui/gfx/geometry",
+    "+ui/gfx/win/direct_write.h",
     "+url",
 ]
 specific_include_rules = {
diff --git a/third_party/blink/common/dwrite_rasterizer_support/dwrite_rasterizer_support.cc b/third_party/blink/common/dwrite_rasterizer_support/dwrite_rasterizer_support.cc
new file mode 100644
index 0000000..efe971fa
--- /dev/null
+++ b/third_party/blink/common/dwrite_rasterizer_support/dwrite_rasterizer_support.cc
@@ -0,0 +1,30 @@
+// 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/public/common/dwrite_rasterizer_support/dwrite_rasterizer_support.h"
+#include "base/logging.h"
+#include "base/win/windows_version.h"
+#include "ui/gfx/win/direct_write.h"
+
+#include <dwrite.h>
+#include <dwrite_2.h>
+#include <wrl.h>
+
+namespace blink {
+
+bool DWriteRasterizerSupport::IsDWriteFactory2Available() {
+  Microsoft::WRL::ComPtr<IDWriteFactory> factory;
+  gfx::win::CreateDWriteFactory(&factory);
+  Microsoft::WRL::ComPtr<IDWriteFactory2> factory2;
+  factory.As<IDWriteFactory2>(&factory2);
+  if (!factory2.Get()) {
+    // If we were unable to get a IDWriteFactory2, check that we are actually on
+    // a Windows version where we allow it. Windows 8.1 and up should have the
+    // IDWritefactory2 available.
+    CHECK_LT(base::win::GetVersion(), base::win::VERSION_WIN8_1);
+  }
+  return factory2.Get();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/common/feature_policy/feature_policy.cc b/third_party/blink/common/feature_policy/feature_policy.cc
index c7a74fd..9bfb1e3 100644
--- a/third_party/blink/common/feature_policy/feature_policy.cc
+++ b/third_party/blink/common/feature_policy/feature_policy.cc
@@ -263,6 +263,8 @@
                             FeaturePolicy::FeatureDefault::EnableForSelf},
                            {mojom::FeaturePolicyFeature::kImageCompression,
                             FeaturePolicy::FeatureDefault::EnableForAll},
+                           {mojom::FeaturePolicyFeature::kLazyLoad,
+                            FeaturePolicy::FeatureDefault::EnableForAll},
                            {mojom::FeaturePolicyFeature::kLegacyImageFormats,
                             FeaturePolicy::FeatureDefault::EnableForAll},
                            {mojom::FeaturePolicyFeature::kMagnetometer,
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 708efae..2947da2f 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -103,6 +103,10 @@
     ]
     deps += [ ":font_unique_name_table_proto" ]
   }
+
+  if (is_win) {
+    sources += [ "dwrite_rasterizer_support/dwrite_rasterizer_support.h" ]
+  }
 }
 
 if (is_android) {
diff --git a/third_party/blink/public/common/dwrite_rasterizer_support/dwrite_rasterizer_support.h b/third_party/blink/public/common/dwrite_rasterizer_support/dwrite_rasterizer_support.h
new file mode 100644
index 0000000..c71262b
--- /dev/null
+++ b/third_party/blink/public/common/dwrite_rasterizer_support/dwrite_rasterizer_support.h
@@ -0,0 +1,19 @@
+// 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_DWRITE_RASTERIZER_SUPPORT_DWRITE_RASTERIZER_SUPPORT_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_DWRITE_RASTERIZER_SUPPORT_DWRITE_RASTERIZER_SUPPORT_H_
+
+#include "third_party/blink/common/common_export.h"
+
+namespace blink {
+
+class BLINK_COMMON_EXPORT DWriteRasterizerSupport {
+ public:
+  static bool IsDWriteFactory2Available();
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_DWRITE_RASTERIZER_SUPPORT_DWRITE_RASTERIZER_SUPPORT_H_
diff --git a/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py b/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py
new file mode 100644
index 0000000..3991ea3
--- /dev/null
+++ b/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py
@@ -0,0 +1,53 @@
+# 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.
+
+"""Blink feature-policy presubmit script.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into gcl.
+"""
+
+def _RunUmaHistogramChecks(input_api, output_api):  # pylint: disable=C0103
+    import sys
+
+    original_sys_path = sys.path
+    try:
+        sys.path = sys.path + [input_api.os_path.join(
+            input_api.PresubmitLocalPath(), '..', '..', '..', '..', '..',
+            'tools', 'metrics', 'histograms')]
+        import update_histogram_enum
+    finally:
+        sys.path = original_sys_path
+
+    source_path = ''
+    for f in input_api.AffectedFiles():
+        if f.LocalPath().endswith('feature_policy.mojom'):
+            source_path = f.LocalPath()
+            break
+    else:
+        return []
+
+    start_marker = '^enum FeaturePolicyFeature {'
+    end_marker = '^};'
+    presubmit_error = update_histogram_enum.CheckPresubmitErrors(
+        histogram_enum_name='FeaturePolicyFeature',
+        update_script_name='update_feature_policy_enum.py',
+        source_enum_path=source_path,
+        start_marker=start_marker,
+        end_marker=end_marker,
+        strip_k_prefix=True)
+    if presubmit_error:
+        return [output_api.PresubmitPromptWarning(presubmit_error,
+                                                  items=[source_path])]
+    return []
+
+def CheckChangeOnUpload(input_api, output_api):  # pylint: disable=C0103
+    results = []
+    results.extend(_RunUmaHistogramChecks(input_api, output_api))
+    return results
+
+def CheckChangeOnCommit(input_api, output_api):  # pylint: disable=C0103
+    results = []
+    results.extend(_RunUmaHistogramChecks(input_api, output_api))
+    return results
diff --git a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
index c58c2f5..96d2e2ad4 100644
--- a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
+++ b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
@@ -96,6 +96,8 @@
   // which interfere with document's input stream (document.write(),
   // document.close(), etc.).
   kDocumentWrite = 28,
+  // Used to enforce lazyloading for a frame and any nested <iframe> or image.
+  kLazyLoad = 29,
 
   // Don't change assigned numbers of any item, and don't reuse removed slots.
   // Also, run update_feature_policy_enum.py in
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom b/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom
index d4c110e1..6278dde 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom
@@ -11,17 +11,6 @@
 
 const int64 kInvalidServiceWorkerRegistrationId = -1;
 
-// Represents ScriptType enum for ServiceWorkerRegistrationOptions:
-// https://w3c.github.io/ServiceWorker/#dom-registrationoptions-type
-// https://html.spec.whatwg.org/multipage/workers.html#workertype
-// TODO(asamidoi, nhiroki): Move this enum to blink/public/mojom/script or
-// somewhere else, and replace the duplicate enum in
-// third_party/blink/renderer/core/script/script.h.
-enum ScriptType {
-  kClassic,
-  kModule,
-};
-
 // Represents ServiceWorkerUpdateViaCache enum for ServiceWorkerRegistrationOptions:
 // https://w3c.github.io/ServiceWorker/#enumdef-serviceworkerupdateviacache
 enum ServiceWorkerUpdateViaCache {
@@ -40,7 +29,6 @@
 // https://w3c.github.io/ServiceWorker/#dictdef-registrationoptions
 struct ServiceWorkerRegistrationOptions {
   url.mojom.Url scope;
-  ScriptType type = kClassic;
   ServiceWorkerUpdateViaCache update_via_cache = kImports;
 };
 
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h
index 3543a156..9f565f6 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h
@@ -108,7 +108,6 @@
   virtual void RegisterServiceWorker(
       const WebURL& pattern,
       const WebURL& script_url,
-      blink::mojom::ScriptType script_type,
       blink::mojom::ServiceWorkerUpdateViaCache update_via_cache,
       std::unique_ptr<WebServiceWorkerRegistrationCallbacks>) {}
   // For ServiceWorkerContainer#getRegistration(). Requests the embedder to
diff --git a/third_party/blink/public/web/DEPS b/third_party/blink/public/web/DEPS
index 368f8834..9a8eaa7 100644
--- a/third_party/blink/public/web/DEPS
+++ b/third_party/blink/public/web/DEPS
@@ -16,6 +16,7 @@
     "+services/ws/public/mojom/ime/ime.mojom-shared.h",
     "+third_party/blink/public/platform",
     "+third_party/blink/public/web",
+    "+ui/accessibility/ax_enums.mojom-shared.h",
 
     # Allowed only inside INSIDE_BLINK
     "+third_party/blink/renderer/core",
diff --git a/third_party/blink/public/web/web_ax_enums.h b/third_party/blink/public/web/web_ax_enums.h
index 18f89b2..218a3a20 100644
--- a/third_party/blink/public/web/web_ax_enums.h
+++ b/third_party/blink/public/web/web_ax_enums.h
@@ -33,43 +33,6 @@
 
 namespace blink {
 
-// Accessibility events sent from Blink to the embedder.
-// These values must match blink::AXObjectCache::AXNotification values.
-// Enforced in AssertMatchingEnums.cpp.
-enum WebAXEvent {
-  kWebAXEventActiveDescendantChanged,
-  kWebAXEventAriaAttributeChanged,
-  kWebAXEventAutocorrectionOccured,
-  kWebAXEventBlur,
-  kWebAXEventCheckedStateChanged,
-  kWebAXEventChildrenChanged,
-  kWebAXEventClicked,
-  kWebAXEventDocumentSelectionChanged,
-  kWebAXEventDocumentTitleChanged,
-  kWebAXEventExpandedChanged,
-  kWebAXEventFocus,
-  kWebAXEventHide,
-  kWebAXEventHover,
-  kWebAXEventInvalidStatusChanged,
-  kWebAXEventLayoutComplete,
-  kWebAXEventLiveRegionChanged,
-  kWebAXEventLoadComplete,
-  kWebAXEventLocationChanged,
-  kWebAXEventMenuListItemSelected,
-  kWebAXEventMenuListItemUnselected,
-  kWebAXEventMenuListValueChanged,
-  kWebAXEventRowCollapsed,
-  kWebAXEventRowCountChanged,
-  kWebAXEventRowExpanded,
-  kWebAXEventScrollPositionChanged,
-  kWebAXEventScrolledToAnchor,
-  kWebAXEventSelectedChildrenChanged,
-  kWebAXEventSelectedTextChanged,
-  kWebAXEventShow,
-  kWebAXEventTextChanged,
-  kWebAXEventValueChanged
-};
-
 // Accessibility roles.
 // These values must match blink::AccessibilityRole values.
 // Enforced in AssertMatchingEnums.cpp.
diff --git a/third_party/blink/public/web/web_embedded_worker_start_data.h b/third_party/blink/public/web/web_embedded_worker_start_data.h
index 68ac0b7..cb76e04 100644
--- a/third_party/blink/public/web/web_embedded_worker_start_data.h
+++ b/third_party/blink/public/web/web_embedded_worker_start_data.h
@@ -34,7 +34,6 @@
 #include "base/unguessable_token.h"
 #include "third_party/blink/public/common/privacy_preferences.h"
 #include "third_party/blink/public/mojom/net/ip_address_space.mojom-shared.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom-shared.h"
 #include "third_party/blink/public/platform/web_content_security_policy.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
@@ -51,7 +50,6 @@
 
   WebURL script_url;
   WebString user_agent;
-  mojom::ScriptType script_type;
   PauseAfterDownloadMode pause_after_download_mode;
   // Whether to pause the initialization and wait for debugger to attach
   // before proceeding. This technique allows debugging worker startup.
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index ce42ab89..e1a04063 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -74,6 +74,7 @@
 #include "third_party/blink/public/web/web_navigation_type.h"
 #include "third_party/blink/public/web/web_text_direction.h"
 #include "third_party/blink/public/web/web_triggering_event_info.h"
+#include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "v8/include/v8.h"
 
 namespace service_manager {
@@ -733,7 +734,7 @@
   // Accessibility -------------------------------------------------------
 
   // Notifies embedder about an accessibility event.
-  virtual void PostAccessibilityEvent(const WebAXObject&, WebAXEvent) {}
+  virtual void PostAccessibilityEvent(const WebAXObject&, ax::mojom::Event) {}
 
   // Provides accessibility information about a find in page result.
   virtual void HandleAccessibilityFindInPageResult(int identifier,
diff --git a/third_party/blink/public/web/web_remote_frame.h b/third_party/blink/public/web/web_remote_frame.h
index 6f6fd06..2addfb254 100644
--- a/third_party/blink/public/web/web_remote_frame.h
+++ b/third_party/blink/public/web/web_remote_frame.h
@@ -138,6 +138,8 @@
 
   virtual WebRect GetCompositingRect() = 0;
 
+  virtual bool OOPIFHasPointerEventsNone() const = 0;
+
  protected:
   explicit WebRemoteFrame(WebTreeScopeType scope) : WebFrame(scope) {}
 
diff --git a/third_party/blink/public/web/web_remote_frame_client.h b/third_party/blink/public/web/web_remote_frame_client.h
index de85c47..d57c8e7 100644
--- a/third_party/blink/public/web/web_remote_frame_client.h
+++ b/third_party/blink/public/web/web_remote_frame_client.h
@@ -56,6 +56,9 @@
   // Set inherited effective touch action on the remote frame.
   virtual void SetInheritedEffectiveTouchAction(blink::WebTouchAction) {}
 
+  // Update pointer-events property on the remote frame.
+  virtual void PointerEventsChanged() {}
+
   // Toggles render throttling for the remote frame.
   virtual void UpdateRenderThrottlingStatus(bool is_throttled,
                                             bool subtree_throttled) {}
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
index 400d33e..c49a07c 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
 #include "third_party/blink/renderer/core/script/classic_pending_script.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
@@ -398,11 +399,6 @@
       return;
     }
 
-    if (!script_state_->ContextIsValid()) {
-      SuppressStreaming(kContextNotValid);
-      return;
-    }
-
     DCHECK(!stream_);
     DCHECK(!source_);
     stream_ = new SourceStream;
@@ -410,11 +406,11 @@
     source_ = std::make_unique<v8::ScriptCompiler::StreamedSource>(stream_,
                                                                    encoding_);
 
-    ScriptState::Scope scope(script_state_);
     std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask>
         script_streaming_task(
             base::WrapUnique(v8::ScriptCompiler::StartStreamingScript(
-                script_state_->GetIsolate(), source_.get(), compile_options_)));
+                V8PerIsolateData::MainThreadIsolate(), source_.get(),
+                compile_options_)));
     if (!script_streaming_task) {
       // V8 cannot stream the script.
       SuppressStreaming(kV8CannotStream);
@@ -476,11 +472,10 @@
     // existing task as no longer MayBlock.
     if (RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled() &&
         !blocking_task_started_or_cancelled_.test_and_set()) {
-      ScriptState::Scope scope(script_state_);
       std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask>
           script_streaming_task(
               base::WrapUnique(v8::ScriptCompiler::StartStreamingScript(
-                  script_state_->GetIsolate(), source_.get(),
+                  V8PerIsolateData::MainThreadIsolate(), source_.get(),
                   compile_options_)));
 
       // The task creation shouldn't fail, since it didn't fail before during
@@ -500,7 +495,6 @@
 
 ScriptStreamer::ScriptStreamer(
     ClassicPendingScript* script,
-    ScriptState* script_state,
     v8::ScriptCompiler::CompileOptions compile_options,
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner)
     : pending_script_(script),
@@ -512,7 +506,6 @@
       streaming_suppressed_(false),
       suppressed_reason_(kInvalid),
       compile_options_(compile_options),
-      script_state_(script_state),
       script_url_string_(script->GetResource()->Url().Copy().GetString()),
       script_resource_identifier_(script->GetResource()->Identifier()),
       // Unfortunately there's no dummy encoding value in the enum; let's use
@@ -524,7 +517,6 @@
 
 void ScriptStreamer::Trace(blink::Visitor* visitor) {
   visitor->Trace(pending_script_);
-  visitor->Trace(script_state_);
 }
 
 void ScriptStreamer::StreamingComplete() {
@@ -562,12 +554,9 @@
 
 void ScriptStreamer::StartStreaming(
     ClassicPendingScript* script,
-    Settings* settings,
-    ScriptState* script_state,
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
     NotStreamingReason* not_streaming_reason) {
   DCHECK(IsMainThread());
-  DCHECK(script_state->ContextIsValid());
   *not_streaming_reason = kInvalid;
   ScriptResource* resource = ToScriptResource(script->GetResource());
   if (!resource->Url().ProtocolIsInHTTPFamily()) {
@@ -592,9 +581,9 @@
   // to arrive: the Content-Length HTTP header is not sent for chunked
   // downloads.
 
-  ScriptStreamer* streamer = new ScriptStreamer(
-      script, script_state, v8::ScriptCompiler::kNoCompileOptions,
-      std::move(loading_task_runner));
+  ScriptStreamer* streamer =
+      new ScriptStreamer(script, v8::ScriptCompiler::kNoCompileOptions,
+                         std::move(loading_task_runner));
 
   // If this script was ready when streaming began, no callbacks will be
   // received to populate the data for the ScriptStreamer, so send them now.
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.h b/third_party/blink/renderer/bindings/core/v8/script_streamer.h
index 578fb0b4..149c03e 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.h
@@ -19,8 +19,6 @@
 
 class ClassicPendingScript;
 class ScriptResource;
-class ScriptState;
-class Settings;
 class SourceStream;
 
 // ScriptStreamer streams incomplete script data to V8 so that it can be parsed
@@ -42,7 +40,7 @@
     kAlreadyLoaded,  // DEPRECATED
     kNotHTTP,
     kReload,
-    kContextNotValid,
+    kContextNotValid,  // DEPRECATED
     kEncodingNotSupported,
     kThreadBusy,
     kV8CannotStream,
@@ -65,8 +63,6 @@
   // Launches a task (on a background thread) which will stream the given
   // ClassicPendingScript into V8 as it loads.
   static void StartStreaming(ClassicPendingScript*,
-                             Settings*,
-                             ScriptState*,
                              scoped_refptr<base::SingleThreadTaskRunner>,
                              NotStreamingReason* not_streaming_reason);
 
@@ -126,7 +122,6 @@
   static constexpr size_t kMaximumLengthOfBOM = 4;
 
   ScriptStreamer(ClassicPendingScript*,
-                 ScriptState*,
                  v8::ScriptCompiler::CompileOptions,
                  scoped_refptr<base::SingleThreadTaskRunner>);
 
@@ -160,8 +155,6 @@
   // What kind of cached data V8 produces during streaming.
   v8::ScriptCompiler::CompileOptions compile_options_;
 
-  Member<ScriptState> script_state_;
-
   // Keep the script URL string for event tracing.
   const String script_url_string_;
 
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
index 7ec1d52..949407d0 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
@@ -90,8 +90,8 @@
   }
 
  protected:
-  void AppendData(const char* data) {
-    GetResource()->AppendData(data, strlen(data));
+  void AppendData(ScriptResource* resource, const char* data) {
+    resource->AppendData(data, strlen(data));
     // Yield control to the background thread, so that V8 gets a chance to
     // process the data before the main thread adds more. Note that we
     // cannot fully control in what kind of chunks the data is passed to V8
@@ -100,15 +100,19 @@
     test::YieldCurrentThread();
   }
 
-  void AppendPadding() {
+  void AppendData(const char* data) { AppendData(GetResource(), data); }
+
+  void AppendPadding(ScriptResource* resource) {
     for (int i = 0; i < 10; ++i) {
-      AppendData(
-          " /* this is padding to make the script long enough, so "
-          "that V8's buffer gets filled and it starts processing "
-          "the data */ ");
+      AppendData(resource,
+                 " /* this is padding to make the script long enough, so "
+                 "that V8's buffer gets filled and it starts processing "
+                 "the data */ ");
     }
   }
 
+  void AppendPadding() { AppendPadding(GetResource()); }
+
   void Finish() {
     GetResource()->Loader()->DidFinishLoading(TimeTicks(), 0, 0, 0, false);
     GetResource()->SetStatus(ResourceStatus::kCached);
@@ -152,8 +156,7 @@
   // Test that we can successfully compile a streamed script.
   V8TestingScope scope;
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -193,8 +196,7 @@
   // handle it gracefully.
   V8TestingScope scope;
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -235,8 +237,7 @@
   // while streaming is ongoing, and ScriptStreamer handles it gracefully.
   V8TestingScope scope;
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -259,6 +260,42 @@
   EXPECT_FALSE(client->Finished());
 }
 
+TEST_F(ScriptStreamingTest, DataAfterCancellingStreaming) {
+  // Test that the upper layers (PendingScript and up) can be ramped down
+  // before streaming is started, and ScriptStreamer handles it gracefully.
+  V8TestingScope scope;
+  ScriptStreamer::NotStreamingReason reason;
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
+                                 &reason);
+  GetPendingScript()->SetNotStreamingReasonForTest(reason);
+  TestPendingScriptClient* client = new TestPendingScriptClient;
+  GetPendingScript()->WatchForLoad(client);
+
+  // In general, we cannot control what the background thread is doing
+  // (whether it's parsing or waiting for more data). In this test, we have
+  // given it so little data that it's surely waiting for more.
+
+  EXPECT_FALSE(client->Finished());
+
+  // Keep the resource alive
+  Persistent<ScriptResource> resource = GetResource();
+
+  // Simulate cancelling the network load (e.g., because the user navigated
+  // away).
+  GetPendingScript()->Dispose();
+  pending_script_ = nullptr;  // This would destroy m_resource, but we are still
+                              // holding on to it here.
+
+  // Make sure the streaming starts.
+  AppendPadding(resource);
+  resource.Clear();
+
+  // The V8 side will complete too. This should not crash. We don't receive
+  // any results from the streaming and the client doesn't get notified.
+  ProcessTasksUntilStreamingComplete();
+  EXPECT_FALSE(client->Finished());
+}
+
 TEST_F(ScriptStreamingTest, SuppressingStreaming) {
   // If we notice during streaming that there is a code cache, streaming
   // is suppressed (V8 doesn't parse while the script is loading), and the
@@ -266,8 +303,7 @@
   // script is loaded.
   V8TestingScope scope;
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -299,8 +335,7 @@
   // loaded.
   V8TestingScope scope;
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -322,8 +357,7 @@
   ScriptStreamer::SetSmallScriptThresholdForTesting(100);
 
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -348,8 +382,7 @@
   ScriptStreamer::SetSmallScriptThresholdForTesting(100);
 
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -388,8 +421,7 @@
   GetResource()->SetEncodingForTest("windows-1252");
 
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -430,8 +462,7 @@
   GetResource()->SetEncodingForTest("windows-1252");
 
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
   TestPendingScriptClient* client = new TestPendingScriptClient;
@@ -466,8 +497,7 @@
 TEST_F(ScriptStreamingTest, GarbageCollectDuringStreaming) {
   V8TestingScope scope;
   ScriptStreamer::NotStreamingReason reason;
-  ScriptStreamer::StartStreaming(GetPendingScript(), GetSettings(),
-                                 scope.GetScriptState(), loading_task_runner_,
+  ScriptStreamer::StartStreaming(GetPendingScript(), loading_task_runner_,
                                  &reason);
   GetPendingScript()->SetNotStreamingReasonForTest(reason);
 
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
index 18603ac..ec6095e 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -51,6 +51,7 @@
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
@@ -322,8 +323,28 @@
   script_state->DisposePerContextData();
 }
 
-void V8GCController::CollectAllGarbageForTesting(v8::Isolate* isolate) {
-  for (unsigned i = 0; i < 5; i++)
+void V8GCController::CollectAllGarbageForTesting(
+    v8::Isolate* isolate,
+    v8::EmbedderHeapTracer::EmbedderStackState stack_state) {
+  constexpr unsigned kNumberOfGCs = 5;
+
+  if (stack_state != v8::EmbedderHeapTracer::EmbedderStackState::kUnknown) {
+    V8PerIsolateData* data = V8PerIsolateData::From(isolate);
+    v8::EmbedderHeapTracer* tracer =
+        RuntimeEnabledFeatures::HeapUnifiedGarbageCollectionEnabled()
+            ? static_cast<v8::EmbedderHeapTracer*>(
+                  data->GetUnifiedHeapController())
+            : static_cast<v8::EmbedderHeapTracer*>(
+                  data->GetScriptWrappableMarkingVisitor());
+    // Passing a stack state is only supported when either wrapper tracing or
+    // unified heap is enabled.
+    CHECK(tracer);
+    for (unsigned i = 0; i < kNumberOfGCs; i++)
+      tracer->GarbageCollectionForTesting(stack_state);
+    return;
+  }
+
+  for (unsigned i = 0; i < kNumberOfGCs; i++)
     isolate->RequestGarbageCollectionForTesting(
         v8::Isolate::kFullGarbageCollection);
 }
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h
index 4b877d7..456be58 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h
@@ -49,11 +49,14 @@
   static void GcEpilogue(v8::Isolate*, v8::GCType, v8::GCCallbackFlags);
 
   static void CollectGarbage(v8::Isolate*, bool only_minor_gc = false);
-  // You should use collectAllGarbageForTesting() when you want to collect all
-  // V8 & Blink objects. It runs multiple V8 GCs to collect references
-  // that cross the binding boundary. collectAllGarbage() also runs multipe
-  // Oilpan GCs to collect a chain of persistent handles.
-  static void CollectAllGarbageForTesting(v8::Isolate*);
+
+  // Collects V8 and Blink objects in multiple garbage collectin passes. Also
+  // triggers follow up garbage collections in Oilpan to collect chains of
+  // persistent handles.
+  static void CollectAllGarbageForTesting(
+      v8::Isolate*,
+      v8::EmbedderHeapTracer::EmbedderStackState stack_state =
+          v8::EmbedderHeapTracer::EmbedderStackState::kUnknown);
 
   static Node* OpaqueRootForGC(v8::Isolate*, Node*);
 
diff --git a/third_party/blink/renderer/controller/blink_leak_detector.cc b/third_party/blink/renderer/controller/blink_leak_detector.cc
index 9982d2c..57be6c1 100644
--- a/third_party/blink/renderer/controller/blink_leak_detector.cc
+++ b/third_party/blink/renderer/controller/blink_leak_detector.cc
@@ -82,24 +82,18 @@
   for (auto resource_fetcher : ResourceFetcher::MainThreadFetchers())
     resource_fetcher->PrepareForLeakDetection();
 
-  V8GCController::CollectAllGarbageForTesting(
-      V8PerIsolateData::MainThreadIsolate());
-  CoreInitializer::GetInstance().CollectAllGarbageForAnimationWorklet();
-  // Note: Oilpan precise GC is scheduled at the end of the event loop.
-
   // Task queue may contain delayed object destruction tasks.
   // This method is called from navigation hook inside FrameLoader,
   // so previous document is still held by the loader until the next event loop.
   // Complete all pending tasks before proceeding to gc.
-  number_of_gc_needed_ = 2;
+  number_of_gc_needed_ = 3;
   delayed_gc_timer_.StartOneShot(TimeDelta(), FROM_HERE);
 }
 
 void BlinkLeakDetector::TimerFiredGC(TimerBase*) {
-  // We do a second and third GC here to address flakiness
-  // The second GC is necessary as Resource GC may have postponed clean-up tasks
-  // to next event loop.  The third GC is necessary for cleaning up Document
-  // after worker object died.
+  // Multiple rounds of GC are necessary as collectors may have postponed
+  // clean-up tasks to the next event loop. E.g. the third GC is necessary for
+  // cleaning up Document after the worker object has been reclaimed.
 
   // Inspect counters on the next event loop.
   if (--number_of_gc_needed_ > 0) {
@@ -120,7 +114,8 @@
   }
 
   V8GCController::CollectAllGarbageForTesting(
-      V8PerIsolateData::MainThreadIsolate());
+      V8PerIsolateData::MainThreadIsolate(),
+      v8::EmbedderHeapTracer::EmbedderStackState::kEmpty);
   CoreInitializer::GetInstance().CollectAllGarbageForAnimationWorklet();
   // Note: Oilpan precise GC is scheduled at the end of the event loop.
 }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index e0b72cfe..3eef932 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -7588,6 +7588,12 @@
   return false;
 }
 
+bool Document::IsLazyLoadPolicyEnforced() const {
+  return RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
+         !GetFeaturePolicy()->IsFeatureEnabled(
+             mojom::FeaturePolicyFeature::kLazyLoad);
+}
+
 LazyLoadImageObserver& Document::EnsureLazyLoadImageObserver() {
   if (!lazy_load_image_observer_)
     lazy_load_image_observer_ = new LazyLoadImageObserver();
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 0f773bc9..3659b8b 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1454,6 +1454,7 @@
 #endif
 
   bool IsVerticalScrollEnforced() const { return is_vertical_scroll_enforced_; }
+  bool IsLazyLoadPolicyEnforced() const;
 
   LazyLoadImageObserver& EnsureLazyLoadImageObserver();
 
diff --git a/third_party/blink/renderer/core/editing/inline_box_position.cc b/third_party/blink/renderer/core/editing/inline_box_position.cc
index 3dfcd86..76e7cf3 100644
--- a/third_party/blink/renderer/core/editing/inline_box_position.cc
+++ b/third_party/blink/renderer/core/editing/inline_box_position.cc
@@ -154,8 +154,12 @@
 
     candidate = box;
   }
+
+  // TODO(editing-dev): The fixup below seems hacky. It may also be incorrect in
+  // non-ltr text. Make it saner.
   if (candidate && candidate == text_layout_object->LastTextBox() &&
-      affinity == TextAffinity::kDownstream) {
+      affinity == TextAffinity::kDownstream &&
+      caret_offset == candidate->CaretMaxOffset()) {
     inline_box = SearchAheadForBetterMatch(text_layout_object);
     if (inline_box)
       caret_offset = inline_box->CaretMinOffset();
diff --git a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
index 0481261..ab9e521f 100644
--- a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
+++ b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
@@ -958,4 +958,17 @@
             local_caret_rect.layout_object);
 }
 
+// https://crbug.com/883044
+TEST_P(ParameterizedLocalCaretRectTest, AfterCollapsedWhiteSpaceInRTLText) {
+  LoadAhem();
+  InsertStyleElement(
+      "bdo { display: block; font: 10px/10px Ahem; width: 100px }");
+  const Position position =
+      SetCaretTextToBody("<bdo dir=rtl>AAA  |BBB<span>CCC</span></bdo>");
+  const Node* text = position.AnchorNode();
+  EXPECT_EQ(LocalCaretRect(text->GetLayoutObject(), LayoutRect(60, 0, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(position, TextAffinity::kDownstream)));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
index d1876f4..12c90acb 100644
--- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
@@ -446,6 +446,11 @@
   return GetFrame()->View()->GetCompositingRect();
 }
 
+bool WebRemoteFrameImpl::OOPIFHasPointerEventsNone() const {
+  DCHECK(GetFrame()->DeprecatedLocalOwner());
+  return GetFrame()->DeprecatedLocalOwner()->HasPointerEventsNone();
+}
+
 WebRemoteFrameImpl::WebRemoteFrameImpl(WebTreeScopeType scope,
                                        WebRemoteFrameClient* client)
     : WebRemoteFrame(scope),
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.h b/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
index fac141d..7d5588b 100644
--- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
+++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
@@ -91,6 +91,7 @@
   void SetHasReceivedUserGestureBeforeNavigation(bool value) override;
   v8::Local<v8::Object> GlobalProxy() const override;
   WebRect GetCompositingRect() override;
+  bool OOPIFHasPointerEventsNone() const override;
 
   void InitializeCoreFrame(Page&, FrameOwner*, const AtomicString& name);
   RemoteFrame* GetFrame() const { return frame_.Get(); }
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 3a2e347..c095316 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2416,9 +2416,9 @@
     DocumentLifecycle::LifecycleState target_state) {
   bool run_more_lifecycle_phases =
       RunStyleAndLayoutLifecyclePhases(target_state);
-  DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
   if (!run_more_lifecycle_phases)
     return;
+  DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
 
   if (!GetLayoutView())
     return;
@@ -2506,7 +2506,12 @@
 
     NotifyFrameRectsChangedIfNeededRecursive();
   }
-  return true;
+  // If we exceed the number of re-layouts during ResizeObserver notifications,
+  // then we shouldn't continue with the lifecycle updates. At that time, we
+  // have scheduled an animation and we'll try again.
+  DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean ||
+         Lifecycle().GetState() == DocumentLifecycle::kVisualUpdatePending);
+  return Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean;
 }
 
 bool LocalFrameView::RunCompositingLifecyclePhase(
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 59a10e8..c1930eaf 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -196,6 +196,10 @@
   ToHTMLFrameOwnerElement(Owner())->SetNeedsCompositingUpdate();
 }
 
+void RemoteFrame::PointerEventsChanged() {
+  Client()->PointerEventsChanged();
+}
+
 void RemoteFrame::AdvanceFocus(WebFocusType type, LocalFrame* source) {
   Client()->AdvanceFocus(type, source);
 }
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index 689b787f..77d28f0e 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -61,6 +61,8 @@
 
   RemoteFrameClient* Client() const;
 
+  void PointerEventsChanged();
+
  private:
   RemoteFrame(RemoteFrameClient*, Page&, FrameOwner*);
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client.h b/third_party/blink/renderer/core/frame/remote_frame_client.h
index faf6c60..8fd0df16 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_client.h
@@ -62,6 +62,8 @@
 
   virtual void SetInheritedEffectiveTouchAction(TouchAction) = 0;
 
+  virtual void PointerEventsChanged() = 0;
+
   virtual void UpdateRenderThrottlingStatus(bool isThrottled,
                                             bool subtreeThrottled) = 0;
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
index b60c1a4..e6cee698 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
@@ -176,6 +176,10 @@
   web_frame_->Client()->SetInheritedEffectiveTouchAction(touch_action);
 }
 
+void RemoteFrameClientImpl::PointerEventsChanged() {
+  web_frame_->Client()->PointerEventsChanged();
+}
+
 void RemoteFrameClientImpl::UpdateRenderThrottlingStatus(
     bool is_throttled,
     bool subtree_throttled) {
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
index fa9ad8cb..b4dee59 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
@@ -49,6 +49,7 @@
   void VisibilityChanged(bool visible) override;
   void SetIsInert(bool) override;
   void SetInheritedEffectiveTouchAction(TouchAction) override;
+  void PointerEventsChanged() override;
   void UpdateRenderThrottlingStatus(bool is_throttled,
                                     bool subtree_throttled) override;
   uint32_t Print(const IntRect&, cc::PaintCanvas*) const override;
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index 2d8afad7..3bee3a0 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -24,11 +24,13 @@
 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/remote_frame.h"
 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
 #include "third_party/blink/renderer/core/html/lazy_load_frame_observer.h"
 #include "third_party/blink/renderer/core/html_names.h"
@@ -235,6 +237,12 @@
   }
 }
 
+void HTMLFrameOwnerElement::PointerEventsChanged() {
+  if (ContentFrame() && ContentFrame()->IsRemoteFrame()) {
+    ToRemoteFrame(ContentFrame())->PointerEventsChanged();
+  }
+}
+
 void HTMLFrameOwnerElement::FrameOwnerPropertiesChanged() {
   // Don't notify about updates if ContentFrame() is null, for example when
   // the subframe hasn't been created yet.
@@ -342,10 +350,13 @@
   // Update the |should_lazy_load_children_| value according to the "lazyload"
   // attribute immediately, so that it still gets respected even if the "src"
   // attribute gets parsed in ParseAttribute() before the "lazyload" attribute
-  // does.
+  // does. Note that when the *feature policy* for "lazyload" is disabled, the
+  // attribute value "off" for "lazyload" is ignored (i.e., interpreted as
+  // "auto" instead).
   if (should_lazy_load_children_ &&
       EqualIgnoringASCIICase(FastGetAttribute(HTMLNames::lazyloadAttr),
-                             "off")) {
+                             "off") &&
+      !GetDocument().IsLazyLoadPolicyEnforced()) {
     should_lazy_load_children_ = false;
   }
 
@@ -431,6 +442,12 @@
   return true;
 }
 
+bool HTMLFrameOwnerElement::HasPointerEventsNone() const {
+  return GetComputedStyle()
+             ? GetComputedStyle()->PointerEvents() == EPointerEvents::kNone
+             : false;
+}
+
 void HTMLFrameOwnerElement::CancelPendingLazyLoad() {
   if (!lazy_load_frame_observer_)
     return;
@@ -444,7 +461,11 @@
 void HTMLFrameOwnerElement::ParseAttribute(
     const AttributeModificationParams& params) {
   if (params.name == HTMLNames::lazyloadAttr) {
-    if (EqualIgnoringASCIICase(params.new_value, "off")) {
+    // Note that when the *feature policy* for "lazyload" is disabled, the
+    // attribute value "off" for "lazyload" is ignored (i.e., interpreted as
+    // "auto" instead).
+    if (EqualIgnoringASCIICase(params.new_value, "off") &&
+        !GetDocument().IsLazyLoadPolicyEnforced()) {
       should_lazy_load_children_ = false;
       if (lazy_load_frame_observer_ &&
           lazy_load_frame_observer_->IsLazyLoadPending()) {
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.h b/third_party/blink/renderer/core/html/html_frame_owner_element.h
index f8fe9ff..87d8bec 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.h
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.h
@@ -116,6 +116,11 @@
   // For unit tests, manually trigger the UpdateContainerPolicy method.
   void UpdateContainerPolicyForTests() { UpdateContainerPolicy(); }
 
+  bool HasPointerEventsNone() const;
+  // This function is to notify ChildFrameCompositor of pointer-events changes
+  // of an OOPIF.
+  void PointerEventsChanged();
+
   void CancelPendingLazyLoad();
 
   void ParseAttribute(const AttributeModificationParams&) override;
@@ -124,6 +129,7 @@
 
  protected:
   HTMLFrameOwnerElement(const QualifiedName& tag_name, Document&);
+
   void SetSandboxFlags(SandboxFlags);
 
   bool LoadOrRedirectSubframe(const KURL&,
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn
index b5ab541..cdd86e7 100644
--- a/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -442,6 +442,7 @@
     "ng/ng_out_of_flow_layout_part.cc",
     "ng/ng_out_of_flow_layout_part.h",
     "ng/ng_out_of_flow_positioned_descendant.h",
+    "ng/ng_outline_type.h",
     "ng/ng_outline_utils.cc",
     "ng/ng_outline_utils.h",
     "ng/ng_page_layout_algorithm.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index ca5517f..e8b111f 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1853,14 +1853,13 @@
   return caret_rect;
 }
 
-void LayoutBlock::AddOutlineRects(
-    Vector<LayoutRect>& rects,
-    const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+void LayoutBlock::AddOutlineRects(Vector<LayoutRect>& rects,
+                                  const LayoutPoint& additional_offset,
+                                  NGOutlineType include_block_overflows) const {
   if (!IsAnonymous())  // For anonymous blocks, the children add outline rects.
     rects.push_back(LayoutRect(additional_offset, Size()));
 
-  if (include_block_overflows == kIncludeBlockVisualOverflow &&
+  if (include_block_overflows == NGOutlineType::kIncludeBlockVisualOverflow &&
       !HasOverflowClip() && !HasControlClip()) {
     AddOutlineRectsForNormalChildren(rects, additional_offset,
                                      include_block_overflows);
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h
index 380d4eb..e551f130 100644
--- a/third_party/blink/renderer/core/layout/layout_block.h
+++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -450,7 +450,7 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const override;
+                       NGOutlineType) const override;
 
   void UpdateBlockChildDirtyBitsBeforeLayout(bool relayout_children,
                                              LayoutBox&);
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 50be27d..a96125b 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4818,7 +4818,7 @@
 void LayoutBlockFlow::AddOutlineRects(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   // For blocks inside inlines, we go ahead and include margins so that we run
   // right up to the inline boxes above and below us (thus getting merged with
   // them to form a single irregular shape).
@@ -4848,7 +4848,7 @@
   LayoutBlock::AddOutlineRects(rects, additional_offset,
                                include_block_overflows);
 
-  if (include_block_overflows == kIncludeBlockVisualOverflow &&
+  if (include_block_overflows == NGOutlineType::kIncludeBlockVisualOverflow &&
       !HasOverflowClip() && !HasControlClip()) {
     for (RootInlineBox* curr = FirstRootBox(); curr;
          curr = curr->NextRootBox()) {
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index 32b78902..640eede 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -536,7 +536,7 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const override;
+                       NGOutlineType) const override;
 
   bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
   void InvalidateDisplayItemClients(PaintInvalidationReason) const override;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index fe9229f..b3ab0db2 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -963,7 +963,7 @@
 
 void LayoutBox::AddOutlineRects(Vector<LayoutRect>& rects,
                                 const LayoutPoint& additional_offset,
-                                IncludeBlockVisualOverflowOrNot) const {
+                                NGOutlineType) const {
   rects.push_back(LayoutRect(additional_offset, Size()));
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 5377cb3..5163c39c 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -456,7 +456,7 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const override;
+                       NGOutlineType) const override;
 
   // Use this with caution! No type checking is done!
   LayoutBox* PreviousSiblingBox() const;
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 3ad5ae0..4bcb13bb 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -522,7 +522,7 @@
 void LayoutBoxModelObject::AddOutlineRectsForNormalChildren(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   for (LayoutObject* child = SlowFirstChild(); child;
        child = child->NextSibling()) {
     // Outlines of out-of-flow positioned descendants are handled in
@@ -547,7 +547,7 @@
     const LayoutObject& descendant,
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   if (descendant.IsText() || descendant.IsListMarker())
     return;
 
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.h b/third_party/blink/renderer/core/layout/layout_box_model_object.h
index 775d043..c12b0b7 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.h
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -475,11 +475,11 @@
 
   void AddOutlineRectsForNormalChildren(Vector<LayoutRect>&,
                                         const LayoutPoint& additional_offset,
-                                        IncludeBlockVisualOverflowOrNot) const;
+                                        NGOutlineType) const;
   void AddOutlineRectsForDescendant(const LayoutObject& descendant,
                                     Vector<LayoutRect>&,
                                     const LayoutPoint& additional_offset,
-                                    IncludeBlockVisualOverflowOrNot) const;
+                                    NGOutlineType) const;
 
   void AddLayerHitTestRects(LayerHitTestRects&,
                             const PaintLayer*,
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index ccef8ac..007144d6d 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -255,6 +255,13 @@
 void LayoutEmbeddedContent::StyleDidChange(StyleDifference diff,
                                            const ComputedStyle* old_style) {
   LayoutReplaced::StyleDidChange(diff, old_style);
+
+  if (!old_style || Style()->PointerEvents() != old_style->PointerEvents()) {
+    Node* node = GetNode();
+    if (node->IsFrameOwnerElement())
+      ToHTMLFrameOwnerElement(node)->PointerEventsChanged();
+  }
+
   EmbeddedContentView* embedded_content_view = GetEmbeddedContentView();
   if (!embedded_content_view)
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_flow_thread.cc
index 28c03e0..d2643f83 100644
--- a/third_party/blink/renderer/core/layout/layout_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_flow_thread.cc
@@ -159,7 +159,7 @@
 void LayoutFlowThread::AddOutlineRects(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   Vector<LayoutRect> rects_in_flowthread;
   LayoutBlockFlow::AddOutlineRects(rects_in_flowthread, additional_offset,
                                    include_block_overflows);
diff --git a/third_party/blink/renderer/core/layout/layout_flow_thread.h b/third_party/blink/renderer/core/layout/layout_flow_thread.h
index 3d172c5..7a4c1d1 100644
--- a/third_party/blink/renderer/core/layout/layout_flow_thread.h
+++ b/third_party/blink/renderer/core/layout/layout_flow_thread.h
@@ -113,7 +113,7 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const override;
+                       NGOutlineType) const override;
 
   bool NodeAtPoint(HitTestResult&,
                    const HitTestLocation& location_in_container,
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 2bd9795..9c2cab07 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1589,7 +1589,7 @@
 void LayoutInline::AddOutlineRects(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   AbsoluteLayoutRectsGeneratorContext context(rects, additional_offset);
   GenerateLineBoxRects(context);
   AddOutlineRectsForChildrenAndContinuations(rects, additional_offset,
@@ -1599,7 +1599,7 @@
 void LayoutInline::AddOutlineRectsForChildrenAndContinuations(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   AddOutlineRectsForNormalChildren(rects, additional_offset,
                                    include_block_overflows);
   AddOutlineRectsForContinuations(rects, additional_offset,
@@ -1609,7 +1609,7 @@
 void LayoutInline::AddOutlineRectsForContinuations(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    IncludeBlockVisualOverflowOrNot include_block_overflows) const {
+    NGOutlineType include_block_overflows) const {
   if (LayoutBoxModelObject* continuation = Continuation()) {
     if (continuation->NeedsLayout()) {
       // TODO(mstensho): Prevent this from happening. Before we can get the
@@ -1634,7 +1634,8 @@
 
 FloatRect LayoutInline::LocalBoundingBoxRectForAccessibility() const {
   Vector<LayoutRect> rects;
-  AddOutlineRects(rects, LayoutPoint(), kIncludeBlockVisualOverflow);
+  AddOutlineRects(rects, LayoutPoint(),
+                  NGOutlineType::kIncludeBlockVisualOverflow);
   return FloatRect(UnionRect(rects));
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_inline.h b/third_party/blink/renderer/core/layout/layout_inline.h
index 4dd643de..3753d23 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.h
+++ b/third_party/blink/renderer/core/layout/layout_inline.h
@@ -190,16 +190,16 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const final;
+                       NGOutlineType) const final;
   // The following methods are called from the container if it has already added
   // outline rects for line boxes and/or children of this LayoutInline.
   void AddOutlineRectsForChildrenAndContinuations(
       Vector<LayoutRect>&,
       const LayoutPoint& additional_offset,
-      IncludeBlockVisualOverflowOrNot) const;
+      NGOutlineType) const;
   void AddOutlineRectsForContinuations(Vector<LayoutRect>&,
                                        const LayoutPoint& additional_offset,
-                                       IncludeBlockVisualOverflowOrNot) const;
+                                       NGOutlineType) const;
 
   using LayoutBoxModelObject::Continuation;
   using LayoutBoxModelObject::SetContinuation;
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 7af3d7c..341f995b 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -40,6 +40,7 @@
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_object_child_list.h"
 #include "third_party/blink/renderer/core/layout/map_coordinates_flags.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_outline_type.h"
 #include "third_party/blink/renderer/core/layout/subtree_layout_scope.h"
 #include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h"
 #include "third_party/blink/renderer/core/paint/compositing/compositing_state.h"
@@ -1707,22 +1708,18 @@
   // Collects rectangles that the outline of this object would be drawing along
   // the outside of, even if the object isn't styled with a outline for now. The
   // rects also cover continuations.
-  enum IncludeBlockVisualOverflowOrNot {
-    kDontIncludeBlockVisualOverflow,
-    kIncludeBlockVisualOverflow,
-  };
   virtual void AddOutlineRects(Vector<LayoutRect>&,
                                const LayoutPoint& additional_offset,
-                               IncludeBlockVisualOverflowOrNot) const {}
+                               NGOutlineType) const {}
 
   // For history and compatibility reasons, we draw outline:auto (for focus
   // rings) and normal style outline differently.
   // Focus rings enclose block visual overflows (of line boxes and descendants),
   // while normal outlines don't.
-  IncludeBlockVisualOverflowOrNot OutlineRectsShouldIncludeBlockVisualOverflow()
-      const {
-    return StyleRef().OutlineStyleIsAuto() ? kIncludeBlockVisualOverflow
-                                           : kDontIncludeBlockVisualOverflow;
+  NGOutlineType OutlineRectsShouldIncludeBlockVisualOverflow() const {
+    return StyleRef().OutlineStyleIsAuto()
+               ? NGOutlineType::kIncludeBlockVisualOverflow
+               : NGOutlineType::kDontIncludeBlockVisualOverflow;
   }
 
   // Collects rectangles enclosing visual overflows of the DOM subtree under
@@ -1734,7 +1731,8 @@
   void AddElementVisualOverflowRects(
       Vector<LayoutRect>& rects,
       const LayoutPoint& additional_offset) const {
-    AddOutlineRects(rects, additional_offset, kIncludeBlockVisualOverflow);
+    AddOutlineRects(rects, additional_offset,
+                    NGOutlineType::kIncludeBlockVisualOverflow);
   }
 
   // Compute a list of hit-test rectangles per layer rooted at this
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.cc b/third_party/blink/renderer/core/layout/layout_text_control.cc
index 50cc9015..a067429 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -301,7 +301,7 @@
 
 void LayoutTextControl::AddOutlineRects(Vector<LayoutRect>& rects,
                                         const LayoutPoint& additional_offset,
-                                        IncludeBlockVisualOverflowOrNot) const {
+                                        NGOutlineType) const {
   rects.push_back(LayoutRect(additional_offset, Size()));
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.h b/third_party/blink/renderer/core/layout/layout_text_control.h
index 8f42483..43aed74 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control.h
+++ b/third_party/blink/renderer/core/layout/layout_text_control.h
@@ -94,7 +94,7 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const final;
+                       NGOutlineType) const final;
 
   bool CanBeProgramaticallyScrolled() const final { return true; }
 };
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
index 52307972..e1f395e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -26,6 +26,8 @@
 // In this representation TextNodes are merged up into their parent inline
 // element where possible.
 class CORE_EXPORT NGInlineItem {
+  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+
  public:
   enum NGInlineItemType {
     kText,
@@ -206,6 +208,9 @@
 // Represents a text content with a list of NGInlineItem. A node may have an
 // additional NGInlineItemsData for ::first-line pseudo element.
 struct CORE_EXPORT NGInlineItemsData {
+  USING_FAST_MALLOC(NGInlineItemsData);
+
+ public:
   // Text content for all inline items represented by a single NGInlineNode.
   // Encoded either as UTF-16 or latin-1 depending on the content.
   String text_content;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 09e354af..c7416c3 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -149,8 +149,7 @@
 void LayoutNGMixin<Base>::AddOutlineRects(
     Vector<LayoutRect>& rects,
     const LayoutPoint& additional_offset,
-    LayoutObject::IncludeBlockVisualOverflowOrNot include_block_overflows)
-    const {
+    NGOutlineType include_block_overflows) const {
   Base::AddOutlineRects(rects, additional_offset, include_block_overflows);
   if (CurrentFragment()) {
     CurrentFragment()->AddSelfOutlineRects(&rects, additional_offset);
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index 3783f98..4901d595 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -89,10 +89,9 @@
                         scoped_refptr<NGPaintFragment>);
 
  protected:
-  void AddOutlineRects(
-      Vector<LayoutRect>&,
-      const LayoutPoint& additional_offset,
-      LayoutObject::IncludeBlockVisualOverflowOrNot) const override;
+  void AddOutlineRects(Vector<LayoutRect>&,
+                       const LayoutPoint& additional_offset,
+                       NGOutlineType) const override;
 
   const NGPhysicalBoxFragment* CurrentFragment() const override;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index d13b22c..72930cc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/html_marquee_element.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_set.h"
@@ -140,8 +141,6 @@
 
 }  // namespace
 
-NGBlockNode::NGBlockNode(LayoutBox* box) : NGLayoutInputNode(box, kBlock) {}
-
 scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
     const NGConstraintSpace& constraint_space,
     NGBreakToken* break_token) {
@@ -324,8 +323,12 @@
   base::Optional<MinMaxSize> maybe_sizes =
       ComputeMinMaxSizeWithAlgorithm(*this, *constraint_space,
                                      /* break token */ nullptr, input);
-  if (maybe_sizes.has_value())
+  if (maybe_sizes.has_value()) {
+    if (UNLIKELY(IsHTMLMarqueeElement(box_->GetNode()) &&
+                 ToHTMLMarqueeElement(box_->GetNode())->IsHorizontal()))
+      maybe_sizes->min_size = LayoutUnit();
     return *maybe_sizes;
+  }
 
   if (!box_->GetFrameView()->IsInPerformLayout()) {
     // We can't synthesize these using Layout() if we're not in PerformLayout.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
index f0b9868..74bb0ee 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -29,7 +29,7 @@
 class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
   friend NGLayoutInputNode;
  public:
-  explicit NGBlockNode(LayoutBox*);
+  explicit NGBlockNode(LayoutBox* box) : NGLayoutInputNode(box, kBlock) {}
 
   scoped_refptr<NGLayoutResult> Layout(
       const NGConstraintSpace& constraint_space,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
index 4197e06..fbe4d56 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
@@ -42,7 +42,7 @@
                                      scoped_refptr<const ComputedStyle> style,
                                      WritingMode writing_mode,
                                      TextDirection direction)
-    : NGContainerFragmentBuilder(style, writing_mode, direction),
+    : NGContainerFragmentBuilder(std::move(style), writing_mode, direction),
       node_(node),
       layout_object_(node.GetLayoutBox()),
       box_type_(NGPhysicalFragment::NGBoxType::kNormalBox),
@@ -53,7 +53,7 @@
                                      scoped_refptr<const ComputedStyle> style,
                                      WritingMode writing_mode,
                                      TextDirection direction)
-    : NGContainerFragmentBuilder(style, writing_mode, direction),
+    : NGContainerFragmentBuilder(std::move(style), writing_mode, direction),
       node_(nullptr),
       layout_object_(layout_object),
       box_type_(NGPhysicalFragment::NGBoxType::kNormalBox),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_outline_type.h b/third_party/blink/renderer/core/layout/ng/ng_outline_type.h
new file mode 100644
index 0000000..a0fb8c3
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/ng_outline_type.h
@@ -0,0 +1,18 @@
+// 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_LAYOUT_NG_NG_OUTLINE_TYPE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_OUTLINE_TYPE_H_
+
+namespace blink {
+
+// Outline styles
+enum class NGOutlineType {
+  kDontIncludeBlockVisualOverflow,  // Standard outline
+  kIncludeBlockVisualOverflow,      // Focus outline
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
index c72e488..a0e790fc 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
@@ -89,10 +89,9 @@
 
 // This method is called from inside PaintOutline(), and since we call
 // PaintOutline() while transformed to our coord system, return local coords.
-void LayoutSVGModelObject::AddOutlineRects(
-    Vector<LayoutRect>& rects,
-    const LayoutPoint&,
-    IncludeBlockVisualOverflowOrNot) const {
+void LayoutSVGModelObject::AddOutlineRects(Vector<LayoutRect>& rects,
+                                           const LayoutPoint&,
+                                           NGOutlineType) const {
   rects.push_back(LayoutRect(VisualRectInLocalSVGCoordinates()));
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
index ca45f520..bd663b8 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
@@ -102,7 +102,7 @@
                    HitTestAction) final;
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const final;
+                       NGOutlineType) const final;
 
  protected:
   FloatRect local_visual_rect_;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 0d720fe..78cad04 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -401,7 +401,7 @@
 
 void LayoutSVGText::AddOutlineRects(Vector<LayoutRect>& rects,
                                     const LayoutPoint&,
-                                    IncludeBlockVisualOverflowOrNot) const {
+                                    NGOutlineType) const {
   rects.push_back(LayoutRect(ObjectBoundingBox()));
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index 77a6eda..86d88bbe 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -48,7 +48,7 @@
 
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
-                       IncludeBlockVisualOverflowOrNot) const override;
+                       NGOutlineType) const override;
 
   static LayoutSVGText* LocateLayoutSVGTextAncestor(LayoutObject*);
   static const LayoutSVGText* LocateLayoutSVGTextAncestor(const LayoutObject*);
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource.cc b/third_party/blink/renderer/core/loader/resource/script_resource.cc
index 45754678..d246b8e 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource.cc
+++ b/third_party/blink/renderer/core/loader/resource/script_resource.cc
@@ -54,11 +54,12 @@
 bool IsRequestContextSupported(WebURLRequest::RequestContext request_context) {
   // TODO(nhiroki): Support |kRequestContextSharedWorker| for module loading for
   // shared workers (https://crbug.com/824646).
+  // TODO(nhiroki): Support |kRequestContextServiceWorker| for module loading
+  // for service workers (https://crbug.com/824647).
   // TODO(nhiroki): Support "audioworklet" and "paintworklet" destinations.
   switch (request_context) {
     case WebURLRequest::kRequestContextScript:
     case WebURLRequest::kRequestContextWorker:
-    case WebURLRequest::kRequestContextServiceWorker:
       return true;
     default:
       break;
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index 97610c2..9dd5523 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -320,6 +320,17 @@
 
 #endif
 
+GraphicsLayer* PaintLayerCompositor::OverlayFullscreenVideoGraphicsLayer() {
+  LayoutVideo* video =
+      FindFullscreenVideoLayoutObject(layout_view_.GetDocument());
+  if (!video || !video->Layer()->HasCompositedLayerMapping() ||
+      !video->VideoElement()->UsesOverlayFullscreenVideo()) {
+    return nullptr;
+  }
+
+  return video->Layer()->GetCompositedLayerMapping()->MainGraphicsLayer();
+}
+
 void PaintLayerCompositor::ApplyOverlayFullscreenVideoAdjustmentIfNeeded() {
   in_overlay_fullscreen_video_ = false;
   GraphicsLayer* content_parent = ParentForContentLayers();
@@ -327,33 +338,30 @@
     return;
 
   bool is_local_root = layout_view_.GetFrame()->IsLocalRoot();
-  LayoutVideo* video =
-      FindFullscreenVideoLayoutObject(layout_view_.GetDocument());
-  if (!video || !video->Layer()->HasCompositedLayerMapping() ||
-      !video->VideoElement()->UsesOverlayFullscreenVideo()) {
-    return;
-  }
-
-  GraphicsLayer* video_layer =
-      video->Layer()->GetCompositedLayerMapping()->MainGraphicsLayer();
-
-  // The fullscreen video has layer position equal to its enclosing frame's
-  // scroll position because fullscreen container is fixed-positioned.
-  // We should reset layer position here since we are going to reattach the
-  // layer at the very top level.
-  video_layer->SetPosition(FloatPoint());
+  GraphicsLayer* video_layer = OverlayFullscreenVideoGraphicsLayer();
+  AdjustOverlayFullscreenVideoPosition(video_layer);
 
   // Only steal fullscreen video layer and clear all other layers if we are the
   // main frame.
-  if (!is_local_root)
+  if (!is_local_root || !video_layer)
     return;
 
   content_parent->RemoveAllChildren();
   content_parent->AddChild(video_layer);
-
   in_overlay_fullscreen_video_ = true;
 }
 
+void PaintLayerCompositor::AdjustOverlayFullscreenVideoPosition(
+    GraphicsLayer* video_layer) {
+  if (!video_layer)
+    return;
+  // The fullscreen video has layer position equal to its enclosing frame's
+  // scroll position because fullscreen container is fixed-positioned.
+  // We should reset layer position here since it is attached at the
+  // very top level.
+  video_layer->SetPosition(FloatPoint());
+}
+
 void PaintLayerCompositor::UpdateWithoutAcceleratedCompositing(
     CompositingUpdateType update_type) {
   DCHECK(!HasAcceleratedCompositing());
@@ -527,8 +535,9 @@
         content_parent->SetChildren(child_list);
       }
     }
-
     ApplyOverlayFullscreenVideoAdjustmentIfNeeded();
+  } else {
+    AdjustOverlayFullscreenVideoPosition(OverlayFullscreenVideoGraphicsLayer());
   }
 
   for (unsigned i = 0; i < layers_needing_paint_invalidation.size(); i++) {
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index 60d3b44..7cf3856 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -185,6 +185,8 @@
   void EnableCompositingModeIfNeeded();
 
   void ApplyOverlayFullscreenVideoAdjustmentIfNeeded();
+  void AdjustOverlayFullscreenVideoPosition(GraphicsLayer*);
+  GraphicsLayer* OverlayFullscreenVideoGraphicsLayer();
 
   // Checks the given graphics layer against the compositor's horizontal and
   // vertical scrollbar graphics layers, returning the associated Scrollbar
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 0904224..cffde8b 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -23,6 +23,7 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
+#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/list_marker_painter.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h"
@@ -34,8 +35,10 @@
 #include "third_party/blink/renderer/core/paint/paint_phase.h"
 #include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
+#include "third_party/blink/renderer/core/paint/theme_painter.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
+#include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_types.h"
 
@@ -400,6 +403,8 @@
                   border_edges_.line_left, border_edges_.line_right);
 }
 
+// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
+// eliminate LayoutObject dependency were done yet.
 void NGBoxFragmentPainter::PaintBoxDecorationBackground(
     const PaintInfo& paint_info,
     const LayoutPoint& paint_offset) {
@@ -407,7 +412,7 @@
   const LayoutObject& layout_object = *box_fragment_.GetLayoutObject();
 
   LayoutRect paint_rect;
-  base::Optional<ScopedPaintChunkProperties> scoped_scroll_property;
+  base::Optional<ScopedBoxContentsPaintState> contents_paint_state;
   if (IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
           box_fragment_, paint_info)) {
     // For the case where we are painting the background into the scrolling
@@ -416,17 +421,8 @@
     const LayoutBox& layout_box = ToLayoutBox(layout_object);
     paint_rect = layout_box.PhysicalLayoutOverflowRect();
 
-    const auto* fragment = paint_info.FragmentToPaint(layout_box);
-    if (!fragment)
-      return;
-
-    scoped_scroll_property.emplace(
-        paint_info.context.GetPaintController(), fragment->ContentsProperties(),
-        layout_box, DisplayItem::PaintPhaseToScrollType(paint_info.phase));
-    // See comments for ScrollTranslation in object_paint_properties.h for the
-    // reason of moving by ScrollOrigin(). TODO(wangxianzhu): Encapsulate such
-    // logic at various places into one class.
-    paint_rect.MoveBy(layout_box.ScrollOrigin());
+    contents_paint_state.emplace(paint_info, paint_offset, layout_box);
+    paint_rect.MoveBy(contents_paint_state->PaintOffset());
 
     // The background painting code assumes that the borders are part of the
     // paintRect so we expand the paintRect by the border size when painting the
@@ -438,16 +434,59 @@
     // much bigger change.
     NGPhysicalSize size = box_fragment_.Size();
     paint_rect = LayoutRect(LayoutPoint(), LayoutSize(size.width, size.height));
+    paint_rect.MoveBy(paint_offset);
   }
-  paint_rect.MoveBy(paint_offset);
+
+  PaintBoxDecorationBackgroundWithRect(
+      contents_paint_state ? contents_paint_state->GetPaintInfo() : paint_info,
+      paint_rect);
+}
+
+// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
+// eliminate LayoutObject dependency were done yet.
+bool NGBoxFragmentPainter::BackgroundIsKnownToBeOpaque(
+    const PaintInfo& paint_info) {
+  const LayoutBox& layout_box = ToLayoutBox(*box_fragment_.GetLayoutObject());
+  LayoutRect bounds =
+      IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
+          box_fragment_, paint_info)
+          ? layout_box.LayoutOverflowRect()
+          : layout_box.SelfVisualOverflowRect();
+  return layout_box.BackgroundIsKnownToBeOpaqueInRect(bounds);
+}
+
+// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
+// eliminate LayoutObject dependency were done yet.
+void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
+    const PaintInfo& paint_info,
+    const LayoutRect& paint_rect) {
+  const LayoutObject& layout_object = *box_fragment_.GetLayoutObject();
+  const LayoutBox& layout_box = ToLayoutBox(layout_object);
 
   bool painting_overflow_contents =
       IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
           box_fragment_, paint_info);
   const ComputedStyle& style = box_fragment_.Style();
 
-  // TODO(layout-dev): Implement support for painting overflow contents.
-  const DisplayItemClient& display_item_client = box_fragment_;
+  base::Optional<DisplayItemCacheSkipper> cache_skipper;
+  // Disable cache in under-invalidation checking mode for MediaSliderPart
+  // because we always paint using the latest data (buffered ranges, current
+  // time and duration) which may be different from the cached data, and for
+  // delayed-invalidation object because it may change before it's actually
+  // invalidated. Note that we still report harmless under-invalidation of
+  // non-delayed-invalidation animated background, which should be ignored.
+  if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
+      (style.Appearance() == kMediaSliderPart ||
+       layout_box.ShouldDelayFullPaintInvalidation())) {
+    cache_skipper.emplace(paint_info.context);
+  }
+
+  const DisplayItemClient& display_item_client =
+      painting_overflow_contents ? static_cast<const DisplayItemClient&>(
+                                       *layout_box.Layer()
+                                            ->GetCompositedLayerMapping()
+                                            ->ScrollingContentsLayer())
+                                 : box_fragment_;
   if (DrawingRecorder::UseCachedDrawingIfPossible(
           paint_info.context, display_item_client,
           DisplayItem::kBoxDecorationBackground))
@@ -458,6 +497,12 @@
   BoxDecorationData box_decoration_data(PhysicalFragment());
   GraphicsContextStateSaver state_saver(paint_info.context, false);
 
+  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+      LayoutRect(EnclosingIntRect(paint_rect)) == paint_rect &&
+      BackgroundIsKnownToBeOpaque(paint_info))
+    recorder.SetKnownToBeOpaque();
+
+  bool needs_end_layer = false;
   if (!painting_overflow_contents) {
     PaintNormalBoxShadow(paint_info, paint_rect, style, border_edges_.line_left,
                          border_edges_.line_right);
@@ -468,24 +513,31 @@
           paint_rect, border_edges_.line_left, border_edges_.line_right);
       paint_info.context.ClipRoundedRect(border);
 
-      if (box_decoration_data.bleed_avoidance == kBackgroundBleedClipLayer)
+      if (box_decoration_data.bleed_avoidance == kBackgroundBleedClipLayer) {
         paint_info.context.BeginLayer();
+        needs_end_layer = true;
+      }
     }
   }
 
-  // TODO(layout-dev): Support theme painting.
-  bool theme_painted = false;
-
+  IntRect snapped_paint_rect(PixelSnappedIntRect(paint_rect));
+  ThemePainter& theme_painter = LayoutTheme::GetTheme().Painter();
+  bool theme_painted =
+      box_decoration_data.has_appearance &&
+      !theme_painter.Paint(layout_box, paint_info, snapped_paint_rect);
   bool should_paint_background =
-      !theme_painted &&
-      (!paint_info.SkipRootBackground() ||
-       paint_info.PaintContainer() != layout_object) &&
-      (!layout_object.IsBoxModelObject() ||
-       !ToLayoutBoxModelObject(layout_object).BackgroundStolenForBeingBody());
+      !theme_painted && (!paint_info.SkipRootBackground() ||
+                         paint_info.PaintContainer() != layout_box);
   if (should_paint_background) {
     PaintBackground(paint_info, paint_rect,
                     box_decoration_data.background_color,
                     box_decoration_data.bleed_avoidance);
+
+    if (box_decoration_data.has_appearance) {
+      theme_painter.PaintDecorations(layout_box.GetNode(),
+                                     layout_box.GetDocument(), style,
+                                     paint_info, snapped_paint_rect);
+    }
   }
 
   if (!painting_overflow_contents) {
@@ -493,7 +545,13 @@
                                       border_edges_.line_left,
                                       border_edges_.line_right);
 
+    // The theme will tell us whether or not we should also paint the CSS
+    // border.
     if (box_decoration_data.has_border_decoration &&
+        (!box_decoration_data.has_appearance ||
+         (!theme_painted &&
+          LayoutTheme::GetTheme().Painter().PaintBorderOnly(
+              layout_box.GetNode(), style, paint_info, snapped_paint_rect))) &&
         ShouldPaintBoxFragmentBorders(layout_object)) {
       Node* generating_node = layout_object.GeneratingNode();
       const Document& document = layout_object.GetDocument();
@@ -503,10 +561,33 @@
     }
   }
 
-  if (box_decoration_data.bleed_avoidance == kBackgroundBleedClipLayer)
+  if (needs_end_layer)
     paint_info.context.EndLayer();
 }
 
+// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
+// eliminate LayoutObject dependency were done yet.
+void NGBoxFragmentPainter::PaintBackground(
+    const PaintInfo& paint_info,
+    const LayoutRect& paint_rect,
+    const Color& background_color,
+    BackgroundBleedAvoidance bleed_avoidance) {
+  const LayoutObject& layout_object = *box_fragment_.GetLayoutObject();
+  const LayoutBox& layout_box = ToLayoutBox(layout_object);
+  if (layout_box.IsDocumentElement())
+    return;
+  if (layout_box.BackgroundStolenForBeingBody())
+    return;
+  if (layout_box.BackgroundIsKnownToBeObscured())
+    return;
+  // TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry.
+  BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>(
+      box_fragment_.GetLayoutObject()));
+  PaintFillLayers(paint_info, background_color,
+                  box_fragment_.Style().BackgroundLayers(), paint_rect,
+                  geometry, bleed_avoidance);
+}
+
 void NGBoxFragmentPainter::PaintInlineChildBoxUsingLegacyFallback(
     const NGPhysicalFragment& fragment,
     const PaintInfo& paint_info) {
@@ -828,19 +909,6 @@
       border_edges_.line_left, border_edges_.line_right);
 }
 
-void NGBoxFragmentPainter::PaintBackground(
-    const PaintInfo& paint_info,
-    const LayoutRect& paint_rect,
-    const Color& background_color,
-    BackgroundBleedAvoidance bleed_avoidance) {
-  // TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry.
-  BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>(
-      box_fragment_.GetLayoutObject()));
-  PaintFillLayers(paint_info, background_color,
-                  box_fragment_.Style().BackgroundLayers(), paint_rect,
-                  geometry, bleed_avoidance);
-}
-
 bool NGBoxFragmentPainter::IsInSelfHitTestingPhase(HitTestAction action) const {
   // TODO(layout-dev): We should set an IsContainingBlock flag on
   // NGPhysicalBoxFragment, instead of routing back to LayoutObject.
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 1da13d7..f41c5b1e8 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -71,6 +71,10 @@
 
   void PaintBoxDecorationBackground(const PaintInfo&,
                                     const LayoutPoint& paint_offset);
+  void PaintBoxDecorationBackgroundWithRect(const PaintInfo&,
+                                            const LayoutRect&);
+  bool BackgroundIsKnownToBeOpaque(const PaintInfo&);
+
   void PaintAllPhasesAtomically(const PaintInfo&,
                                 bool is_self_painting);
   void PaintBlockChildren(const PaintInfo&);
diff --git a/third_party/blink/renderer/core/paint/text_painter_base.cc b/third_party/blink/renderer/core/paint/text_painter_base.cc
index 80a5e07..f75868f 100644
--- a/third_party/blink/renderer/core/paint/text_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/text_painter_base.cc
@@ -288,17 +288,23 @@
   // vertical text.
   switch (baseline_type) {
     case kAlphabeticBaseline:
-      if (style.TextUnderlinePosition() == kTextUnderlinePositionAuto) {
+      if (!(style.TextUnderlinePosition() & kTextUnderlinePositionUnder)) {
         return ResolvedUnderlinePosition::kRoman;
       }
-      // TODO(https://crbug.com/313888) Support left, right.
       return ResolvedUnderlinePosition::kUnder;
     case kIdeographicBaseline:
       // Compute language-appropriate default underline position.
       // https://drafts.csswg.org/css-text-decor-3/#default-stylesheet
       UScriptCode script = style.GetFontDescription().GetScript();
-      if (script == USCRIPT_KATAKANA_OR_HIRAGANA || script == USCRIPT_HANGUL)
+      if (script == USCRIPT_KATAKANA_OR_HIRAGANA || script == USCRIPT_HANGUL) {
+        if (style.TextUnderlinePosition() & kTextUnderlinePositionLeft) {
+          return ResolvedUnderlinePosition::kUnder;
+        }
         return ResolvedUnderlinePosition::kOver;
+      }
+      if (style.TextUnderlinePosition() & kTextUnderlinePositionRight) {
+        return ResolvedUnderlinePosition::kOver;
+      }
       return ResolvedUnderlinePosition::kUnder;
   }
   NOTREACHED();
diff --git a/third_party/blink/renderer/core/script/classic_pending_script.cc b/third_party/blink/renderer/core/script/classic_pending_script.cc
index 4465f13..f2ae40283 100644
--- a/third_party/blink/renderer/core/script/classic_pending_script.cc
+++ b/third_party/blink/renderer/core/script/classic_pending_script.cc
@@ -540,9 +540,8 @@
   DCHECK(!streamer_);
   DCHECK(!IsCurrentlyStreaming());
   DCHECK(!streamer_done_);
-  ScriptStreamer::StartStreaming(
-      this, document->GetFrame()->GetSettings(), script_state,
-      document->GetTaskRunner(task_type), &not_streamed_reason_);
+  ScriptStreamer::StartStreaming(this, document->GetTaskRunner(task_type),
+                                 &not_streamed_reason_);
   DCHECK(streamer_ || not_streamed_reason_ != ScriptStreamer::kInvalid);
   bool success = streamer_ && !streamer_->IsStreamingFinished();
 
diff --git a/third_party/blink/renderer/core/script/script.h b/third_party/blink/renderer/core/script/script.h
index a807959..3bb1ed0 100644
--- a/third_party/blink/renderer/core/script/script.h
+++ b/third_party/blink/renderer/core/script/script.h
@@ -16,8 +16,6 @@
 class LocalFrame;
 class SecurityOrigin;
 
-// TODO(asamidoi, nhiroki): Remove this enum in favor of
-// blink::mojom::ScriptType.
 enum class ScriptType { kClassic, kModule };
 
 // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index ccedf5b..e1e0de0 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -932,7 +932,10 @@
       HasBlendMode() || HasIsolation() || HasViewportConstrainedPosition() ||
       GetPosition() == EPosition::kSticky ||
       HasPropertyThatCreatesStackingContext(WillChangeProperties()) ||
-      ContainsPaint() || ContainsLayout()) {
+      /* TODO(882625): This becomes unnecessary when will-change correctly takes
+      into account active animations. */
+      ShouldCompositeForCurrentAnimations() || ContainsPaint() ||
+      ContainsLayout()) {
     SetIsStackingContext(true);
   }
 }
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index c6457b7..da710790 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -3356,17 +3356,19 @@
 
 DOMRectList* Internals::focusRingRects(Element* element) {
   Vector<LayoutRect> rects;
-  if (element && element->GetLayoutObject())
+  if (element && element->GetLayoutObject()) {
     element->GetLayoutObject()->AddOutlineRects(
-        rects, LayoutPoint(), LayoutObject::kIncludeBlockVisualOverflow);
+        rects, LayoutPoint(), NGOutlineType::kIncludeBlockVisualOverflow);
+  }
   return DOMRectList::Create(rects);
 }
 
 DOMRectList* Internals::outlineRects(Element* element) {
   Vector<LayoutRect> rects;
-  if (element && element->GetLayoutObject())
+  if (element && element->GetLayoutObject()) {
     element->GetLayoutObject()->AddOutlineRects(
-        rects, LayoutPoint(), LayoutObject::kDontIncludeBlockVisualOverflow);
+        rects, LayoutPoint(), NGOutlineType::kDontIncludeBlockVisualOverflow);
+  }
   return DOMRectList::Create(rects);
 }
 
diff --git a/third_party/blink/renderer/core/timing/memory_info.idl b/third_party/blink/renderer/core/timing/memory_info.idl
index 2af4ab2..dbbf246 100644
--- a/third_party/blink/renderer/core/timing/memory_info.idl
+++ b/third_party/blink/renderer/core/timing/memory_info.idl
@@ -34,7 +34,7 @@
 [
     NoInterfaceObject
 ] interface MemoryInfo {
-    [Measure] readonly attribute unsigned long totalJSHeapSize;
-    [Measure] readonly attribute unsigned long usedJSHeapSize;
-    [Measure] readonly attribute unsigned long jsHeapSizeLimit;
+    [Measure] readonly attribute unsigned long long totalJSHeapSize;
+    [Measure] readonly attribute unsigned long long usedJSHeapSize;
+    [Measure] readonly attribute unsigned long long jsHeapSizeLimit;
 };
diff --git a/third_party/blink/renderer/core/workers/global_scope_creation_params.cc b/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
index d49696c4..ea64dec 100644
--- a/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
+++ b/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
@@ -11,7 +11,6 @@
 
 GlobalScopeCreationParams::GlobalScopeCreationParams(
     const KURL& script_url,
-    // TODO(asamidoi): Replace ScriptType to mojom::ScriptType
     ScriptType script_type,
     const String& user_agent,
     const Vector<CSPHeaderAndType>& content_security_policy_parsed_headers,
diff --git a/third_party/blink/renderer/core/workers/global_scope_creation_params.h b/third_party/blink/renderer/core/workers/global_scope_creation_params.h
index dc8b5a1..f96f537e 100644
--- a/third_party/blink/renderer/core/workers/global_scope_creation_params.h
+++ b/third_party/blink/renderer/core/workers/global_scope_creation_params.h
@@ -39,7 +39,6 @@
  public:
   GlobalScopeCreationParams(
       const KURL& script_url,
-      // TODO(asamidoi): Replace ScriptType to mojom::ScriptType
       ScriptType script_type,
       const String& user_agent,
       const Vector<CSPHeaderAndType>& content_security_policy_parsed_headers,
diff --git a/third_party/blink/renderer/core/workers/worker_module_tree_client.h b/third_party/blink/renderer/core/workers/worker_module_tree_client.h
index f8fb0894..caec3ce 100644
--- a/third_party/blink/renderer/core/workers/worker_module_tree_client.h
+++ b/third_party/blink/renderer/core/workers/worker_module_tree_client.h
@@ -5,7 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_MODULE_TREE_CLIENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_MODULE_TREE_CLIENT_H_
 
-#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 
@@ -14,7 +13,7 @@
 class ModuleScript;
 
 // A ModuleTreeClient that lives on the worker context's thread.
-class CORE_EXPORT WorkerModuleTreeClient final : public ModuleTreeClient {
+class WorkerModuleTreeClient final : public ModuleTreeClient {
  public:
   explicit WorkerModuleTreeClient(Modulator*);
 
diff --git a/third_party/blink/renderer/modules/accessibility/DEPS b/third_party/blink/renderer/modules/accessibility/DEPS
index ec3df5f..24c1870 100644
--- a/third_party/blink/renderer/modules/accessibility/DEPS
+++ b/third_party/blink/renderer/modules/accessibility/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
     "+mojo/public/cpp/bindings/binding.h",
+    "+ui/accessibility/ax_enums.mojom-shared.h",
     "-third_party/blink/renderer/modules",
     "+third_party/blink/renderer/modules/accessibility",
     "+third_party/blink/renderer/modules/media_controls",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index 8a0ab77..77e19ee 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -396,13 +396,28 @@
   if (IsDetached())
     return false;
 
-  if (GetLayoutObject()->IsTextControl())
-    return true;
-
   const Node* node = GetNodeOrContainingBlockNode();
   if (!node)
     return false;
 
+  // TODO(accessibility) pursue standards track so that aria-goog-editable
+  // becomes aria-editable. At that time, create ariaEditableAttr in
+  // html_element.cc. The current version of the editable attribute does not
+  // inherit, in order to match the automatic Gecko implementation, but
+  // hopefully the standardized version will, in which case a more performant
+  // implementation will be required, e.g. cache it or only expose on ancestor,
+  // having browser-side propagate it.
+  const Element* elem = node->IsElementNode()
+                            ? ToElement(node)
+                            : FlatTreeTraversal::ParentElement(*node);
+  if (elem && elem->hasAttribute("aria-goog-editable")) {
+    auto editable = elem->getAttribute("aria-goog-editable");
+    return !EqualIgnoringASCIICase("false", editable);
+  }
+
+  if (GetLayoutObject()->IsTextControl())
+    return true;
+
   if (HasEditableStyle(*node))
     return true;
 
@@ -430,6 +445,21 @@
   if (!node)
     return false;
 
+  // TODO(accessibility) pursue standards track so that aria-goog-editable
+  // becomes aria-editable. At that time, create ariaEditableAttr in
+  // html_element.cc. The current version of the editable attribute does not
+  // inherit, in order to match the automatic Gecko implementation, but
+  // hopefully the standardized version will, in which case a more performant
+  // implementation will be required, e.g. cache it or only expose on ancestor,
+  // having browser-side propagate it.
+  const Element* elem = node->IsElementNode()
+                            ? ToElement(node)
+                            : FlatTreeTraversal::ParentElement(*node);
+  if (elem && elem->hasAttribute("aria-goog-editable")) {
+    auto editable = elem->getAttribute("aria-goog-editable");
+    return !EqualIgnoringASCIICase("false", editable);
+  }
+
   if (HasRichlyEditableStyle(*node))
     return true;
 
@@ -2424,7 +2454,7 @@
       AXObjectCache().HandleAriaSelectedChanged(active_descendant->GetNode());
     }
     AXObjectCache().PostNotification(
-        GetLayoutObject(), AXObjectCacheImpl::kAXActiveDescendantChanged);
+        GetLayoutObject(), ax::mojom::Event::kActiveDescendantChanged);
   }
 }
 
@@ -2453,9 +2483,10 @@
   }
 
   // Post that the row count changed.
-  if (container_parent)
+  if (container_parent) {
     AXObjectCache().PostNotification(container_parent,
-                                     AXObjectCacheImpl::kAXRowCountChanged);
+                                     ax::mojom::Event::kRowCountChanged);
+  }
 
   // Post that the specific row either collapsed or expanded.
   AccessibilityExpanded expanded = IsExpanded();
@@ -2463,15 +2494,13 @@
     return;
 
   if (RoleValue() == kRowRole || RoleValue() == kTreeItemRole) {
-    AXObjectCacheImpl::AXNotification notification =
-        AXObjectCacheImpl::kAXRowExpanded;
+    ax::mojom::Event notification = ax::mojom::Event::kRowExpanded;
     if (expanded == kExpandedCollapsed)
-      notification = AXObjectCacheImpl::kAXRowCollapsed;
+      notification = ax::mojom::Event::kRowCollapsed;
 
     AXObjectCache().PostNotification(this, notification);
   } else {
-    AXObjectCache().PostNotification(this,
-                                     AXObjectCacheImpl::kAXExpandedChanged);
+    AXObjectCache().PostNotification(this, ax::mojom::Event::kExpandedChanged);
   }
 }
 
@@ -2481,7 +2510,7 @@
     // Reusing the value change event in order to invalidate, even though the
     // value did not necessarily change.
     // TODO(dmazzoni) change to using a MarkDirty() API.
-    AXObjectCache().PostNotification(this, AXObjectCacheImpl::kAXValueChanged);
+    AXObjectCache().PostNotification(this, ax::mojom::Event::kValueChanged);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_list_box.cc b/third_party/blink/renderer/modules/accessibility/ax_list_box.cc
index c34efaf..3eaabde5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_list_box.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_list_box.cc
@@ -84,8 +84,8 @@
   if (!select->IsFocused())
     return;
 
-  AXObjectCache().PostNotification(
-      this, AXObjectCacheImpl::kAXActiveDescendantChanged);
+  AXObjectCache().PostNotification(this,
+                                   ax::mojom::Event::kActiveDescendantChanged);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
index 85ee9f64..9f093fe 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
@@ -127,7 +127,7 @@
   }
 
   AXObjectCache().PostNotification(this,
-                                   AXObjectCacheImpl::kAXMenuListValueChanged);
+                                   ax::mojom::Event::kMenuListValueChanged);
 }
 
 void AXMenuList::DidShowPopup() {
@@ -146,8 +146,7 @@
   popup->DidHide();
 
   if (GetNode() && GetNode()->IsFocused())
-    AXObjectCache().PostNotification(
-        this, AXObjectCacheImpl::kAXFocusedUIElementChanged);
+    AXObjectCache().PostNotification(this, ax::mojom::Event::kFocus);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
index 1c4521b..a1bf9c8 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
@@ -135,25 +135,24 @@
       old_index < static_cast<int>(children_.size())) {
     AXObject* previous_child = children_[old_index].Get();
     cache.PostNotification(previous_child,
-                           AXObjectCacheImpl::kAXMenuListItemUnselected);
+                           ax::mojom::Event::kMenuListItemSelected);
   }
 
   if (option_index >= 0 && option_index < static_cast<int>(children_.size())) {
     AXObject* child = children_[option_index].Get();
-    cache.PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged);
-    cache.PostNotification(this, AXObjectCacheImpl::kAXActiveDescendantChanged);
-    cache.PostNotification(child, AXObjectCacheImpl::kAXMenuListItemSelected);
+    cache.PostNotification(this, ax::mojom::Event::kChildrenChanged);
+    cache.PostNotification(this, ax::mojom::Event::kActiveDescendantChanged);
+    cache.PostNotification(child, ax::mojom::Event::kMenuListItemSelected);
   }
 }
 
 void AXMenuListPopup::DidHide() {
   AXObjectCacheImpl& cache = AXObjectCache();
   AXObject* descendant = ActiveDescendant();
-  cache.PostNotification(this, AXObjectCacheImpl::kAXHide);
+  cache.PostNotification(this, ax::mojom::Event::kHide);
   if (descendant) {
-    cache.PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged);
-    cache.PostNotification(descendant,
-                           AXObjectCacheImpl::kAXMenuListItemUnselected);
+    cache.PostNotification(this, ax::mojom::Event::kChildrenChanged);
+    cache.PostNotification(descendant, ax::mojom::Event::kMenuListItemSelected);
   }
 }
 
@@ -162,14 +161,13 @@
     AddChildren();
 
   AXObjectCacheImpl& cache = AXObjectCache();
-  cache.PostNotification(this, AXObjectCacheImpl::kAXShow);
+  cache.PostNotification(this, ax::mojom::Event::kShow);
   int selected_index = GetSelectedIndex();
   if (selected_index >= 0 &&
       selected_index < static_cast<int>(children_.size())) {
     DidUpdateActiveOption(selected_index);
   } else {
-    cache.PostNotification(parent_,
-                           AXObjectCacheImpl::kAXFocusedUIElementChanged);
+    cache.PostNotification(parent_, ax::mojom::Event::kFocus);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index af6aebc..03d94f36 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -113,8 +113,7 @@
   value += increase ? step : -step;
 
   OnNativeSetValueAction(String::Number(value));
-  AXObjectCache().PostNotification(GetNode(),
-                                   AXObjectCacheImpl::kAXValueChanged);
+  AXObjectCache().PostNotification(GetNode(), ax::mojom::Event::kValueChanged);
 }
 
 AXObject* AXNodeObject::ActiveDescendant() {
@@ -2408,7 +2407,7 @@
   if (IsDetached())
     return;
 
-  AXObjectCache().PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged);
+  AXObjectCache().PostNotification(this, ax::mojom::Event::kChildrenChanged);
 
   // Go up the accessibility parent chain, but only if the element already
   // exists. This method is called during layout, minimal work should be done.
@@ -2424,16 +2423,16 @@
 
     // If this element supports ARIA live regions, then notify the AT of
     // changes.
-    if (parent->IsLiveRegion())
+    if (parent->IsLiveRegion()) {
       AXObjectCache().PostNotification(parent,
-                                       AXObjectCacheImpl::kAXLiveRegionChanged);
+                                       ax::mojom::Event::kLiveRegionChanged);
+    }
 
     // If this element is an ARIA text box or content editable, post a "value
     // changed" notification on it so that it behaves just like a native input
     // element or textarea.
     if (IsNonNativeTextControl())
-      AXObjectCache().PostNotification(parent,
-                                       AXObjectCacheImpl::kAXValueChanged);
+      AXObjectCache().PostNotification(parent, ax::mojom::Event::kValueChanged);
   }
 }
 
@@ -2450,11 +2449,11 @@
   // or the web area if the selection is just in the document somewhere.
   if (IsFocused() || IsWebArea()) {
     AXObjectCache().PostNotification(this,
-                                     AXObjectCacheImpl::kAXSelectedTextChanged);
+                                     ax::mojom::Event::kTextSelectionChanged);
     if (GetDocument()) {
       AXObject* document_object = AXObjectCache().GetOrCreate(GetDocument());
       AXObjectCache().PostNotification(
-          document_object, AXObjectCacheImpl::kAXDocumentSelectionChanged);
+          document_object, ax::mojom::Event::kDocumentSelectionChanged);
     }
   } else {
     AXObject::SelectionChanged();  // Calls selectionChanged on parent.
@@ -2472,14 +2471,13 @@
       continue;
 
     if (parent->IsLiveRegion())
-      cache.PostNotification(parent_node,
-                             AXObjectCacheImpl::kAXLiveRegionChanged);
+      cache.PostNotification(parent_node, ax::mojom::Event::kLiveRegionChanged);
 
     // If this element is an ARIA text box or content editable, post a "value
     // changed" notification on it so that it behaves just like a native input
     // element or textarea.
     if (parent->IsNonNativeTextControl())
-      cache.PostNotification(parent_node, AXObjectCacheImpl::kAXValueChanged);
+      cache.PostNotification(parent_node, ax::mojom::Event::kValueChanged);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 9e9ef98..74ddf2a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -2926,7 +2926,7 @@
                               kProgrammaticScroll, false, kScrollBehaviorAuto));
   AXObjectCache().PostNotification(
       AXObjectCache().GetOrCreate(GetDocument()->GetLayoutView()),
-      AXObjectCacheImpl::kAXLocationChanged);
+      ax::mojom::Event::kLocationChanged);
   return true;
 }
 
@@ -2952,7 +2952,7 @@
                               kProgrammaticScroll, false, kScrollBehaviorAuto));
   AXObjectCache().PostNotification(
       AXObjectCache().GetOrCreate(GetDocument()->GetLayoutView()),
-      AXObjectCacheImpl::kAXLocationChanged);
+      ax::mojom::Event::kLocationChanged);
   return true;
 }
 
@@ -2971,7 +2971,7 @@
                               kProgrammaticScroll, false, kScrollBehaviorAuto));
   AXObjectCache().PostNotification(
       AXObjectCache().GetOrCreate(GetDocument()->GetLayoutView()),
-      AXObjectCacheImpl::kAXLocationChanged);
+      ax::mojom::Event::kLocationChanged);
   return true;
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 009e2d0..de3bad5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -677,11 +677,11 @@
   if (node_for_relation_update)
     relation_cache_->UpdateRelatedTree(node_for_relation_update);
 
-  PostNotification(obj, AXObjectCacheImpl::kAXTextChanged);
+  PostNotification(obj, ax::mojom::Event::kTextChanged);
 }
 
 void AXObjectCacheImpl::DocumentTitleChanged() {
-  PostNotification(Root(), AXObjectCacheImpl::kAXDocumentTitleChanged);
+  PostNotification(Root(), ax::mojom::Event::kDocumentTitleChanged);
 }
 
 void AXObjectCacheImpl::UpdateCacheAfterNodeIsAttached(Node* node) {
@@ -757,10 +757,11 @@
     }
 #endif
 
-    AXNotification notification = notifications_to_post_[i].second;
+    ax::mojom::Event notification = notifications_to_post_[i].second;
     PostPlatformNotification(obj, notification);
 
-    if (notification == kAXChildrenChanged && obj->ParentObjectIfExists() &&
+    if (notification == ax::mojom::Event::kChildrenChanged &&
+        obj->ParentObjectIfExists() &&
         obj->LastKnownIsIgnoredValue() != obj->AccessibilityIsIgnored())
       ChildrenChanged(obj->ParentObject());
   }
@@ -769,21 +770,21 @@
 }
 
 void AXObjectCacheImpl::PostNotification(LayoutObject* layout_object,
-                                         AXNotification notification) {
+                                         ax::mojom::Event notification) {
   if (!layout_object)
     return;
   PostNotification(Get(layout_object), notification);
 }
 
 void AXObjectCacheImpl::PostNotification(Node* node,
-                                         AXNotification notification) {
+                                         ax::mojom::Event notification) {
   if (!node)
     return;
   PostNotification(Get(node), notification);
 }
 
 void AXObjectCacheImpl::PostNotification(AXObject* object,
-                                         AXNotification notification) {
+                                         ax::mojom::Event notification) {
   if (!object)
     return;
 
@@ -809,16 +810,16 @@
 }
 
 void AXObjectCacheImpl::CheckedStateChanged(Node* node) {
-  PostNotification(node, AXObjectCacheImpl::kAXCheckedStateChanged);
+  PostNotification(node, ax::mojom::Event::kCheckedStateChanged);
 }
 
 void AXObjectCacheImpl::ListboxOptionStateChanged(HTMLOptionElement* option) {
-  PostNotification(option, kAXCheckedStateChanged);
+  PostNotification(option, ax::mojom::Event::kCheckedStateChanged);
 }
 
 void AXObjectCacheImpl::ListboxSelectedChildrenChanged(
     HTMLSelectElement* select) {
-  PostNotification(select, kAXSelectedChildrenChanged);
+  PostNotification(select, ax::mojom::Event::kSelectedChildrenChanged);
 }
 
 void AXObjectCacheImpl::ListboxActiveIndexChanged(HTMLSelectElement* select) {
@@ -830,7 +831,7 @@
 }
 
 void AXObjectCacheImpl::LocationChanged(LayoutObject* layout_object) {
-  PostNotification(layout_object, kAXLocationChanged);
+  PostNotification(layout_object, ax::mojom::Event::kLocationChanged);
 }
 
 void AXObjectCacheImpl::RadiobuttonRemovedFromGroup(
@@ -848,7 +849,7 @@
     return;
 
   ToAXRadioInput(first_obj)->UpdatePosAndSetSize(1);
-  PostNotification(first_obj, kAXAriaAttributeChanged);
+  PostNotification(first_obj, ax::mojom::Event::kAriaAttributeChanged);
   ToAXRadioInput(first_obj)->RequestUpdateToNextNode(true);
 }
 
@@ -862,12 +863,12 @@
   // end of a layout, and it allows an AX notification to be sent when a page
   // has its first layout, rather than when the document first loads.
   if (AXObject* obj = GetOrCreate(layout_object))
-    PostNotification(obj, kAXLayoutComplete);
+    PostNotification(obj, ax::mojom::Event::kLayoutComplete);
 }
 
 void AXObjectCacheImpl::HandleClicked(Node* node) {
   if (AXObject* obj = GetOrCreate(node))
-    PostNotification(obj, kAXClicked);
+    PostNotification(obj, ax::mojom::Event::kClicked);
 }
 
 void AXObjectCacheImpl::HandleAttributeChanged(
@@ -875,7 +876,7 @@
     AccessibleNode* accessible_node) {
   modification_count_++;
   if (AXObject* obj = Get(accessible_node))
-    PostNotification(obj, kAXAriaAttributeChanged);
+    PostNotification(obj, ax::mojom::Event::kAriaAttributeChanged);
 }
 
 void AXObjectCacheImpl::HandleAriaExpandedChange(Node* node) {
@@ -888,11 +889,11 @@
   if (!obj)
     return;
 
-  PostNotification(obj, kAXCheckedStateChanged);
+  PostNotification(obj, ax::mojom::Event::kCheckedStateChanged);
 
   AXObject* listbox = obj->ParentObjectUnignored();
   if (listbox && listbox->RoleValue() == kListBoxRole)
-    PostNotification(listbox, kAXSelectedChildrenChanged);
+    PostNotification(listbox, ax::mojom::Event::kSelectedChildrenChanged);
 }
 
 // This might be the new target of a relation. Handle all possible cases.
@@ -978,7 +979,7 @@
   if (attr_name == aria_activedescendantAttr)
     HandleActiveDescendantChanged(element);
   else if (attr_name == aria_valuenowAttr || attr_name == aria_valuetextAttr)
-    PostNotification(element, AXObjectCacheImpl::kAXValueChanged);
+    PostNotification(element, ax::mojom::Event::kValueChanged);
   else if (attr_name == aria_labelAttr || attr_name == aria_labeledbyAttr ||
            attr_name == aria_labelledbyAttr)
     TextChanged(element);
@@ -993,11 +994,11 @@
   else if (attr_name == aria_hiddenAttr)
     ChildrenChanged(element->parentNode());
   else if (attr_name == aria_invalidAttr)
-    PostNotification(element, AXObjectCacheImpl::kAXInvalidStatusChanged);
+    PostNotification(element, ax::mojom::Event::kInvalidStatusChanged);
   else if (attr_name == aria_ownsAttr)
     ChildrenChanged(element);
   else
-    PostNotification(element, AXObjectCacheImpl::kAXAriaAttributeChanged);
+    PostNotification(element, ax::mojom::Event::kAriaAttributeChanged);
 }
 
 void AXObjectCacheImpl::HandleAutofillStateChanged(Element* elem,
@@ -1023,7 +1024,7 @@
   if (AXObject* obj = Get(layout_object)) {
     if (!obj->NeedsToUpdateChildren()) {
       obj->SetNeedsToUpdateChildren();
-      PostNotification(layout_object, kAXChildrenChanged);
+      PostNotification(layout_object, ax::mojom::Event::kChildrenChanged);
     }
   }
 }
@@ -1093,8 +1094,9 @@
   return !is_null && !hidden;
 }
 
-void AXObjectCacheImpl::PostPlatformNotification(AXObject* obj,
-                                                 AXNotification notification) {
+void AXObjectCacheImpl::PostPlatformNotification(
+    AXObject* obj,
+    ax::mojom::Event notification) {
   if (!obj || !obj->GetDocument() || !obj->DocumentFrameView() ||
       !obj->DocumentFrameView()->GetFrame().GetPage())
     return;
@@ -1102,8 +1104,7 @@
   WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame(
       obj->GetDocument()->AXObjectCacheOwner().GetFrame());
   if (webframe && webframe->Client()) {
-    webframe->Client()->PostAccessibilityEvent(
-        WebAXObject(obj), static_cast<WebAXEvent>(notification));
+    webframe->Client()->PostAccessibilityEvent(WebAXObject(obj), notification);
   }
 }
 
@@ -1122,12 +1123,12 @@
 
   AXObject* old_focused_object = Get(old_focused_node);
 
-  PostPlatformNotification(old_focused_object, kAXBlur);
-  PostPlatformNotification(focused_object, kAXFocusedUIElementChanged);
+  PostPlatformNotification(old_focused_object, ax::mojom::Event::kBlur);
+  PostPlatformNotification(focused_object, ax::mojom::Event::kFocus);
 }
 
 void AXObjectCacheImpl::HandleInitialFocus() {
-  PostNotification(document_, kAXFocusedUIElementChanged);
+  PostNotification(document_, ax::mojom::Event::kFocus);
 }
 
 void AXObjectCacheImpl::HandleEditableTextContentChanged(Node* node) {
@@ -1145,13 +1146,13 @@
 
   while (obj && !obj->IsNativeTextControl() && !obj->IsNonNativeTextControl())
     obj = obj->ParentObject();
-  PostNotification(obj, kAXValueChanged);
+  PostNotification(obj, ax::mojom::Event::kValueChanged);
 }
 
 void AXObjectCacheImpl::HandleScaleAndLocationChanged(Document* document) {
   if (!document)
     return;
-  PostNotification(document, kAXLocationChanged);
+  PostNotification(document, ax::mojom::Event::kLocationChanged);
 }
 
 void AXObjectCacheImpl::HandleTextFormControlChanged(Node* node) {
@@ -1170,7 +1171,7 @@
 }
 
 void AXObjectCacheImpl::HandleValueChanged(Node* node) {
-  PostNotification(node, kAXValueChanged);
+  PostNotification(node, ax::mojom::Event::kValueChanged);
 }
 
 void AXObjectCacheImpl::HandleUpdateActiveMenuOption(LayoutMenuList* menu_list,
@@ -1199,12 +1200,12 @@
 }
 
 void AXObjectCacheImpl::HandleLoadComplete(Document* document) {
-  PostNotification(GetOrCreate(document), kAXLoadComplete);
+  PostNotification(GetOrCreate(document), ax::mojom::Event::kLoadComplete);
   AddPermissionStatusListener();
 }
 
 void AXObjectCacheImpl::HandleLayoutComplete(Document* document) {
-  PostNotification(GetOrCreate(document), kAXLayoutComplete);
+  PostNotification(GetOrCreate(document), ax::mojom::Event::kLayoutComplete);
 }
 
 void AXObjectCacheImpl::HandleScrolledToAnchor(const Node* anchor_node) {
@@ -1215,20 +1216,21 @@
     return;
   if (obj->AccessibilityIsIgnored())
     obj = obj->ParentObjectUnignored();
-  PostPlatformNotification(obj, kAXScrolledToAnchor);
+  PostPlatformNotification(obj, ax::mojom::Event::kScrolledToAnchor);
 }
 
 void AXObjectCacheImpl::HandleScrollPositionChanged(
     LocalFrameView* frame_view) {
   AXObject* target_ax_object =
       GetOrCreate(frame_view->GetFrame().GetDocument());
-  PostPlatformNotification(target_ax_object, kAXScrollPositionChanged);
+  PostPlatformNotification(target_ax_object,
+                           ax::mojom::Event::kScrollPositionChanged);
 }
 
 void AXObjectCacheImpl::HandleScrollPositionChanged(
     LayoutObject* layout_object) {
   PostPlatformNotification(GetOrCreate(layout_object),
-                           kAXScrollPositionChanged);
+                           ax::mojom::Event::kScrollPositionChanged);
 }
 
 const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* node) {
@@ -1256,7 +1258,7 @@
         hit->GetLayoutObject()->IsLayoutEmbeddedContent())
       return;
 
-    PostPlatformNotification(hit, kAXHover);
+    PostPlatformNotification(hit, ax::mojom::Event::kHover);
   }
 }
 
@@ -1344,57 +1346,4 @@
   AXObjectCache::Trace(visitor);
 }
 
-STATIC_ASSERT_ENUM(kWebAXEventActiveDescendantChanged,
-                   AXObjectCacheImpl::kAXActiveDescendantChanged);
-STATIC_ASSERT_ENUM(kWebAXEventAriaAttributeChanged,
-                   AXObjectCacheImpl::kAXAriaAttributeChanged);
-STATIC_ASSERT_ENUM(kWebAXEventAutocorrectionOccured,
-                   AXObjectCacheImpl::kAXAutocorrectionOccured);
-STATIC_ASSERT_ENUM(kWebAXEventBlur, AXObjectCacheImpl::kAXBlur);
-STATIC_ASSERT_ENUM(kWebAXEventCheckedStateChanged,
-                   AXObjectCacheImpl::kAXCheckedStateChanged);
-STATIC_ASSERT_ENUM(kWebAXEventChildrenChanged,
-                   AXObjectCacheImpl::kAXChildrenChanged);
-STATIC_ASSERT_ENUM(kWebAXEventClicked, AXObjectCacheImpl::kAXClicked);
-STATIC_ASSERT_ENUM(kWebAXEventDocumentSelectionChanged,
-                   AXObjectCacheImpl::kAXDocumentSelectionChanged);
-STATIC_ASSERT_ENUM(kWebAXEventDocumentTitleChanged,
-                   AXObjectCacheImpl::kAXDocumentTitleChanged);
-STATIC_ASSERT_ENUM(kWebAXEventExpandedChanged,
-                   AXObjectCacheImpl::kAXExpandedChanged);
-STATIC_ASSERT_ENUM(kWebAXEventFocus,
-                   AXObjectCacheImpl::kAXFocusedUIElementChanged);
-STATIC_ASSERT_ENUM(kWebAXEventHide, AXObjectCacheImpl::kAXHide);
-STATIC_ASSERT_ENUM(kWebAXEventHover, AXObjectCacheImpl::kAXHover);
-STATIC_ASSERT_ENUM(kWebAXEventInvalidStatusChanged,
-                   AXObjectCacheImpl::kAXInvalidStatusChanged);
-STATIC_ASSERT_ENUM(kWebAXEventLayoutComplete,
-                   AXObjectCacheImpl::kAXLayoutComplete);
-STATIC_ASSERT_ENUM(kWebAXEventLiveRegionChanged,
-                   AXObjectCacheImpl::kAXLiveRegionChanged);
-STATIC_ASSERT_ENUM(kWebAXEventLoadComplete, AXObjectCacheImpl::kAXLoadComplete);
-STATIC_ASSERT_ENUM(kWebAXEventLocationChanged,
-                   AXObjectCacheImpl::kAXLocationChanged);
-STATIC_ASSERT_ENUM(kWebAXEventMenuListItemSelected,
-                   AXObjectCacheImpl::kAXMenuListItemSelected);
-STATIC_ASSERT_ENUM(kWebAXEventMenuListItemUnselected,
-                   AXObjectCacheImpl::kAXMenuListItemUnselected);
-STATIC_ASSERT_ENUM(kWebAXEventMenuListValueChanged,
-                   AXObjectCacheImpl::kAXMenuListValueChanged);
-STATIC_ASSERT_ENUM(kWebAXEventRowCollapsed, AXObjectCacheImpl::kAXRowCollapsed);
-STATIC_ASSERT_ENUM(kWebAXEventRowCountChanged,
-                   AXObjectCacheImpl::kAXRowCountChanged);
-STATIC_ASSERT_ENUM(kWebAXEventRowExpanded, AXObjectCacheImpl::kAXRowExpanded);
-STATIC_ASSERT_ENUM(kWebAXEventScrollPositionChanged,
-                   AXObjectCacheImpl::kAXScrollPositionChanged);
-STATIC_ASSERT_ENUM(kWebAXEventScrolledToAnchor,
-                   AXObjectCacheImpl::kAXScrolledToAnchor);
-STATIC_ASSERT_ENUM(kWebAXEventSelectedChildrenChanged,
-                   AXObjectCacheImpl::kAXSelectedChildrenChanged);
-STATIC_ASSERT_ENUM(kWebAXEventSelectedTextChanged,
-                   AXObjectCacheImpl::kAXSelectedTextChanged);
-STATIC_ASSERT_ENUM(kWebAXEventShow, AXObjectCacheImpl::kAXShow);
-STATIC_ASSERT_ENUM(kWebAXEventTextChanged, AXObjectCacheImpl::kAXTextChanged);
-STATIC_ASSERT_ENUM(kWebAXEventValueChanged, AXObjectCacheImpl::kAXValueChanged);
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 185c3fe..9a899c5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "ui/accessibility/ax_enums.mojom-shared.h"
 
 namespace blink {
 
@@ -56,40 +57,6 @@
  public:
   static AXObjectCache* Create(Document&);
 
-  enum AXNotification {
-    kAXActiveDescendantChanged,
-    kAXAriaAttributeChanged,
-    kAXAutocorrectionOccured,
-    kAXBlur,
-    kAXCheckedStateChanged,
-    kAXChildrenChanged,
-    kAXClicked,
-    kAXDocumentSelectionChanged,
-    kAXDocumentTitleChanged,
-    kAXExpandedChanged,
-    kAXFocusedUIElementChanged,
-    kAXHide,
-    kAXHover,
-    kAXInvalidStatusChanged,
-    kAXLayoutComplete,
-    kAXLiveRegionChanged,
-    kAXLoadComplete,
-    kAXLocationChanged,
-    kAXMenuListItemSelected,
-    kAXMenuListItemUnselected,
-    kAXMenuListValueChanged,
-    kAXRowCollapsed,
-    kAXRowCountChanged,
-    kAXRowExpanded,
-    kAXScrollPositionChanged,
-    kAXScrolledToAnchor,
-    kAXSelectedChildrenChanged,
-    kAXSelectedTextChanged,
-    kAXShow,
-    kAXTextChanged,
-    kAXValueChanged
-  };
-
   explicit AXObjectCacheImpl(Document&);
   ~AXObjectCacheImpl() override;
   void Trace(blink::Visitor*) override;
@@ -219,9 +186,9 @@
   // values are cached as long as the modification count hasn't changed.
   int ModificationCount() const { return modification_count_; }
 
-  void PostNotification(LayoutObject*, AXNotification);
-  void PostNotification(Node*, AXNotification);
-  void PostNotification(AXObject*, AXNotification);
+  void PostNotification(LayoutObject*, ax::mojom::Event);
+  void PostNotification(Node*, ax::mojom::Event);
+  void PostNotification(AXObject*, ax::mojom::Event);
 
   //
   // Aria-owns support.
@@ -258,7 +225,7 @@
   void RequestAOMEventListenerPermission();
 
  protected:
-  void PostPlatformNotification(AXObject*, AXNotification);
+  void PostPlatformNotification(AXObject*, ax::mojom::Event);
   void LabelChanged(Element*);
 
   AXObject* CreateFromRenderer(LayoutObject*);
@@ -286,7 +253,7 @@
 #endif
 
   TaskRunnerTimer<AXObjectCacheImpl> notification_post_timer_;
-  HeapVector<std::pair<Member<AXObject>, AXNotification>>
+  HeapVector<std::pair<Member<AXObject>, ax::mojom::Event>>
       notifications_to_post_;
   void NotificationPostTimerFired(TimerBase*);
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc b/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc
index 93a9119..dd1c41a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc
@@ -53,7 +53,7 @@
 
   ToAXRadioInput(next_axobject)->UpdatePosAndSetSize(position);
   AXObjectCache().PostNotification(next_axobject,
-                                   AXObjectCacheImpl::kAXAriaAttributeChanged);
+                                   ax::mojom::Event::kAriaAttributeChanged);
   ToAXRadioInput(next_axobject)->RequestUpdateToNextNode(forward);
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
index c4dfefe2..3195405 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
@@ -35,7 +35,7 @@
 
 void AXVirtualObject::ChildrenChanged() {
   ClearChildren();
-  AXObjectCache().PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged);
+  AXObjectCache().PostNotification(this, ax::mojom::Event::kChildrenChanged);
 }
 
 const AtomicString& AXVirtualObject::GetAOMPropertyOrARIAAttribute(
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 1489cec6..065ea0c 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -391,13 +391,9 @@
   String source_code;
   std::unique_ptr<Vector<char>> cached_meta_data;
 
-  // TODO(https://crbug.com/824647): Use blink::mojom::ScriptType everywhere
-  // and deprecate blink::ScriptType.
-  // Remove this line after removed all blink::ScriptType.
-  ScriptType script_type =
-      (worker_start_data_.script_type == mojom::ScriptType::kModule)
-          ? ScriptType::kModule
-          : ScriptType::kClassic;
+  // TODO(nhiroki); Set |script_type| to ScriptType::kModule for module fetch.
+  // (https://crbug.com/824647)
+  ScriptType script_type = ScriptType::kClassic;
 
   // |main_script_loader_| isn't created if the InstalledScriptsManager had the
   // script.
@@ -462,33 +458,13 @@
   worker_inspector_proxy_->WorkerThreadCreated(document, worker_thread_.get(),
                                                worker_start_data_.script_url);
 
-  // > Switching on job’s worker type, run these substeps with the following
-  // > options:
-  // https://w3c.github.io/ServiceWorker/#update-algorithm
-  if (script_type == ScriptType::kClassic) {
-    // > "classic": Fetch a classic worker script given job’s serialized script
-    // > url, job’s client, "serviceworker", and the to-be-created environment
-    // > settings object for this service worker.
-    worker_thread_->EvaluateClassicScript(
-        worker_start_data_.script_url, source_code, std::move(cached_meta_data),
-        v8_inspector::V8StackTraceId());
-  } else {
-    // > "module": Fetch a module worker script graph given job’s serialized
-    // > script url, job’s client, "serviceworker", "omit", and the
-    // > to-be-created environment settings object for this service worker.
-
-    // TODO(asamidoi): Currently, we use the shadow page's Document as an
-    // outside_settings_object as a workaround. This should be the Document that
-    // called navigator.ServiceWorker.register(). To do it, we need to make a
-    // way to pass the settings object over mojo IPCs.
-    auto* outside_settings_object =
-        document->CreateFetchClientSettingsObjectSnapshot();
-    network::mojom::FetchCredentialsMode credentials_mode =
-        network::mojom::FetchCredentialsMode::kOmit;
-    worker_thread_->ImportModuleScript(worker_start_data_.script_url,
-                                       outside_settings_object,
-                                       credentials_mode);
-  }
+  // TODO(nhiroki): Support module workers (https://crbug.com/680046).
+  // Note that this doesn't really start the script evaluation until
+  // ReadyToEvaluateScript() is called on the WebServiceWorkerContextProxy
+  // on the worker thread.
+  worker_thread_->EvaluateClassicScript(
+      worker_start_data_.script_url, source_code, std::move(cached_meta_data),
+      v8_inspector::V8StackTraceId());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/registration_options.idl b/third_party/blink/renderer/modules/service_worker/registration_options.idl
index 3730e774..4442ea6 100644
--- a/third_party/blink/renderer/modules/service_worker/registration_options.idl
+++ b/third_party/blink/renderer/modules/service_worker/registration_options.idl
@@ -5,6 +5,5 @@
 // https://w3c.github.io/ServiceWorker/#dictdef-registrationoptions
 dictionary RegistrationOptions {
     USVString scope;
-    WorkerType type = "classic";
     ServiceWorkerUpdateViaCache updateViaCache = "imports";
 };
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
index 813cb3e..b86eca31 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
@@ -50,7 +50,6 @@
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -79,15 +78,6 @@
   return mojom::ServiceWorkerUpdateViaCache::kImports;
 }
 
-mojom::ScriptType ParseScriptType(const String& type) {
-  if (type == "classic")
-    return mojom::ScriptType::kClassic;
-  if (type == "module")
-    return mojom::ScriptType::kModule;
-  NOTREACHED() << "Invalid type: " << type;
-  return mojom::ScriptType::kClassic;
-}
-
 class GetRegistrationCallback : public WebServiceWorkerProvider::
                                     WebServiceWorkerGetRegistrationCallbacks {
  public:
@@ -189,17 +179,6 @@
     return promise;
   }
 
-  // TODO(asamidoi): Remove this check after module loading for
-  // ServiceWorker is enabled by default (https://crbug.com/824647).
-  if (options.type() == "module" &&
-      !RuntimeEnabledFeatures::ModuleServiceWorkerEnabled()) {
-    resolver->Reject(DOMException::Create(
-        DOMExceptionCode::kNotSupportedError,
-        "type 'module' in RegistrationOptions is not implemented yet."
-        "See https://crbug.com/824647 for details."));
-    return promise;
-  }
-
   auto callbacks = std::make_unique<CallbackPromiseAdapter<
       ServiceWorkerRegistration, ServiceWorkerErrorForUpdate>>(resolver);
 
@@ -305,10 +284,9 @@
 
   mojom::ServiceWorkerUpdateViaCache update_via_cache =
       ParseUpdateViaCache(options.updateViaCache());
-  mojom::ScriptType type = ParseScriptType(options.type());
 
-  provider_->RegisterServiceWorker(pattern_url, script_url, type,
-                                   update_via_cache, std::move(callbacks));
+  provider_->RegisterServiceWorker(pattern_url, script_url, update_via_cache,
+                                   std::move(callbacks));
   return promise;
 }
 
@@ -404,6 +382,11 @@
   return promise;
 }
 
+ServiceWorkerContainer::ReadyProperty*
+ServiceWorkerContainer::CreateReadyProperty() {
+  return new ReadyProperty(GetExecutionContext(), this, ReadyProperty::kReady);
+}
+
 ScriptPromise ServiceWorkerContainer::ready(ScriptState* caller_state) {
   if (!GetExecutionContext())
     return ScriptPromise();
@@ -496,9 +479,4 @@
   }
 }
 
-ServiceWorkerContainer::ReadyProperty*
-ServiceWorkerContainer::CreateReadyProperty() {
-  return new ReadyProperty(GetExecutionContext(), this, ReadyProperty::kReady);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
index a750ba0..6099c23 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
@@ -131,7 +131,6 @@
   void RegisterServiceWorker(
       const WebURL& pattern,
       const WebURL& script_url,
-      blink::mojom::ScriptType script_type,
       mojom::ServiceWorkerUpdateViaCache update_via_cache,
       std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks)
       override {
@@ -252,7 +251,6 @@
   StubWebServiceWorkerProvider()
       : register_call_count_(0),
         get_registration_call_count_(0),
-        script_type_(mojom::ScriptType::kClassic),
         update_via_cache_(mojom::ServiceWorkerUpdateViaCache::kImports) {}
 
   // Creates a WebServiceWorkerProvider. This can outlive the
@@ -268,7 +266,6 @@
   const WebURL& RegisterScriptURL() { return register_script_url_; }
   size_t GetRegistrationCallCount() { return get_registration_call_count_; }
   const WebURL& GetRegistrationURL() { return get_registration_url_; }
-  mojom::ScriptType ScriptType() const { return script_type_; }
   mojom::ServiceWorkerUpdateViaCache UpdateViaCache() const {
     return update_via_cache_;
   }
@@ -284,14 +281,12 @@
     void RegisterServiceWorker(
         const WebURL& pattern,
         const WebURL& script_url,
-        blink::mojom::ScriptType script_type,
         mojom::ServiceWorkerUpdateViaCache update_via_cache,
         std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks)
         override {
       owner_.register_call_count_++;
       owner_.register_scope_ = pattern;
       owner_.register_script_url_ = script_url;
-      owner_.script_type_ = script_type;
       owner_.update_via_cache_ = update_via_cache;
       registration_callbacks_to_delete_.push_back(std::move(callbacks));
     }
@@ -325,7 +320,6 @@
   WebURL register_script_url_;
   size_t get_registration_call_count_;
   WebURL get_registration_url_;
-  mojom::ScriptType script_type_;
   mojom::ServiceWorkerUpdateViaCache update_via_cache_;
 };
 
@@ -352,7 +346,6 @@
               stub_provider.RegisterScope());
     EXPECT_EQ(WebURL(KURL("http://localhost/x/y/worker.js")),
               stub_provider.RegisterScriptURL());
-    EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType());
     EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
               stub_provider.UpdateViaCache());
   }
@@ -374,7 +367,6 @@
     EXPECT_EQ(1ul, stub_provider.GetRegistrationCallCount());
     EXPECT_EQ(WebURL(KURL("http://localhost/x/index.html")),
               stub_provider.GetRegistrationURL());
-    EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType());
     EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
               stub_provider.UpdateViaCache());
   }
@@ -403,39 +395,10 @@
               stub_provider.RegisterScope());
     EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/worker.js")),
               stub_provider.RegisterScriptURL());
-    EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType());
     EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kNone,
               stub_provider.UpdateViaCache());
   }
 }
 
-TEST_F(ServiceWorkerContainerTest, Register_TypeOptionDelegatesToProvider) {
-  SetPageURL("http://localhost/x/index.html");
-
-  StubWebServiceWorkerProvider stub_provider;
-  Provide(stub_provider.Provider());
-
-  ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-      GetExecutionContext(), GetNavigatorServiceWorker());
-
-  // register
-  {
-    ScriptState::Scope script_scope(GetScriptState());
-    RegistrationOptions options;
-    options.setType("module");
-    container->registerServiceWorker(GetScriptState(), "/x/y/worker.js",
-                                     options);
-
-    EXPECT_EQ(1ul, stub_provider.RegisterCallCount());
-    EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/")),
-              stub_provider.RegisterScope());
-    EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/worker.js")),
-              stub_provider.RegisterScriptURL());
-    EXPECT_EQ(mojom::ScriptType::kModule, stub_provider.ScriptType());
-    EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
-              stub_provider.UpdateViaCache());
-  }
-}
-
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 077b0eb8..3bea7b4 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -40,7 +40,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/global_fetch.h"
@@ -54,7 +53,6 @@
 #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
 #include "third_party/blink/renderer/core/workers/installed_scripts_manager.h"
 #include "third_party/blink/renderer/core/workers/worker_clients.h"
-#include "third_party/blink/renderer/core/workers/worker_module_tree_client.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h"
@@ -172,13 +170,9 @@
     const KURL& module_url_record,
     FetchClientSettingsObjectSnapshot* outside_settings_object,
     network::mojom::FetchCredentialsMode credentials_mode) {
-  Modulator* modulator = Modulator::From(ScriptController()->GetScriptState());
-
-  FetchModuleScript(module_url_record, outside_settings_object,
-                    WebURLRequest::kRequestContextServiceWorker,
-                    credentials_mode,
-                    ModuleScriptCustomFetchType::kWorkerConstructor,
-                    new WorkerModuleTreeClient(modulator));
+  // TODO(nhiroki): Implement module loading for service workers.
+  // (https://crbug.com/824647)
+  NOTREACHED();
 }
 
 void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size,
diff --git a/third_party/blink/renderer/platform/feature_policy/feature_policy.cc b/third_party/blink/renderer/platform/feature_policy/feature_policy.cc
index 5331c3d..cf0f8f5 100644
--- a/third_party/blink/renderer/platform/feature_policy/feature_policy.cc
+++ b/third_party/blink/renderer/platform/feature_policy/feature_policy.cc
@@ -245,6 +245,8 @@
                                    mojom::FeaturePolicyFeature::kDocumentWrite);
       default_feature_name_map.Set(
           "image-compression", mojom::FeaturePolicyFeature::kImageCompression);
+      default_feature_name_map.Set("lazyload",
+                                   mojom::FeaturePolicyFeature::kLazyLoad);
       default_feature_name_map.Set(
           "legacy-image-formats",
           mojom::FeaturePolicyFeature::kLegacyImageFormats);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 6f42011..20a538d 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -768,10 +768,6 @@
       name: "ModuleScriptsImportMetaUrl",
     },
     {
-      name: "ModuleServiceWorker",
-      status: "test",
-    },
-    {
       name: "MojoJS",
       status: "test",
     },
diff --git a/tools/android/roll/android_deps/build.gradle b/tools/android/roll/android_deps/build.gradle
index db7cfb2..1b35618 100644
--- a/tools/android/roll/android_deps/build.gradle
+++ b/tools/android/roll/android_deps/build.gradle
@@ -64,11 +64,11 @@
 
     compile "com.android.support:multidex:1.0.0"
 
+    compile "javax.inject:javax.inject:1"
+
     // Dagger
     def daggerVersion = '2.17'
     compile "com.google.dagger:dagger:${daggerVersion}"
-    compile "javax.inject:javax.inject:1"
-
     annotationProcessor "com.google.dagger:dagger-compiler:${daggerVersion}"
 }
 
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
index 365e515..e5a2f12 100644
--- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
+++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -76,11 +76,11 @@
             new File("${absoluteDepDir}/README.chromium").write(makeReadme(dependency))
             new File("${absoluteDepDir}/cipd.yaml").write(makeCipdYaml(dependency, repositoryPath))
             new File("${absoluteDepDir}/OWNERS").write(makeOwners())
-            if (!dependency.licenseUrl?.trim()?.isEmpty()) {
-                downloadFile(dependency.licenseUrl, new File("${absoluteDepDir}/LICENSE"))
-            } else if (!dependency.licensePath?.isEmpty()) {
+            if (!dependency.licensePath?.trim()?.isEmpty()) {
                 new File("${absoluteDepDir}/LICENSE").write(
                         new File("${normalisedRepoPath}/${dependency.licensePath}").text)
+            } else if (!dependency.licenseUrl?.trim()?.isEmpty()) {
+                downloadFile(dependency.licenseUrl, new File("${absoluteDepDir}/LICENSE"))
             }
         }
 
@@ -265,7 +265,7 @@
         # To create CIPD package run the following command.
         # cipd create --pkg-def cipd.yaml -tag version:${cipdVersion}
         package: chromium/${repoPath}/${DOWNLOAD_DIRECTORY_NAME}/${dependency.id}
-        description: ${dependency.displayName}
+        description: "${dependency.displayName}"
         data:
         - file: ${dependency.fileName}
         """.stripIndent()
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
index 0ca3be4a..af6e50c 100644
--- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
+++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
@@ -21,23 +21,25 @@
     final def dependencies = new HashMap<String, DependencyDescription>()
 
     // Some libraries don't properly fill their POM with the appropriate licensing information.
-    // It is provided here from manual lookups.
+    // It is provided here from manual lookups. Note that licenseUrl must provide textual content
+    // rather than be an html page.
     final def FALLBACK_PROPERTIES = [
         'com_google_googlejavaformat_google_java_format': new DependencyDescription(
-          url: "https://github.com/google/google-java-format",
-          licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
-          licenseName: "Apache 2.0"),
+            url: "https://github.com/google/google-java-format",
+            licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
+            licenseName: "Apache 2.0"),
         'com_google_guava_guava': new DependencyDescription(
-          url: "https://github.com/google/guava",
-          licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
-          licenseName: "Apache 2.0"),
+            url: "https://github.com/google/guava",
+            licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
+            licenseName: "Apache 2.0"),
         'org_codehaus_mojo_animal_sniffer_annotations': new DependencyDescription(
-          url: "http://www.mojohaus.org/animal-sniffer/animal-sniffer-annotations/",
-          licenseUrl: "https://opensource.org/licenses/mit-license.php",
-          licenseName: "MIT"),
+            url: "http://www.mojohaus.org/animal-sniffer/animal-sniffer-annotations/",
+            licenseUrl: "https://raw.githubusercontent.com/mojohaus/animal-sniffer/master/animal-sniffer-annotations/pom.xml",
+            licensePath: "licenses/Codehaus_License-2009.txt",
+            licenseName: "MIT"),
         'org_checkerframework_checker_compat_qual' :new DependencyDescription(
-          licenseUrl: "https://github.com/typetools/checker-framework/blob/master/LICENSE.txt",
-          licenseName: "GPL v2 (with the classpath exception)"),
+            licenseUrl: "https://raw.githubusercontent.com/typetools/checker-framework/master/LICENSE.txt",
+            licenseName: "GPL v2 with the classpath exception"),
     ]
 
     Project project
@@ -151,24 +153,25 @@
     }
 
     private customizeDep(DependencyDescription dep) {
-        if (dep.id?.startsWith("com_google_android_gms_play_services_")) {
+        if (dep.id?.startsWith("com_google_android_")) {
             dep.licenseUrl = ""
             // This should match fetch_all._ANDROID_SDK_LICENSE_PATH
-            dep.licensePath = "Android_SDK_License-December_9_2016.txt"
+            dep.licensePath = "licenses/Android_SDK_License-December_9_2016.txt"
             if (dep.url?.isEmpty()) {
                 dep.url = "https://developers.google.com/android/guides/setup"
             }
-            // Filter out targets like:
-            //     com_google_android_gms_play_services_auth_api_phone_license
-            if (dep.id?.endsWith("_license")) {
-                dep.exclude = true
-            }
         } else if (dep.licenseName?.isEmpty()) {
             def fallbackProperties = FALLBACK_PROPERTIES.get(dep.id)
             if (fallbackProperties != null) {
                 project.logger.debug("Using fallback properties for ${dep.id}")
                 dep.licenseName = fallbackProperties.licenseName
                 dep.licenseUrl = fallbackProperties.licenseUrl
+                if (fallbackProperties.licensePath != null) {
+                    dep.licensePath = fallbackProperties.licensePath
+                }
+                if (dep.url?.isEmpty()) {
+                    dep.url = fallbackProperties.url
+                }
             }
         }
 
diff --git a/tools/android/roll/android_deps/fetch_all.py b/tools/android/roll/android_deps/fetch_all.py
index 561c59a..cea4b71 100755
--- a/tools/android/roll/android_deps/fetch_all.py
+++ b/tools/android/roll/android_deps/fetch_all.py
@@ -51,9 +51,8 @@
 # Path to BUILD.gn file under android_deps/
 _ANDROID_DEPS_BUILD_GN = _ANDROID_DEPS_SUBDIR + '/BUILD.gn'
 
-# Path to updated Android SDK License under android_deps/
-_ANDROID_SDK_LICENSE_PATH = (
-    _ANDROID_DEPS_SUBDIR + '/Android_SDK_License-December_9_2016.txt')
+# Path to custom licenses under android_deps/
+_ANDROID_DEPS_LICENSE_SUBDIR = _ANDROID_DEPS_SUBDIR + '/licenses'
 
 # Path to additional_readme_paths.json
 _ANDROID_DEPS_ADDITIONAL_README_PATHS = (
@@ -75,10 +74,10 @@
   _ANDROID_DEPS_ADDITIONAL_README_PATHS,
 ]
 
-# The list of files that are copied to the build directory by this script.
-# Should not include _UPDATED_GIT_FILES.
+# The list of files and dirs that are copied to the build directory by this
+# script. Should not include _UPDATED_GIT_FILES.
 _COPIED_PATHS = [
-  _ANDROID_SDK_LICENSE_PATH,
+  _ANDROID_DEPS_LICENSE_SUBDIR,
   _BUILD_GRADLE_PATH,
   _GRADLE_BUILDSRC_PATH,
 ]
@@ -382,9 +381,9 @@
     return
 
   missing_files = []
-  for src_file in _UPDATED_GIT_FILES + _COPIED_PATHS:
-    if not os.path.exists(os.path.join(chromium_src, src_file)):
-      missing_files.append(src_file)
+  for src_path in _UPDATED_GIT_FILES + _COPIED_PATHS:
+    if not os.path.exists(os.path.join(chromium_src, src_path)):
+      missing_files.append(src_path)
 
   if missing_files:
     raise Exception('Missing files from %s: %s' % (chromium_src, missing_files))
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index 88aab80..48f9a94 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -17,14 +17,16 @@
 import path_util
 
 
-_COMPACT_FILE_PATH_KEY = 'p'
+# These must match |_KEYS| in shared.js.
 _COMPACT_FILE_COMPONENT_INDEX_KEY = 'c'
+_COMPACT_FILE_PATH_KEY = 'p'
 _COMPACT_FILE_SYMBOLS_KEY = 's'
-_COMPACT_SYMBOL_NAME_KEY = 'n'
 _COMPACT_SYMBOL_BYTE_SIZE_KEY = 'b'
-_COMPACT_SYMBOL_TYPE_KEY = 't'
 _COMPACT_SYMBOL_COUNT_KEY = 'u'
 _COMPACT_SYMBOL_FLAGS_KEY = 'f'
+_COMPACT_SYMBOL_NAME_KEY = 'n'
+_COMPACT_SYMBOL_NUM_ALIASES_KEY = 'a'
+_COMPACT_SYMBOL_TYPE_KEY = 't'
 
 # Always emit this many distict symbols (if present), even when small.
 # No need to optimize file size at this point).
@@ -132,10 +134,13 @@
 
     is_dex_method = symbol.section_name == models.SECTION_DEX_METHOD
     symbol_entry = {
+      _COMPACT_SYMBOL_BYTE_SIZE_KEY: symbol_size,
       _COMPACT_SYMBOL_NAME_KEY: symbol.template_name,
       _COMPACT_SYMBOL_TYPE_KEY: symbol.section,
-      _COMPACT_SYMBOL_BYTE_SIZE_KEY: symbol_size,
     }
+    if symbol.num_aliases != 1:
+      symbol_entry[_COMPACT_SYMBOL_NUM_ALIASES_KEY] = symbol.num_aliases
+
     # We use symbol count for the method count mode in the diff mode report.
     # Negative values are used to indicate a symbol was removed, so it should
     # count as -1 rather than the default, 1.
diff --git a/tools/binary_size/libsupersize/static/shared.js b/tools/binary_size/libsupersize/static/shared.js
index 63ead0a..262a8aa0 100644
--- a/tools/binary_size/libsupersize/static/shared.js
+++ b/tools/binary_size/libsupersize/static/shared.js
@@ -57,16 +57,20 @@
  * @typedef {(node: TreeNode, unit: string) => GetSizeResult} GetSize
  */
 
-/** Abberivated keys used by FileEntrys in the JSON data file. */
+/**
+ * Abberivated keys used by FileEntrys in the JSON data file. These must match
+ * _COMPACT_*_KEY variables in html_report.py.
+ */
 const _KEYS = Object.freeze({
-  SOURCE_PATH: /** @type {'p'} */ ('p'),
   COMPONENT_INDEX: /** @type {'c'} */ ('c'),
+  SOURCE_PATH: /** @type {'p'} */ ('p'),
   FILE_SYMBOLS: /** @type {'s'} */ ('s'),
-  SYMBOL_NAME: /** @type {'n'} */ ('n'),
   SIZE: /** @type {'b'} */ ('b'),
-  TYPE: /** @type {'t'} */ ('t'),
   COUNT: /** @type {'u'} */ ('u'),
   FLAGS: /** @type {'f'} */ ('f'),
+  SYMBOL_NAME: /** @type {'n'} */ ('n'),
+  NUM_ALIASES: /** @type {'a'} */ ('a'),
+  TYPE: /** @type {'t'} */ ('t'),
 });
 
 /** Abberivated keys used by FileEntrys in the JSON data file. */
diff --git a/tools/binary_size/libsupersize/static/state.js b/tools/binary_size/libsupersize/static/state.js
index 8c5241d..f6703c5 100644
--- a/tools/binary_size/libsupersize/static/state.js
+++ b/tools/binary_size/libsupersize/static/state.js
@@ -357,10 +357,13 @@
       const suffixElement = dom.textElement('small', unit);
 
       const bytesGrouped = bytes.toLocaleString(_LOCALE, {useGrouping: true});
-
+      let description = `${bytesGrouped} bytes`;
+      if (node.numAliases && node.numAliases > 1) {
+        description += ` for 1 of ${node.numAliases} aliases`;
+      }
       return {
         element: dom.createFragment([textNode, suffixElement]),
-        description: `${bytesGrouped} bytes`,
+        description,
         value: bytes,
       };
     }
diff --git a/tools/binary_size/libsupersize/static/tree-worker.js b/tools/binary_size/libsupersize/static/tree-worker.js
index adb25d29..231c3d2c 100644
--- a/tools/binary_size/libsupersize/static/tree-worker.js
+++ b/tools/binary_size/libsupersize/static/tree-worker.js
@@ -95,17 +95,19 @@
     shortNameIndex,
     size = 0,
     flags = 0,
+    numAliases,
     childStats = {},
   } = options;
   return {
     children: [],
     parent: null,
-    childStats,
     idPath,
+    type,
     shortNameIndex,
     size,
-    type,
     flags,
+    numAliases,
+    childStats,
   };
 }
 
@@ -374,6 +376,7 @@
       const type = symbol[_KEYS.TYPE];
       const count = symbol[_KEYS.COUNT] || 1;
       const flags = symbol[_KEYS.FLAGS] || 0;
+      const numAliases = symbol[_KEYS.NUM_ALIASES] || 1;
 
       const symbolNode = createNode({
         // Join file path to symbol name with a ":"
@@ -382,6 +385,7 @@
         size,
         type,
         flags,
+        numAliases,
         childStats: {
           [type]: {
             size,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 145e5b5f..e7af1f8b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3453,6 +3453,7 @@
   <int value="9" label="EFD_BAD_MESSAGE_WORKER"/>
   <int value="10" label="WVG_PARTITION_ID_NOT_UTF8"/>
   <int value="11" label="ESWMF_BAD_EVENT_ACK"/>
+  <int value="12" label="MHVG_INVALID_PLUGIN_FRAME_ID"/>
 </enum>
 
 <enum name="BadMessageReasonGuestView">
@@ -16683,6 +16684,7 @@
       label="FILEMANAGERPRIVATEINTERNAL_SHAREPATHWITHCROSTINICONTAINER"/>
   <int value="1273" label="AUTOTESTPRIVATE_SETCROSTINIENABLED"/>
   <int value="1274" label="AUTOTESTPRIVATE_GETHISTOGRAM"/>
+  <int value="1275" label="TABCAPTURE_GETMEDIASTREAMID"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -28156,6 +28158,7 @@
   <int value="-2132591642" label="enable-input-view"/>
   <int value="-2124839789"
       label="OmniboxUIExperimentHideSteadyStateUrlSchemeAndSubdomains:enabled"/>
+  <int value="-2124685253" label="USBGuard:enabled"/>
   <int value="-2123795624" label="ArcSmartTextSelection:enabled"/>
   <int value="-2122048316"
       label="DisplayPersistenceToggleInPermissionPrompts:enabled"/>
@@ -29575,6 +29578,7 @@
   <int value="628570445" label="AndroidAutofillAccessibility:enabled"/>
   <int value="629549626" label="ContextualSearchMlTapSuppression:enabled"/>
   <int value="630244477" label="ServiceWorkerPaymentApps:enabled"/>
+  <int value="630776247" label="USBGuard:disabled"/>
   <int value="630947363" label="touch-events"/>
   <int value="632340413" label="network-settings-config"/>
   <int value="633442161" label="ExperimentalUi:disabled"/>
@@ -30575,6 +30579,265 @@
   <int value="4" label="ClosedAbort"/>
 </enum>
 
+<enum name="MachKernReturn">
+  <summary>
+    Mach kern return values defined in
+    https://opensource.apple.com/source/xnu/xnu-4570.41.2/osfmk/mach/kern_return.h
+    and
+    https://opensource.apple.com/source/xnu/xnu-4570.41.2/osfmk/mach/message.h
+  </summary>
+  <int value="0" label="KERN_SUCCESS"/>
+  <int value="1" label="KERN_INVALID_ADDRESS">
+    Specified address is not currently valid.
+  </int>
+  <int value="2" label="KERN_PROTECTION_FAILURE">
+    Specified memory is valid, but does not permit the required forms of access.
+  </int>
+  <int value="3" label="KERN_NO_SPACE">
+    The address range specified is already in use, or no address range of the
+    size specified could be found.
+  </int>
+  <int value="4" label="KERN_INVALID_ARGUMENT">
+    The function requested was not applicable to this type of argument, or an
+    argument is invalid
+  </int>
+  <int value="5" label="KERN_FAILURE">
+    The function could not be performed. A catch-all.
+  </int>
+  <int value="6" label="KERN_RESOURCE_SHORTAGE">
+    A system resource could not be allocated to fulfill this request. This
+    failure may not be permanent.
+  </int>
+  <int value="7" label="KERN_NOT_RECEIVER">
+    The task in question does not hold receive rights for the port argument.
+  </int>
+  <int value="8" label="KERN_NO_ACCESS">Bogus access restriction.</int>
+  <int value="9" label="KERN_MEMORY_FAILURE">
+    During a page fault, the target address refers to a memory object that has
+    been destroyed. This failure is permanent.
+  </int>
+  <int value="10" label="KERN_MEMORY_ERROR">
+    During a page fault, the memory object indicated that the data could not be
+    returned. This failure may be temporary; future attempts to access this same
+    data may succeed, as defined by the memory object.
+  </int>
+  <int value="12" label="KERN_NOT_IN_SET">
+    The receive right is not a member of a port set.
+  </int>
+  <int value="13" label="KERN_NAME_EXISTS">
+    The name already denotes a right in the task.
+  </int>
+  <int value="14" label="KERN_ABORTED">
+    The operation was aborted. Ipc code will catch this and reflect it as a
+    message error.
+  </int>
+  <int value="15" label="KERN_INVALID_NAME">
+    The name doesn't denote a right in the task.
+  </int>
+  <int value="17" label="KERN_INVALID_RIGHT">
+    The name denotes a right, but not an appropriate right.
+  </int>
+  <int value="18" label="KERN_INVALID_VALUE">A blatant range error.</int>
+  <int value="21" label="KERN_RIGHT_EXISTS">
+    The task already has send or receive rights for the port under another name.
+  </int>
+  <int value="23" label="KERN_MEMORY_PRESENT">
+    An attempt was made to supply &quot;precious&quot; data for memory that is
+    already present in a memory object.
+  </int>
+  <int value="24" label="KERN_MEMORY_DATA_MOVED">
+    A page was requested of a memory manager via memory_object_data_request for
+    an object using a MEMORY_OBJECT_COPY_CALL strategy, with the
+    VM_PROT_WANTS_COPY flag being used to specify that the page desired is for a
+    copy of the object, and the memory manager has detected the page was pushed
+    into a copy of the object while the kernel was walking the shadow chain from
+    the copy to the object. This error code is delivered via
+    memory_object_data_error and is handled by the kernel (it forces the kernel
+    to restart the fault). It will not be seen by users.
+  </int>
+  <int value="25" label="KERN_MEMORY_RESTART_COPY">
+    A strategic copy was attempted of an object upon which a quicker copy is now
+    possible. The caller should retry the copy using vm_object_copy_quickly.
+    This error code is seen only by the kernel.
+  </int>
+  <int value="26" label="KERN_INVALID_PROCESSOR_SET">
+    An argument applied to assert processor set privilege was not a processor
+    set control port.
+  </int>
+  <int value="27" label="KERN_POLICY_LIMIT">
+    The specified scheduling attributes exceed the thread's limits.
+  </int>
+  <int value="28" label="KERN_INVALID_POLICY">
+    The specified scheduling policy is not currently enabled for the processor
+    set.
+  </int>
+  <int value="29" label="KERN_INVALID_OBJECT">
+    The external memory manager failed to initialize the memory object.
+  </int>
+  <int value="30" label="KERN_ALREADY_WAITING">
+    A thread is attempting to wait for an event for which there is already a
+    waiting thread.
+  </int>
+  <int value="31" label="KERN_DEFAULT_SET">
+    An attempt was made to destroy the default processor set.
+  </int>
+  <int value="32" label="KERN_EXCEPTION_PROTECTED">
+    An attempt was made to fetch an exception port that is protected, or to
+    abort a thread while processing a protected exception.
+  </int>
+  <int value="33" label="KERN_INVALID_LEDGER">
+    A ledger was required but not supplied.
+  </int>
+  <int value="34" label="KERN_INVALID_MEMORY_CONTROL">
+    The port was not a memory cache control port.
+  </int>
+  <int value="35" label="KERN_INVALID_SECURITY">
+    An argument supplied to assert security privilege was not a host security
+    port.
+  </int>
+  <int value="36" label="KERN_NOT_DEPRESSED">
+    thread_depress_abort was called on a thread which was not currently
+    depressed.
+  </int>
+  <int value="37" label="KERN_TERMINATED">
+    Object has been terminated and is no longer available
+  </int>
+  <int value="38" label="KERN_LOCK_SET_DESTROYED">
+    Lock set has been destroyed and is no longer available.
+  </int>
+  <int value="39" label="KERN_LOCK_UNSTABLE">
+    The thread holding the lock terminated before releasing the lock
+  </int>
+  <int value="40" label="KERN_LOCK_OWNED">
+    The lock is already owned by another thread
+  </int>
+  <int value="41" label="KERN_LOCK_OWNED_SELF">
+    The lock is already owned by the calling thread
+  </int>
+  <int value="42" label="KERN_SEMAPHORE_DESTROYED">
+    Semaphore has been destroyed and is no longer available.
+  </int>
+  <int value="43" label="KERN_RPC_SERVER_TERMINATED">
+    Return from RPC indicating the target server was terminated before it
+    successfully replied
+  </int>
+  <int value="44" label="KERN_RPC_TERMINATE_ORPHAN">
+    Terminate an orphaned activation.
+  </int>
+  <int value="45" label="KERN_RPC_CONTINUE_ORPHAN">
+    Allow an orphaned activation to continue executing.
+  </int>
+  <int value="48" label="KERN_NOT_WAITING">
+    A signalled thread was not actually waiting. */
+  </int>
+  <int value="50" label="KERN_CODESIGN_ERROR">
+    During a page fault, indicates that the page was rejected as a result of a
+    signature check.
+  </int>
+  <int value="51" label="KERN_POLICY_STATIC">
+    The requested property cannot be changed at this time.
+  </int>
+  <int value="52" label="KERN_INSUFFICIENT_BUFFER_SIZE">
+    The provided buffer is of insufficient size for the requested data.
+  </int>
+  <int value="1024" label="MACH_MSG_VM_KERNEL">
+    Kernel resource shortage handling out-of-line memory.
+  </int>
+  <int value="2048" label="MACH_MSG_IPC_KERNEL">
+    Kernel resource shortage handling an IPC capability.
+  </int>
+  <int value="4096" label="MACH_MSG_VM_SPACE">
+    No room in VM address space for out-of-line memory.
+  </int>
+  <int value="8192" label="MACH_MSG_IPC_SPACE">
+    No room in IPC name space for another capability name.
+  </int>
+  <int value="268435458" label="MACH_SEND_INVALID_DATA">
+    Bogus in-line data.
+  </int>
+  <int value="268435459" label="MACH_SEND_INVALID_DEST">
+    Bogus destination port.
+  </int>
+  <int value="268435460" label="MACH_SEND_TIMED_OUT">
+    Message not sent before timeout expired.
+  </int>
+  <int value="268435461" label="MACH_SEND_INVALID_VOUCHER">
+    Bogus voucher port.
+  </int>
+  <int value="268435463" label="MACH_SEND_INTERRUPTED">Software interrupt.</int>
+  <int value="268435464" label="MACH_SEND_MSG_TOO_SMALL">
+    Data doesn't contain a complete message.
+  </int>
+  <int value="268435465" label="MACH_SEND_INVALID_REPLY">Bogus reply port.</int>
+  <int value="268435466" label="MACH_SEND_INVALID_RIGHT">
+    Bogus port rights in the message body.
+  </int>
+  <int value="268435467" label="MACH_SEND_INVALID_NOTIFY">
+    Bogus notify port argument.
+  </int>
+  <int value="268435468" label="MACH_SEND_INVALID_MEMORY">
+    Invalid out-of-line memory pointer.
+  </int>
+  <int value="268435469" label="MACH_SEND_NO_BUFFER">
+    No message buffer is available.
+  </int>
+  <int value="268435470" label="MACH_SEND_TOO_LARGE">
+    Send is too large for port
+  </int>
+  <int value="268435471" label="MACH_SEND_INVALID_TYPE">
+    Invalid msg-type specification.
+  </int>
+  <int value="268435472" label="MACH_SEND_INVALID_HEADER">
+    A field in the header had a bad value.
+  </int>
+  <int value="268435473" label="MACH_SEND_INVALID_TRAILER">
+    The trailer to be sent does not match kernel format.
+  </int>
+  <int value="268435477" label="MACH_SEND_INVALID_RT_OOL_SIZE">
+    compatibility: no longer a returned error
+  </int>
+  <int value="268451842" label="MACH_RCV_INVALID_NAME">
+    Bogus name for receive port/port-set.
+  </int>
+  <int value="268451843" label="MACH_RCV_TIMED_OUT">
+    Didn't get a message within the timeout value.
+  </int>
+  <int value="268451844" label="MACH_RCV_TOO_LARGE">
+    Message buffer is not large enough for inline data.
+  </int>
+  <int value="268451845" label="MACH_RCV_INTERRUPTED">Software interrupt.</int>
+  <int value="268451846" label="MACH_RCV_PORT_CHANGED">
+    compatibility: no longer a returned error
+  </int>
+  <int value="268451847" label="MACH_RCV_INVALID_NOTIFY">
+    Bogus notify port argument.
+  </int>
+  <int value="268451848" label="MACH_RCV_INVALID_DATA">
+    Bogus message buffer for inline data.
+  </int>
+  <int value="268451849" label="MACH_RCV_PORT_DIED">
+    Port/set was sent away/died during receive.
+  </int>
+  <int value="268451850" label="MACH_RCV_IN_SET">
+    compatibility: no longer a returned error
+  </int>
+  <int value="268451851" label="MACH_RCV_HEADER_ERROR">
+    Error receiving message header. See special bits.
+  </int>
+  <int value="268451852" label="MACH_RCV_BODY_ERROR">
+    Error receiving message body. See special bits.
+  </int>
+  <int value="268451853" label="MACH_RCV_INVALID_TYPE">
+    Invalid msg-type specification in scatter list.
+  </int>
+  <int value="268451854" label="MACH_RCV_SCATTER_SMALL">
+    Out-of-line overwrite region is not large enough
+  </int>
+  <int value="268451855" label="MACH_RCV_INVALID_TRAILER">
+    trailer type or number of trailer elements not supported
+  </int>
+</enum>
+
 <enum name="MacOSBluetoothOperationsResult">
   <int value="-2" label="Unknown error domain"/>
   <int value="-1" label="No error"/>
@@ -36262,7 +36525,9 @@
   <int value="0" label="Success"/>
   <int value="1" label="Should retry without backoff"/>
   <int value="2" label="Should retry with backoff"/>
-  <int value="3" label="Should suspend"/>
+  <int value="3" label="Should suspend, not implemented"/>
+  <int value="4" label="Should suspend, not allowed"/>
+  <int value="5" label="Should suspend, blocked by administrator"/>
 </enum>
 
 <enum name="OfflineStatus">
@@ -48615,6 +48880,12 @@
   <int value="8" label="User turned off on-by-default privacy setting"/>
 </enum>
 
+<enum name="UnifiedConsentRevokeReason">
+  <int value="0" label="User signed out of Chrome"/>
+  <int value="1" label="Service was disabled"/>
+  <int value="2" label="Custom passphrase was detected"/>
+</enum>
+
 <enum name="UnifiedConsentSyncAndGoogleServicesSettings">
   <int value="0" label="None of the services are enabled"/>
   <int value="1" label="'Sync and all Google services' is enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c3c4ba4..311e748 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -24626,6 +24626,23 @@
   </summary>
 </histogram>
 
+<histogram name="Event.FrameEventRouting.TouchEventAckQueueSize"
+    expires_after="2019-12-31">
+  <owner>wjmaclean@chromium.org</owner>
+  <owner>kenrb@chromium.org</owner>
+  <summary>
+    The size of the TouchEventAckQueue, recorded each time we process an event
+    ack (the queue usually, but not always, decreases in size during ack
+    processing). Ideally this queue will operate at length close to zero,
+    depending on how long it takes for events to travel to a renderer and be
+    processed and an ack sent back. As the size increases it indicates decreased
+    responsiveness of renderers with respect to touch events. One purpose of
+    this metric is to develop a sense of normal queue sizes for different
+    platforms. Initially we expect queue length to be less than 20 most of the
+    time, but this is a guess.
+  </summary>
+</histogram>
+
 <histogram name="Event.Frequency.Renderer.FlingAnimate" units="hertz">
   <obsolete>
     Deprecated 06/2017 due to lack of usage.
@@ -96306,6 +96323,15 @@
   </summary>
 </histogram>
 
+<histogram name="SharedMemory.CreateMacError" enum="MachKernReturn">
+  <owner>alexilin@chromium.org</owner>
+  <summary>
+    Emitted each time a shared memory region could not be created due to a
+    failed Mac system call. The value of the entry indicates the return value of
+    the failed call.
+  </summary>
+</histogram>
+
 <histogram name="SharedMemory.CreateWinError" enum="WinGetLastError">
   <owner>bcwhite@chromium.org</owner>
   <summary>
@@ -109743,6 +109769,18 @@
   </summary>
 </histogram>
 
+<histogram name="UnifiedConsent.RevokeReason" enum="UnifiedConsentRevokeReason"
+    expires_after="2019-08-01">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <owner>tangltom@chromium.org</owner>
+  <summary>
+    The reason the unified consent was revoked. This is recorded every time the
+    consent state changes from &quot;unified consent given&quot; to
+    &quot;unified consent not given&quot;.
+  </summary>
+</histogram>
+
 <histogram name="UnifiedConsent.SyncAndGoogleServicesSettings"
     enum="UnifiedConsentSyncAndGoogleServicesSettings"
     expires_after="2019-08-21">
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index c0e8046..43e9e97 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -258,6 +258,9 @@
 crbug.com/877648 [ Android ] system_health.memory_mobile/long_running:tools:gmail-background [ Skip ]
 crbug.com/877648 [ Android ] system_health.memory_mobile/long_running:tools:gmail-foreground [ Skip ]
 crbug.com/879541 [ Android_One ] system_health.memory_mobile/browse:shopping:avito [ Skip ]
+crbug.com/883320 [ Android_Go ] system_health.memory_mobile/browse:news:cnn [ Skip ]
+crbug.com/883320 [ Android_Go ] system_health.memory_mobile/browse:news:cnn:2018 [ Skip ]
+crbug.com/883320 [ Android_Go ] system_health.memory_mobile/browse:social:tumblr_infinite_scroll [ Skip ]
 
 # Benchmark: start_with_url.warm.startup_pages
 crbug.com/878175 [ Android ] start_with_url.warm.startup_pages/about:blank [ Skip ]
diff --git a/ui/android/java/res/values-v17/styles.xml b/ui/android/java/res/values-v17/styles.xml
index b3db702..4e0a78678 100644
--- a/ui/android/java/res/values-v17/styles.xml
+++ b/ui/android/java/res/values-v17/styles.xml
@@ -170,4 +170,21 @@
         <item name="android:textColor">@color/default_text_color_link</item>
         <item name="android:textSize">@dimen/text_size_small</item>
     </style>
+
+    <!-- Dividers -->
+    <style name="HorizontalDivider"
+           tools:ignore="UnusedResources">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">@dimen/divider_height</item>
+        <item name="android:background">?android:attr/listDivider</item>
+        <item name="android:importantForAccessibility">no</item>
+    </style>
+    <style name="VerticalDivider"
+           tools:ignore="UnusedResources">
+        <item name="android:layout_width">@dimen/divider_height</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:background">?android:attr/listDivider</item>
+        <item name="android:importantForAccessibility">no</item>
+    </style>
+
 </resources>
diff --git a/ui/android/java/res/values/dimens.xml b/ui/android/java/res/values/dimens.xml
index 3e7d68c7..476fd71b 100644
--- a/ui/android/java/res/values/dimens.xml
+++ b/ui/android/java/res/values/dimens.xml
@@ -18,6 +18,9 @@
     <dimen name="dropdown_icon_margin">8dp</dimen>
     <dimen name="button_compat_corner_radius">4dp</dimen>
 
+    <!-- Divider Dimensions -->
+    <dimen name="divider_height">1dp</dimen>
+
     <!--
          Fallback values if the corresponding com.android.internal.R dimensions
          cannot be retrieved by name.
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 4da37842..190cf162 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -910,34 +910,22 @@
   layer->SetShowPrimarySurface(surface_id_one, gfx::Size(10, 10), SK_ColorWHITE,
                                cc::DeadlinePolicy::UseDefaultDeadline(), false);
   EXPECT_FALSE(layer->StretchContentToFillBounds());
-  EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(layer->cc_layer_for_testing())
-                  ->surface_hit_testable());
 
   auto clone = layer->Clone();
   EXPECT_FALSE(clone->StretchContentToFillBounds());
-  EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(clone->cc_layer_for_testing())
-                  ->surface_hit_testable());
   auto mirror = layer->Mirror();
   EXPECT_FALSE(mirror->StretchContentToFillBounds());
-  EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(mirror->cc_layer_for_testing())
-                  ->surface_hit_testable());
 
   local_surface_id = allocator.GenerateId();
   viz::SurfaceId surface_id_two(arbitrary_frame_sink, local_surface_id);
   layer->SetShowPrimarySurface(surface_id_two, gfx::Size(10, 10), SK_ColorWHITE,
                                cc::DeadlinePolicy::UseDefaultDeadline(), true);
   EXPECT_TRUE(layer->StretchContentToFillBounds());
-  EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(layer->cc_layer_for_testing())
-                  ->surface_hit_testable());
 
   clone = layer->Clone();
   EXPECT_TRUE(clone->StretchContentToFillBounds());
-  EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(clone->cc_layer_for_testing())
-                  ->surface_hit_testable());
   mirror = layer->Mirror();
   EXPECT_TRUE(mirror->StretchContentToFillBounds());
-  EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(mirror->cc_layer_for_testing())
-                  ->surface_hit_testable());
 }
 
 class LayerWithNullDelegateTest : public LayerWithDelegateTest {
diff --git a/ui/file_manager/file_manager/common/images/icon128.png b/ui/file_manager/file_manager/common/images/icon128.png
index 9e1f9a35..a1f75ff1 100644
--- a/ui/file_manager/file_manager/common/images/icon128.png
+++ b/ui/file_manager/file_manager/common/images/icon128.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon16.png b/ui/file_manager/file_manager/common/images/icon16.png
index 58d18283..c71b1c5 100644
--- a/ui/file_manager/file_manager/common/images/icon16.png
+++ b/ui/file_manager/file_manager/common/images/icon16.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon192.png b/ui/file_manager/file_manager/common/images/icon192.png
index 111ec9f..a91ea7d7 100644
--- a/ui/file_manager/file_manager/common/images/icon192.png
+++ b/ui/file_manager/file_manager/common/images/icon192.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon48.png b/ui/file_manager/file_manager/common/images/icon48.png
index 2bb8555..12ecaf85 100644
--- a/ui/file_manager/file_manager/common/images/icon48.png
+++ b/ui/file_manager/file_manager/common/images/icon48.png
Binary files differ
diff --git a/ui/ozone/demo/BUILD.gn b/ui/ozone/demo/BUILD.gn
index e76631b0..683e964 100644
--- a/ui/ozone/demo/BUILD.gn
+++ b/ui/ozone/demo/BUILD.gn
@@ -101,11 +101,13 @@
 
 if (is_fuchsia) {
   fuchsia_package("ozone_demo_pkg") {
+    testonly = true
     binary = ":ozone_demo"
     package_name_override = "ozone_demo"
   }
 
   fuchsia_package_runner("ozone_demo_fuchsia") {
+    testonly = true
     package = ":ozone_demo_pkg"
     package_name_override = "ozone_demo"
   }
diff --git a/ui/views/controls/menu/menu_config.cc b/ui/views/controls/menu/menu_config.cc
index 7ea5c01..d8115e9 100644
--- a/ui/views/controls/menu/menu_config.cc
+++ b/ui/views/controls/menu/menu_config.cc
@@ -5,9 +5,11 @@
 #include "ui/views/controls/menu/menu_config.h"
 
 #include "base/macros.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/views/controls/menu/menu_controller.h"
 #include "ui/views/controls/menu/menu_image_util.h"
 #include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/layout/layout_provider.h"
 #include "ui/views/round_rect_painter.h"
 
 namespace views {
@@ -83,6 +85,13 @@
   return corner_radius;
 }
 
+int MenuConfig::ShadowElevationForMenu(const MenuController* controller) const {
+  if ((controller && controller->use_touchable_layout()) ||
+      ui::MaterialDesignController::IsRefreshUi())
+    return touchable_menu_shadow_elevation;
+  return 0;
+}
+
 bool MenuConfig::ShouldShowAcceleratorText(const MenuItemView* item,
                                            base::string16* text) const {
   if (!show_accelerators || !item->GetDelegate() || !item->GetCommand())
@@ -104,4 +113,37 @@
   return instance;
 }
 
+void MenuConfig::InitMaterialMenuConfig() {
+  // These config parameters are from https://crbug.com/829347 and the spec
+  // images linked from that bug.
+  menu_horizontal_border_size = 0;
+  submenu_horizontal_inset = 0;
+  minimum_text_item_height = 28;
+  minimum_container_item_height = 40;
+  minimum_menu_width = 320;
+  label_to_arrow_padding = 0;
+  arrow_to_edge_padding = 16;
+  check_width = 16;
+  check_height = 16;
+  separator_height = 9;
+  separator_lower_height = 4;
+  separator_upper_height = 4;
+  separator_spacing_height = 5;
+  separator_thickness = 1;
+  align_arrow_and_shortcut = true;
+  use_outer_border = false;
+  icons_in_label = true;
+  corner_radius = 8;
+  auxiliary_corner_radius = 4;
+  if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled()) {
+    touchable_menu_height = minimum_text_item_height;
+    touchable_menu_width = minimum_menu_width;
+    if (LayoutProvider::Get()) {
+      touchable_menu_shadow_elevation =
+          LayoutProvider::Get()->GetShadowElevationMetric(EMPHASIS_MEDIUM);
+    }
+    touchable_anchor_offset = 0;
+  }
+}
+
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config.h b/ui/views/controls/menu/menu_config.h
index 885aa4c..fc629ac 100644
--- a/ui/views/controls/menu/menu_config.h
+++ b/ui/views/controls/menu/menu_config.h
@@ -22,11 +22,18 @@
 
   static const MenuConfig& instance();
 
+  // Initialize to the specs presented in https://crbug.com/829347
+  void InitMaterialMenuConfig();
+
   // Helper methods to simplify access to MenuConfig:
   // Returns the appropriate corner radius for the menu controlled by
   // |controller|, or the default corner radius if |controller| is nullptr.
   int CornerRadiusForMenu(const MenuController* controller) const;
 
+  // Returns the appropriate shadow elevation for the menu controlled by
+  // |controller|, or the default shadow elevation if |controller| is nullptr.
+  int ShadowElevationForMenu(const MenuController* controller) const;
+
   // Returns whether |item_view| should show accelerator text. If so, returns
   // the text to show.
   bool ShouldShowAcceleratorText(const MenuItemView* item_view,
diff --git a/ui/views/controls/menu/menu_config_chromeos.cc b/ui/views/controls/menu/menu_config_chromeos.cc
index 085c1adb..41b3911 100644
--- a/ui/views/controls/menu/menu_config_chromeos.cc
+++ b/ui/views/controls/menu/menu_config_chromeos.cc
@@ -4,26 +4,30 @@
 
 #include "ui/views/controls/menu/menu_config.h"
 
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/views/controls/menu/menu_image_util.h"
 
 namespace views {
 
 void MenuConfig::Init() {
-  submenu_horizontal_inset = 1;
-  arrow_to_edge_padding = 21;
-  gfx::ImageSkia check = GetMenuCheckImage(false);
-  check_height = check.height();
-  item_min_height = 29;
-  separator_spacing_height = 7;
-  separator_lower_height = 8;
-  separator_upper_height = 8;
+  if (ui::MaterialDesignController::IsRefreshUi()) {
+    InitMaterialMenuConfig();
+  } else {
+    align_arrow_and_shortcut = true;
+    gfx::ImageSkia check = GetMenuCheckImage(false);
+    check_height = check.height();
+    corner_radius = 2;
+    separator_spacing_height = 7;
+    separator_lower_height = 8;
+    separator_upper_height = 8;
+    submenu_horizontal_inset = 1;
+    // In Ash, the border is provided by the shadow.
+    use_outer_border = false;
+  }
   always_use_icon_to_label_padding = true;
-  align_arrow_and_shortcut = true;
+  arrow_to_edge_padding = 21;
+  item_min_height = 29;
   offset_context_menus = true;
-  corner_radius = 2;
-
-  // In Ash, the border is provided by the shadow.
-  use_outer_border = false;
 }
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config_linux.cc b/ui/views/controls/menu/menu_config_linux.cc
index ded2045..05af6d80 100644
--- a/ui/views/controls/menu/menu_config_linux.cc
+++ b/ui/views/controls/menu/menu_config_linux.cc
@@ -4,10 +4,15 @@
 
 #include "ui/views/controls/menu/menu_config.h"
 
+#include "ui/base/material_design/material_design_controller.h"
+
 namespace views {
 
 void MenuConfig::Init() {
-  arrow_to_edge_padding = 6;
+  if (ui::MaterialDesignController::IsRefreshUi())
+    InitMaterialMenuConfig();
+  else
+    arrow_to_edge_padding = 6;
 }
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config_mac.mm b/ui/views/controls/menu/menu_config_mac.mm
index 607ed754..ea9c2ab 100644
--- a/ui/views/controls/menu/menu_config_mac.mm
+++ b/ui/views/controls/menu/menu_config_mac.mm
@@ -8,45 +8,16 @@
 
 #include "base/mac/mac_util.h"
 
-namespace {
-
-void InitMaterialMenuConfig(views::MenuConfig* config) {
-  // These config parameters are from https://crbug.com/829347 and the spec
-  // images linked from that bug.
-  config->menu_horizontal_border_size = 0;
-  config->submenu_horizontal_inset = 0;
-  config->minimum_text_item_height = 28;
-  config->minimum_container_item_height = 40;
-  config->minimum_menu_width = 320;
-  config->label_to_arrow_padding = 0;
-  config->arrow_to_edge_padding = 16;
-  config->check_width = 16;
-  config->check_height = 16;
-  config->arrow_width = 8;
-  config->separator_height = 9;
-  config->separator_lower_height = 4;
-  config->separator_upper_height = 4;
-  config->separator_spacing_height = 5;
-  config->separator_thickness = 1;
-  config->align_arrow_and_shortcut = true;
-  config->use_outer_border = false;
-  config->icons_in_label = true;
-  config->corner_radius = 8;
-  config->auxiliary_corner_radius = 4;
-}
-
-}  // namespace
-
 namespace views {
 
 void MenuConfig::Init() {
+  InitMaterialMenuConfig();
   font_list = gfx::FontList(gfx::Font([NSFont menuFontOfSize:0.0]));
   check_selected_combobox_item = true;
   arrow_key_selection_wraps = false;
   use_mnemonics = false;
   show_context_menu_accelerators = false;
   all_menus_use_prefix_selection = true;
-  InitMaterialMenuConfig(this);
 }
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config_win.cc b/ui/views/controls/menu/menu_config_win.cc
index 6048ee0..cfda853 100644
--- a/ui/views/controls/menu/menu_config_win.cc
+++ b/ui/views/controls/menu/menu_config_win.cc
@@ -12,6 +12,7 @@
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/win_client_metrics.h"
 #include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/native_theme/native_theme_win.h"
 
@@ -20,6 +21,13 @@
 namespace views {
 
 void MenuConfig::Init() {
+  if (ui::MaterialDesignController::IsRefreshUi()) {
+    InitMaterialMenuConfig();
+  } else {
+    separator_upper_height = 5;
+    separator_lower_height = 7;
+  }
+
   arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
 
   NONCLIENTMETRICS_XP metrics;
@@ -36,7 +44,7 @@
   if (!arrow_size.IsEmpty()) {
     arrow_width = arrow_size.width();
   } else {
-    // Sadly I didn't see a specify metrics for this.
+    // Sadly I didn't see a specific metric for this.
     arrow_width = GetSystemMetrics(SM_CXMENUCHECK);
   }
 
@@ -46,9 +54,6 @@
        show_cues == TRUE);
 
   SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &show_delay, 0);
-
-  separator_upper_height = 5;
-  separator_lower_height = 7;
 }
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index b4da2b5..81a325fd 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -15,6 +15,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
@@ -60,6 +61,7 @@
 
 using base::TimeDelta;
 using ui::OSExchangeData;
+using MD = ui::MaterialDesignController;
 
 namespace views {
 
@@ -1786,7 +1788,15 @@
                                                 const gfx::Point& screen_loc) {
   gfx::Point view_loc = screen_loc;
   View::ConvertPointFromScreen(submenu, &view_loc);
+  MenuScrollViewContainer* container = submenu->GetScrollViewContainer();
+  // When the menu has a Bubble border, that area is largely transparent. This
+  // will exclude that region from hit-testing.
+  gfx::Rect content_rect =
+      container->HasBubbleBorder()
+          ? container->ConvertRectToParent(container->GetContentsBounds())
+          : container->bounds();
   gfx::Rect vis_rect = submenu->GetVisibleBounds();
+  vis_rect.Intersect(content_rect);
   return vis_rect.Contains(view_loc);
 }
 
@@ -2033,6 +2043,17 @@
   const gfx::Rect& monitor_bounds = state_.monitor_bounds;
   const gfx::Rect& anchor_bounds = state_.initial_bounds;
 
+  const MenuConfig& menu_config = MenuConfig::instance();
+  // Shadow insets are built into MenuScrollView's preferred size so it must be
+  // compensated for when determining the bounds of menus with a bubble border.
+  const gfx::Insets border_and_shadow_insets =
+      (MD::IsRefreshUi() && !menu_config.use_outer_border)
+          ? BubbleBorder::GetBorderAndShadowInsets(
+                menu_config.ShadowElevationForMenu(this))
+          : gfx::Insets();
+
+  menu_bounds.Inset(border_and_shadow_insets);
+
   // For comboboxes, ensure the menu is at least as wide as the anchor.
   if (is_combobox_)
     menu_bounds.set_width(std::max(menu_bounds.width(), anchor_bounds.width()));
@@ -2050,8 +2071,6 @@
   // Assume we can honor prefer_leading.
   *is_leading = prefer_leading;
 
-  const MenuConfig& menu_config = MenuConfig::instance();
-
   if (item->GetParentMenuItem()) {
     // Not the first menu; position it relative to the bounds of its parent menu
     // item.
@@ -2126,8 +2145,10 @@
     }
 
     // Everything beyond this point requires monitor bounds to be non-empty.
-    if (monitor_bounds.IsEmpty())
+    if (monitor_bounds.IsEmpty()) {
+      menu_bounds.Inset(-border_and_shadow_insets);
       return menu_bounds;
+    }
 
     // If the menu position is below or above the anchor bounds, force it to fit
     // on the screen. Otherwise, try to fit the menu in the following locations:
@@ -2174,6 +2195,7 @@
       base::ClampToRange(menu_bounds.y(), monitor_bounds.y(),
                          monitor_bounds.bottom() - menu_bounds.height()));
 
+  menu_bounds.Inset(-border_and_shadow_insets);
   return menu_bounds;
 }
 
@@ -2196,7 +2218,7 @@
   // compensated for when determining the bounds of touchable menus.
   const gfx::Insets border_and_shadow_insets =
       BubbleBorder::GetBorderAndShadowInsets(
-          menu_config.touchable_menu_shadow_elevation);
+          menu_config.ShadowElevationForMenu(this));
 
   const gfx::Rect& monitor_bounds = state_.monitor_bounds;
 
@@ -2266,7 +2288,7 @@
           border_and_shadow_insets.bottom() -
           menu_config.touchable_anchor_offset;
       // Align the right of the container with the right of the anchor.
-      if (x + menu_size.width() > monitor_bounds.width()) {
+      if (x + menu_size.width() > monitor_bounds.right()) {
         x = anchor_bounds.right() - menu_size.width() +
             border_and_shadow_insets.right();
       }
@@ -2288,7 +2310,7 @@
             menu_config.touchable_anchor_offset;
       }
       // Align the bottom of the menu to the bottom of the anchor.
-      if (y + menu_size.height() > monitor_bounds.height()) {
+      if (y + menu_size.height() > monitor_bounds.bottom()) {
         y = anchor_bounds.bottom() - menu_size.height() +
             border_and_shadow_insets.bottom();
       }
@@ -2298,13 +2320,13 @@
       x = anchor_bounds.right() - border_and_shadow_insets.left() +
           menu_config.touchable_anchor_offset;
       y = anchor_bounds.y() - border_and_shadow_insets.top();
-      if (x + menu_size.width() > monitor_bounds.width()) {
+      if (x + menu_size.width() > monitor_bounds.right()) {
         // Align the right of the menu with the left of the anchor.
         x = anchor_bounds.x() - menu_size.width() +
             border_and_shadow_insets.right() -
             menu_config.touchable_anchor_offset;
       }
-      if (y + menu_size.height() > monitor_bounds.height()) {
+      if (y + menu_size.height() > monitor_bounds.bottom()) {
         // Align the bottom of the menu with the bottom of the anchor.
         y = anchor_bounds.bottom() - menu_size.height() +
             border_and_shadow_insets.bottom();
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index e338a213..b5a51ed1 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -1429,6 +1429,10 @@
 TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
   MenuBoundsOptions options;
   gfx::Rect expected;
+  MenuScrollViewContainer* container =
+      menu_item()->GetSubmenu()->GetScrollViewContainer();
+  gfx::Insets menu_insets =
+      container->HasBubbleBorder() ? container->GetInsets() : gfx::Insets();
 
   // Fits in all locations -> placed below.
   options.anchor_bounds =
@@ -1436,9 +1440,9 @@
   options.monitor_bounds =
       gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
                 options.anchor_bounds.bottom() + options.menu_size.height());
-  expected =
-      gfx::Rect(options.anchor_bounds.x(), options.anchor_bounds.bottom(),
-                options.menu_size.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - menu_insets.left(),
+                       options.anchor_bounds.bottom() - menu_insets.top(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Fits above and to both sides -> placed above.
@@ -1447,8 +1451,9 @@
   options.monitor_bounds =
       gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
                 options.anchor_bounds.bottom());
-  expected = gfx::Rect(options.anchor_bounds.x(),
-                       options.anchor_bounds.y() - options.menu_size.height(),
+  expected = gfx::Rect(options.anchor_bounds.x() - menu_insets.left(),
+                       options.anchor_bounds.y() - options.menu_size.height() +
+                           menu_insets.bottom(),
                        options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
@@ -1458,10 +1463,10 @@
   options.monitor_bounds =
       gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
                 options.menu_size.height());
-  expected =
-      gfx::Rect(options.anchor_bounds.right(),
-                options.monitor_bounds.bottom() - options.menu_size.height(),
-                options.menu_size.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.right() - menu_insets.left(),
+                       options.monitor_bounds.bottom() -
+                           options.menu_size.height() + menu_insets.bottom(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Fits only on left -> placed left.
@@ -1469,10 +1474,11 @@
                                     options.menu_size.height() / 2, 0, 0);
   options.monitor_bounds = gfx::Rect(0, 0, options.anchor_bounds.right(),
                                      options.menu_size.height());
-  expected =
-      gfx::Rect(options.anchor_bounds.x() - options.menu_size.width(),
-                options.monitor_bounds.bottom() - options.menu_size.height(),
-                options.menu_size.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - options.menu_size.width() +
+                           menu_insets.right(),
+                       options.monitor_bounds.bottom() -
+                           options.menu_size.height() + menu_insets.bottom(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Fits on both sides, prefer left -> placed left.
@@ -1482,10 +1488,11 @@
   options.monitor_bounds =
       gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
                 options.menu_size.height());
-  expected =
-      gfx::Rect(options.anchor_bounds.x() - options.menu_size.width(),
-                options.monitor_bounds.bottom() - options.menu_size.height(),
-                options.menu_size.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - options.menu_size.width() +
+                           menu_insets.right(),
+                       options.monitor_bounds.bottom() -
+                           options.menu_size.height() + menu_insets.bottom(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Fits only on right -> placed right.
@@ -1493,10 +1500,10 @@
   options.monitor_bounds =
       gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
                 options.menu_size.height());
-  expected =
-      gfx::Rect(options.anchor_bounds.right(),
-                options.monitor_bounds.bottom() - options.menu_size.height(),
-                options.menu_size.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.right() - menu_insets.left(),
+                       options.monitor_bounds.bottom() -
+                           options.menu_size.height() + menu_insets.bottom(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 }
 
@@ -1504,18 +1511,22 @@
 TEST_F(MenuControllerTest, CalculateMenuBoundsAnchorTest) {
   MenuBoundsOptions options;
   gfx::Rect expected;
+  MenuScrollViewContainer* container =
+      menu_item()->GetSubmenu()->GetScrollViewContainer();
+  gfx::Insets menu_insets =
+      container->HasBubbleBorder() ? container->GetInsets() : gfx::Insets();
 
   options.menu_anchor = MENU_ANCHOR_TOPLEFT;
-  expected =
-      gfx::Rect(options.anchor_bounds.x(), options.anchor_bounds.bottom(),
-                options.menu_size.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - menu_insets.left(),
+                       options.anchor_bounds.bottom() - menu_insets.top(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   options.menu_anchor = MENU_ANCHOR_TOPRIGHT;
-  expected =
-      gfx::Rect(options.anchor_bounds.right() - options.menu_size.width(),
-                options.anchor_bounds.bottom(), options.menu_size.width(),
-                options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.right() -
+                           options.menu_size.width() + menu_insets.left(),
+                       options.anchor_bounds.bottom() - menu_insets.top(),
+                       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Menu will be placed above or below with an offset.
@@ -1526,7 +1537,8 @@
   expected = gfx::Rect(
       options.anchor_bounds.x() +
           (options.anchor_bounds.width() - options.menu_size.width()) / 2,
-      options.anchor_bounds.y() - options.menu_size.height() - kTouchYPadding,
+      options.anchor_bounds.y() - options.menu_size.height() +
+          menu_insets.bottom() - kTouchYPadding,
       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
@@ -1536,8 +1548,8 @@
   expected = gfx::Rect(
       options.anchor_bounds.x() +
           (options.anchor_bounds.width() - options.menu_size.width()) / 2,
-      options.anchor_bounds.y() + kTouchYPadding, options.menu_size.width(),
-      options.menu_size.height());
+      options.anchor_bounds.y() - menu_insets.top() + kTouchYPadding,
+      options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Assumes anchor bounds is at the bottom of screen.
@@ -1549,7 +1561,8 @@
   expected = gfx::Rect(
       options.anchor_bounds.x() +
           (options.anchor_bounds.width() - options.menu_size.width()) / 2,
-      options.anchor_bounds.y() - options.menu_size.height(),
+      options.anchor_bounds.y() - options.menu_size.height() +
+          menu_insets.bottom(),
       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
@@ -1560,8 +1573,8 @@
   options.anchor_bounds =
       gfx::Rect(options.monitor_bounds.x(), options.menu_size.height(), 0, 0);
   expected = gfx::Rect(
-      options.anchor_bounds.x(),
-      options.anchor_bounds.y() +
+      options.anchor_bounds.x() - menu_insets.left(),
+      options.anchor_bounds.y() + menu_insets.top() +
           (options.anchor_bounds.height() - options.menu_size.height()) / 2,
       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
@@ -1569,8 +1582,9 @@
   options.anchor_bounds = gfx::Rect(options.monitor_bounds.right(),
                                     options.menu_size.height(), 0, 0);
   expected = gfx::Rect(
-      options.anchor_bounds.right() - options.menu_size.width(),
-      options.anchor_bounds.y() +
+      options.anchor_bounds.right() - options.menu_size.width() +
+          menu_insets.right(),
+      options.anchor_bounds.y() + menu_insets.top() +
           (options.anchor_bounds.height() - options.menu_size.height()) / 2,
       options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
@@ -1578,29 +1592,38 @@
 
 TEST_F(MenuControllerTest, CalculateMenuBoundsMonitorFitTest) {
   MenuBoundsOptions options;
+  MenuScrollViewContainer* scroll_view_container =
+      menu_item()->GetSubmenu()->GetScrollViewContainer();
+  gfx::Insets menu_insets = scroll_view_container->HasBubbleBorder()
+                                ? scroll_view_container->GetInsets()
+                                : gfx::Insets();
+
   gfx::Rect expected;
   options.monitor_bounds = gfx::Rect(0, 0, 100, 100);
   options.anchor_bounds = gfx::Rect();
 
   options.menu_size = gfx::Size(options.monitor_bounds.width() / 2,
                                 options.monitor_bounds.height() * 2);
-  expected =
-      gfx::Rect(options.anchor_bounds.x(), options.anchor_bounds.bottom(),
-                options.menu_size.width(), options.monitor_bounds.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - menu_insets.left(),
+                       options.anchor_bounds.bottom() - menu_insets.top(),
+                       options.menu_size.width(),
+                       options.monitor_bounds.height() + menu_insets.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   options.menu_size = gfx::Size(options.monitor_bounds.width() * 2,
                                 options.monitor_bounds.height() / 2);
-  expected =
-      gfx::Rect(options.anchor_bounds.x(), options.anchor_bounds.bottom(),
-                options.monitor_bounds.width(), options.menu_size.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - menu_insets.left(),
+                       options.anchor_bounds.bottom() - menu_insets.top(),
+                       options.monitor_bounds.width() + menu_insets.width(),
+                       options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   options.menu_size = gfx::Size(options.monitor_bounds.width() * 2,
                                 options.monitor_bounds.height() * 2);
-  expected = gfx::Rect(
-      options.anchor_bounds.x(), options.anchor_bounds.bottom(),
-      options.monitor_bounds.width(), options.monitor_bounds.height());
+  expected = gfx::Rect(options.anchor_bounds.x() - menu_insets.left(),
+                       options.anchor_bounds.bottom() - menu_insets.top(),
+                       options.monitor_bounds.width() + menu_insets.width(),
+                       options.monitor_bounds.height() + menu_insets.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 }
 
@@ -1743,11 +1766,18 @@
       std::make_unique<TestMenuItemViewShown>(sub_menu_item_delegate.get());
   sub_menu_item->AddEmptyMenusForTest();
   sub_menu_item->SetController(controller);
-  sub_menu_item->SetBounds(0, 50, 50, 50);
+  gfx::Rect sub_menu_bounds(0, 50, 50, 50);
+  sub_menu_item->SetBoundsRect(sub_menu_bounds);
   base_submenu->AddChildView(sub_menu_item.get());
   SubmenuView* sub_menu_view = sub_menu_item->GetSubmenu();
-  sub_menu_view->SetBounds(0, 50, 50, 50);
-  sub_menu_view->ShowAt(owner(), gfx::Rect(0, 50, 50, 50), false);
+  MenuScrollViewContainer* sub_menu_view_container =
+      sub_menu_view->GetScrollViewContainer();
+  gfx::Insets menu_insets = sub_menu_view_container->HasBubbleBorder()
+                                ? sub_menu_view_container->GetInsets()
+                                : gfx::Insets();
+  sub_menu_bounds.Inset(-menu_insets);
+  sub_menu_view->SetBoundsRect(sub_menu_bounds);
+  sub_menu_view->ShowAt(owner(), sub_menu_bounds, false);
   GetMenuHost(sub_menu_view)
       ->SetContentsView(sub_menu_view->GetScrollViewContainer());
 
diff --git a/ui/views/controls/menu/menu_item_view_unittest.cc b/ui/views/controls/menu/menu_item_view_unittest.cc
index 07273f5d..550dbffd 100644
--- a/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -47,7 +47,9 @@
   DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
 };
 
-TEST(MenuItemViewUnitTest, TestMenuItemViewWithFlexibleWidthChild) {
+using MenuItemViewUnitTest = views::ViewsTestBase;
+
+TEST_F(MenuItemViewUnitTest, TestMenuItemViewWithFlexibleWidthChild) {
   TestMenuItemView root_menu;
   root_menu.set_owned_by_client();
 
@@ -86,7 +88,7 @@
 
 // Tests that the top-level menu item with hidden children should contain the
 // "(empty)" menu item to display.
-TEST(MenuItemViewUnitTest, TestEmptyTopLevelWhenAllItemsAreHidden) {
+TEST_F(MenuItemViewUnitTest, TestEmptyTopLevelWhenAllItemsAreHidden) {
   TestMenuItemView root_menu;
   views::MenuItemView* item1 =
       root_menu.AppendMenuItemWithLabel(1, base::ASCIIToUTF16("item 1"));
@@ -117,7 +119,7 @@
 
 // Tests that submenu with hidden children should contain the "(empty)" menu
 // item to display.
-TEST(MenuItemViewUnitTest, TestEmptySubmenuWhenAllChildItemsAreHidden) {
+TEST_F(MenuItemViewUnitTest, TestEmptySubmenuWhenAllChildItemsAreHidden) {
   TestMenuItemView root_menu;
   MenuItemView* submenu_item =
       root_menu.AppendSubMenu(1, base::ASCIIToUTF16("My Submenu"));
@@ -148,7 +150,7 @@
             empty_item->title());
 }
 
-TEST(MenuItemViewUnitTest, UseMnemonicOnPlatform) {
+TEST_F(MenuItemViewUnitTest, UseMnemonicOnPlatform) {
   TestMenuItemView root_menu;
   views::MenuItemView* item1 =
       root_menu.AppendMenuItemWithLabel(1, base::ASCIIToUTF16("&Item 1"));
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index ecbd5d7..aa8ad37 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -8,6 +8,7 @@
 #include "cc/paint/paint_flags.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/views/border.h"
@@ -19,6 +20,7 @@
 #include "ui/views/round_rect_painter.h"
 
 using ui::NativeTheme;
+using MD = ui::MaterialDesignController;
 
 namespace views {
 
@@ -186,14 +188,14 @@
   arrow_ = BubbleBorderTypeFromAnchor(
       content_view_->GetMenuItem()->GetMenuController()->GetAnchorPosition());
 
-  if (arrow_ != BubbleBorder::NONE)
+  if (HasBubbleBorder())
     CreateBubbleBorder();
   else
     CreateDefaultBorder();
 }
 
 bool MenuScrollViewContainer::HasBubbleBorder() {
-  return arrow_ != BubbleBorder::NONE;
+  return (arrow_ != BubbleBorder::NONE) || MD::IsRefreshUi();
 }
 
 void MenuScrollViewContainer::SetBubbleArrowOffset(int offset) {
@@ -237,7 +239,7 @@
 
 void MenuScrollViewContainer::OnNativeThemeChanged(
     const ui::NativeTheme* theme) {
-  if (arrow_ == BubbleBorder::NONE)
+  if (!HasBubbleBorder())
     CreateDefaultBorder();
 }
 
@@ -309,13 +311,14 @@
 void MenuScrollViewContainer::CreateBubbleBorder() {
   bubble_border_ =
       new BubbleBorder(arrow_, BubbleBorder::SMALL_SHADOW, SK_ColorWHITE);
-  if (content_view_->GetMenuItem()
-          ->GetMenuController()
-          ->use_touchable_layout()) {
+  MenuController* controller =
+      content_view_->GetMenuItem()->GetMenuController();
+  if (MD::IsRefreshUi() || controller->use_touchable_layout()) {
     const MenuConfig& menu_config = MenuConfig::instance();
-    bubble_border_->SetCornerRadius(menu_config.touchable_corner_radius);
+    bubble_border_->SetCornerRadius(
+        menu_config.CornerRadiusForMenu(controller));
     bubble_border_->set_md_shadow_elevation(
-        menu_config.touchable_menu_shadow_elevation);
+        menu_config.ShadowElevationForMenu(controller));
     scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(
         gfx::Insets(menu_config.vertical_touchable_menu_item_padding, 0)));
   }
diff --git a/ui/views/controls/menu/menu_scroll_view_container.h b/ui/views/controls/menu/menu_scroll_view_container.h
index f083419..6d3caf7 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/ui/views/controls/menu/menu_scroll_view_container.h
@@ -9,6 +9,7 @@
 #include "ui/views/bubble/bubble_border.h"
 #include "ui/views/controls/menu/menu_types.h"
 #include "ui/views/view.h"
+#include "ui/views/views_export.h"
 
 namespace views {
 
@@ -17,7 +18,7 @@
 // MenuScrollViewContainer contains the SubmenuView (through a MenuScrollView)
 // and two scroll buttons. The scroll buttons are only visible and enabled if
 // the preferred height of the SubmenuView is bigger than our bounds.
-class MenuScrollViewContainer : public View {
+class VIEWS_EXPORT MenuScrollViewContainer : public View {
  public:
   explicit MenuScrollViewContainer(SubmenuView* content_view);
 
@@ -25,7 +26,7 @@
   View* scroll_down_button() const { return scroll_down_button_; }
   View* scroll_up_button() const { return scroll_up_button_; }
 
-  // External function to check if the bubble border is usd.
+  // External function to check if the bubble border is used.
   bool HasBubbleBorder();
 
   // Offsets the Arrow from the default location.
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 590de78..f09d2151 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -1523,7 +1523,7 @@
                   reinterpret_cast<unsigned char*>(&window_type), 1);
 
   // List of window state properties (_NET_WM_STATE) to set, if any.
-  std::vector< ::Atom> state_atom_list;
+  std::vector<XAtom> state_atom_list;
 
   // Remove popup windows from taskbar unless overridden.
   if ((params.type == Widget::InitParams::TYPE_POPUP ||
@@ -1553,7 +1553,9 @@
   // mapped. So we manually change the state.
   if (!state_atom_list.empty()) {
     DCHECK(window_properties_in_client_.empty());
-    window_properties_in_client_ = state_atom_list;
+    window_properties_in_client_.clear();
+    for (XAtom atom : state_atom_list)
+      window_properties_in_client_.insert(std::make_pair(atom, x11::None));
     ui::SetAtomArrayProperty(xwindow_,
                              "_NET_WM_STATE",
                              "ATOM",
@@ -1656,14 +1658,11 @@
                                               XAtom state2) {
   if (IsVisible())
     ui::SetWMSpecState(xwindow_, enabled, state1, state2);
-  for (XAtom atom : {state1, state2}) {
-    if (atom != x11::None) {
-      if (enabled)
-        window_properties_in_client_.insert(atom);
-      else
-        window_properties_in_client_.erase(atom);
-    }
-  }
+  auto atoms = std::make_pair(state1, state2);
+  if (enabled)
+    window_properties_in_client_.insert(atoms);
+  else
+    window_properties_in_client_.erase(atoms);
 }
 
 void DesktopWindowTreeHostX11::OnWMStateUpdated() {
@@ -1988,8 +1987,8 @@
   XMapWindow(xdisplay_, xwindow_);
   window_mapped_in_client_ = true;
 
-  for (XAtom atom : window_properties_in_client_)
-    ui::SetWMSpecState(xwindow_, true, atom, x11::None);
+  for (const auto& atoms : window_properties_in_client_)
+    ui::SetWMSpecState(xwindow_, true, atoms.first, atoms.second);
 }
 
 void DesktopWindowTreeHostX11::SetWindowTransparency() {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index 5a0a308..9d66f94f 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -208,7 +208,12 @@
 
   // If mapped, sends a message to the window manager to enable or disable the
   // states |state1| and |state2|.  Otherwise, the states will be enabled or
-  // disabled on the next map.
+  // disabled on the next map.  It's the caller's responsibility to make sure
+  // atoms are set and unset in the appropriate pairs.  For example, if a caller
+  // sets (_NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ), it would
+  // be invalid to unset the maximized state by making two calls like
+  // (_NET_WM_STATE_MAXIMIZED_VERT, x11::None), (_NET_WM_STATE_MAXIMIZED_HORZ,
+  // x11::None).
   void SetWMSpecState(bool enabled, XAtom state1, XAtom state2);
 
   // Called when |xwindow_|'s _NET_WM_STATE property is updated.
@@ -345,10 +350,10 @@
 
   // The window manager state bits as indicated by the server.  May be
   // out-of-sync.  May include bits set by non-Chrome apps.
-  base::flat_set<::Atom> window_properties_in_server_;
+  base::flat_set<XAtom> window_properties_in_server_;
 
   // The window manager state bits that Chrome has set.
-  base::flat_set<::Atom> window_properties_in_client_;
+  base::flat_set<std::pair<XAtom, XAtom>> window_properties_in_client_;
 
   // Whether |xwindow_| was requested to be fullscreen via SetFullscreen().
   bool is_fullscreen_;
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index 445d569..46df343 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -1024,6 +1024,12 @@
   updateSelectedCerts_: function() {
     if (!this.findCert_(this.serverCaCerts_, this.selectedServerCaHash_))
       this.selectedServerCaHash_ = undefined;
+    if (!this.selectedServerCaHash_ ||
+        this.selectedServerCaHash_ == DEFAULT_HASH) {
+      var eap = this.eapProperties_;
+      if (eap && eap.UseSystemCAs === false)
+        this.selectedServerCaHash_ = DO_NOT_CHECK_HASH;
+    }
     if (!this.selectedServerCaHash_ && this.serverCaCerts_[0])
       this.selectedServerCaHash_ = this.serverCaCerts_[0].hash;
 
diff --git a/webrunner/BUILD.gn b/webrunner/BUILD.gn
index 7570f00..c3f7842 100644
--- a/webrunner/BUILD.gn
+++ b/webrunner/BUILD.gn
@@ -17,11 +17,13 @@
 fuchsia_package("webrunner_pkg") {
   binary = ":webrunner_exe"
   package_name_override = "web_runner"
+  sandbox_policy = "app/sandbox_policy"
 }
 
 fuchsia_package_runner("webrunner") {
   package = ":webrunner_pkg"
   package_name_override = "web_runner"
+  install_only = true
   package_deps = [ [
         ":service_pkg",
         "chromium",
@@ -46,6 +48,7 @@
 fuchsia_package("service_pkg") {
   binary = ":service_exe"
   package_name_override = "chromium"
+  sandbox_policy = "service/sandbox_policy"
 }
 
 executable("service_exe") {
@@ -64,6 +67,7 @@
 fuchsia_package_runner("service_runner") {
   package = ":service_pkg"
   package_name_override = "chromium"
+  install_only = true
 }
 
 component("service_lib") {
diff --git a/webrunner/app/sandbox_policy b/webrunner/app/sandbox_policy
new file mode 100644
index 0000000..cb3a3c7
--- /dev/null
+++ b/webrunner/app/sandbox_policy
@@ -0,0 +1,13 @@
+{
+  "features": [],
+  "services": [
+      "chromium.web.ContextProvider",
+      "fuchsia.fonts.FontProvider",
+      "fuchsia.media.Audio",
+      "fuchsia.net.LegacySocketProvider",
+      "fuchsia.netstack.Netstack",
+      "fuchsia.process.Launcher",
+      "fuchsia.ui.scenic.Scenic",
+      "fuchsia.ui.viewsv1.ViewManager"
+  ]
+}
diff --git a/webrunner/cipd/build_id.template b/webrunner/cipd/build_id.template
index 7bbd81cb..32a49a4 100644
--- a/webrunner/cipd/build_id.template
+++ b/webrunner/cipd/build_id.template
@@ -1 +1 @@
-@MAJOR@.@MINOR@.@BUILD@.@PATCH@
+@MAJOR@.@MINOR@.@BUILD@.@PATCH@
\ No newline at end of file
diff --git a/webrunner/net_http/BUILD.gn b/webrunner/net_http/BUILD.gn
index 493cf67..db0eeeb 100644
--- a/webrunner/net_http/BUILD.gn
+++ b/webrunner/net_http/BUILD.gn
@@ -29,6 +29,7 @@
 fuchsia_package("http_pkg") {
   binary = ":http_service"
   package_name_override = "http"
+  sandbox_policy = "sandbox_policy"
 }
 
 fuchsia_package_runner("http_pkg_runner") {
diff --git a/webrunner/net_http/sandbox_policy b/webrunner/net_http/sandbox_policy
new file mode 100644
index 0000000..15be6c0
--- /dev/null
+++ b/webrunner/net_http/sandbox_policy
@@ -0,0 +1,7 @@
+{
+  "features": [ "root-ssl-certificates" ],
+  "services": [
+      "fuchsia.net.LegacySocketProvider",
+      "fuchsia.netstack.Netstack"
+  ]
+}
diff --git a/webrunner/service/sandbox_policy b/webrunner/service/sandbox_policy
new file mode 100644
index 0000000..f6de1d1
--- /dev/null
+++ b/webrunner/service/sandbox_policy
@@ -0,0 +1,6 @@
+{
+  "features": [ "root-ssl-certificates", "vulkan" ],
+  "services": [
+    "fuchsia.process.Launcher"
+  ]
+}